Признаки обнаружения лица Viola-Jones 180k
Я реализую адаптацию алгоритм обнаружения лица Виолы-Джонса. Эта технология основана на размещении подкадра в 24х24 пикселя внутри изображения и последующем размещении в нем прямоугольных элементов в каждой позиции с любым размером.
Эти функции могут состоять из двух, трех или четырех прямоугольников. Представлен следующий пример.
![Rectangle features]()
Они утверждают, что исчерпывающий набор более 180k (раздел 2):
Учитывая, что базовое разрешение детектора равно 24x24, исчерпывающий набор элементов прямоугольника довольно большой, более 180 000. Обратите внимание, что в отличие от основания Хаара набор прямоугольников функции являются неполными.
Следующие утверждения явно не указаны в документе, поэтому они являются предположениями с моей стороны:
- Есть только 2 двух прямоугольника, 2 трех прямоугольника и 1 функция с четырьмя прямоугольниками. Логика этого заключается в том, что мы наблюдаем разницу между выделенными прямоугольниками, а не явно цвет или яркость или что-то в этом роде.
- Мы не можем определить тип функции A как 1x1 пиксельный блок; он должен иметь по крайней мере 1x2 пикселя. Кроме того, тип D должен быть не менее 2x2 пикселя, и это правило выполняется в соответствии с другими функциями.
- Мы не можем определить тип функции A как блок пикселя 1x3, поскольку средний пиксель не может быть разбит на разделы, а вычесть его из себя идентично блоку пикселов 1x2; этот тип функции определяется только для равномерной ширины. Кроме того, ширина типа функции C должна быть делимой на 3, и это правило выполняется в соответствии с другими функциями.
- Мы не можем определить функцию с шириной и/или высотой 0. Поэтому мы перебираем x и y на 24 минус размер функции.
Исходя из этих предположений, я подсчитал исчерпывающий набор:
const int frameSize = 24;
const int features = 5;
// All five feature types:
const int feature[features][2] = {{2,1}, {1,2}, {3,1}, {1,3}, {2,2}};
int count = 0;
// Each feature:
for (int i = 0; i < features; i++) {
int sizeX = feature[i][0];
int sizeY = feature[i][1];
// Each position:
for (int x = 0; x <= frameSize-sizeX; x++) {
for (int y = 0; y <= frameSize-sizeY; y++) {
// Each size fitting within the frameSize:
for (int width = sizeX; width <= frameSize-x; width+=sizeX) {
for (int height = sizeY; height <= frameSize-y; height+=sizeY) {
count++;
}
}
}
}
}
Результат 162,336.
Единственный способ, который я нашел, чтобы приблизиться к "более 180 000", о которых говорят Виола и Джонс, - это предположение № 4 и введение ошибок в код. Это включает в себя изменение четырех строк соответственно:
for (int width = 0; width < frameSize-x; width+=sizeX)
for (int height = 0; height < frameSize-y; height+=sizeY)
В результате получается 180,625. (Обратите внимание, что это эффективно предотвратит, когда функции будут касаться правой и/или нижней части подкадра.)
Теперь, конечно, вопрос: допустили ли они ошибку в их реализации? Имеет ли смысл рассматривать объекты с поверхностью нуля? Или я вижу это неправильно?
Ответы
Ответ 1
При ближайшем рассмотрении ваш код выглядит правильно для меня; что заставляет задуматься, были ли у исходных авторов ошибка "один за другим". Я думаю, кто-то должен посмотреть, как это реализует OpenCV!
Тем не менее, одно предложение облегчить понимание состоит в том, чтобы перевернуть порядок циклов for, перейдя по всем размерам сначала, а затем перейдя по возможным местоположениям с учетом размера:
#include <stdio.h>
int main()
{
int i, x, y, sizeX, sizeY, width, height, count, c;
/* All five shape types */
const int features = 5;
const int feature[][2] = {{2,1}, {1,2}, {3,1}, {1,3}, {2,2}};
const int frameSize = 24;
count = 0;
/* Each shape */
for (i = 0; i < features; i++) {
sizeX = feature[i][0];
sizeY = feature[i][1];
printf("%dx%d shapes:\n", sizeX, sizeY);
/* each size (multiples of basic shapes) */
for (width = sizeX; width <= frameSize; width+=sizeX) {
for (height = sizeY; height <= frameSize; height+=sizeY) {
printf("\tsize: %dx%d => ", width, height);
c=count;
/* each possible position given size */
for (x = 0; x <= frameSize-width; x++) {
for (y = 0; y <= frameSize-height; y++) {
count++;
}
}
printf("count: %d\n", count-c);
}
}
}
printf("%d\n", count);
return 0;
}
с теми же результатами, что и предыдущие 162336
Чтобы проверить это, я протестировал случай с окном 4x4 и вручную проверил все случаи (легко подсчитать, так как формы 1x2/2x1 и 1x3/3x1 совпадают только с поворотом на 90 градусов):
2x1 shapes:
size: 2x1 => count: 12
size: 2x2 => count: 9
size: 2x3 => count: 6
size: 2x4 => count: 3
size: 4x1 => count: 4
size: 4x2 => count: 3
size: 4x3 => count: 2
size: 4x4 => count: 1
1x2 shapes:
size: 1x2 => count: 12 +-----------------------+
size: 1x4 => count: 4 | | | | |
size: 2x2 => count: 9 | | | | |
size: 2x4 => count: 3 +-----+-----+-----+-----+
size: 3x2 => count: 6 | | | | |
size: 3x4 => count: 2 | | | | |
size: 4x2 => count: 3 +-----+-----+-----+-----+
size: 4x4 => count: 1 | | | | |
3x1 shapes: | | | | |
size: 3x1 => count: 8 +-----+-----+-----+-----+
size: 3x2 => count: 6 | | | | |
size: 3x3 => count: 4 | | | | |
size: 3x4 => count: 2 +-----------------------+
1x3 shapes:
size: 1x3 => count: 8 Total Count = 136
size: 2x3 => count: 6
size: 3x3 => count: 4
size: 4x3 => count: 2
2x2 shapes:
size: 2x2 => count: 9
size: 2x4 => count: 3
size: 4x2 => count: 3
size: 4x4 => count: 1
Ответ 2
все. Еще есть некоторая путаница в бумагах Виолы и Джонса.
В своей работе CVPR'01 ясно сказано, что
"Более конкретно, мы используем тривиды функций. Значение a функция с двумя прямоугольниками - это разница между суммой пикселей в двух прямоугольных областях. Области имеют одинаковый размер и формы и горизонтали или (см. рис. 1). Функция с тремя прямоугольниками вычисляет сумму в двух внешних прямоугольники вычитаются из суммы в центральный прямоугольник. Наконец a четырехугольная функция".
В работе IJCV'04 сказано точно то же самое. Таким образом, 4 функции. Но, как ни странно, на этот раз они заявили, что исчерпывающий набор функций - 45396! Это, похоже, не является окончательной версией. Я предполагаю, что там были введены некоторые дополнительные ограничения, такие как min_width, min_height, отношение ширины/высоты и четное положение.
Обратите внимание, что обе бумаги загружаются на его веб-страницу.
Ответ 3
Не прочитав всю бумагу, формулировка вашей цитаты торчит у меня
Учитывая, что базовое разрешение детектор 24x24, исчерпывающий набор элементов прямоугольника довольно велика, более 180 000. Обратите внимание, что в отличие от Основание Хаара, набор прямоугольников функции являются неполными.
"Набор элементов прямоугольника является неполным"
"Исчерпывающий набор"
это звучит для меня как настройка, где я ожидаю, что бумажный писатель продолжит объяснять, как они отбирают пространство поиска до более эффективного набора, например, избавляясь от тривиальных случаев, таких как прямоугольники с нулевой площадью поверхности.
изменить: или использовать какой-то алгоритм машинного обучения, как абстрактные намеки на. Исчерпывающий набор подразумевает все возможности, а не только "разумные".
Ответ 4
Нет никакой гарантии, что любой автор любой бумаги будет прав во всех своих предположениях и выводах. Если вы считаете, что предположение № 4 справедливо, сохраните это предположение и опробуйте свою теорию. Вы можете быть более успешными, чем оригинальные авторы.
Ответ 5
Достаточно хорошее наблюдение, но они могли бы неявно опустить рамку 24x24 или "переполнить" и начать использовать первые пиксели, когда они выходят за границы, как в поворотных сменах, или, как сказал Бретон, они могут рассмотреть некоторые функции как "тривиальные функции", а затем отбросить их с помощью AdaBoost.
Кроме того, я написал Python и Matlab версии вашего кода, чтобы я мог сам проверить код (проще отлаживать и следовать за мной), и поэтому я размещаю их здесь, если кто-нибудь найдет их полезными когда-нибудь.
Python:
frameSize = 24;
features = 5;
# All five feature types:
feature = [[2,1], [1,2], [3,1], [1,3], [2,2]]
count = 0;
# Each feature:
for i in range(features):
sizeX = feature[i][0]
sizeY = feature[i][1]
# Each position:
for x in range(frameSize-sizeX+1):
for y in range(frameSize-sizeY+1):
# Each size fitting within the frameSize:
for width in range(sizeX,frameSize-x+1,sizeX):
for height in range(sizeY,frameSize-y+1,sizeY):
count=count+1
print (count)
Matlab:
frameSize = 24;
features = 5;
% All five feature types:
feature = [[2,1]; [1,2]; [3,1]; [1,3]; [2,2]];
count = 0;
% Each feature:
for ii = 1:features
sizeX = feature(ii,1);
sizeY = feature(ii,2);
% Each position:
for x = 0:frameSize-sizeX
for y = 0:frameSize-sizeY
% Each size fitting within the frameSize:
for width = sizeX:sizeX:frameSize-x
for height = sizeY:sizeY:frameSize-y
count=count+1;
end
end
end
end
end
display(count)