Система распознавания лиц Виолы-Джонс заявляет о 180 тысячах функций
-
19-09-2019 - |
Вопрос
Я реализовал адаптацию Алгоритм распознавания лиц Виолы-Джонс.Этот метод основан на размещении подкадра размером 24x24 пикселей внутри изображения и последующем размещении внутри него прямоугольных элементов в каждой позиции и любого возможного размера.
Эти объекты могут состоять из двух, трех или четырех прямоугольников.Представлен следующий пример.
Они утверждают, что исчерпывающий набор превышает 180 тыс. (раздел 2):
Учитывая, что базовое разрешение детектора — 24х24, исчерпывающий набор прямоугольных признаков довольно велик — более 180 000.Заметим, что, в отличие от базиса Хаара, множество прямоугольников features является чрезмерно полным.
Следующие утверждения явно не изложены в статье, поэтому являются предположениями с моей стороны:
- Есть только 2 объекта с двумя прямоугольниками, 2 объекта с тремя прямоугольниками и 1 объект с четырьмя прямоугольниками.Логика этого в том, что мы наблюдаем разница между выделенными прямоугольниками, а не явно цвет, яркость или что-то в этом роде.
- Мы не можем определить тип объекта A как блок пикселей 1x1;он должен быть как минимум 1x2 пикселя.Кроме того, тип D должен иметь размер не менее 2x2 пикселей, и это правило действует соответственно и для других функций.
- Мы не можем определить тип объекта A как блок пикселей 1x3, поскольку средний пиксель не может быть разделен, и его вычитание из самого себя идентично блоку пикселей 1x2;этот тип объекта определен только для четной ширины.Кроме того, ширина объекта типа C должна делиться на 3, и это правило действует соответственно и для других объектов.
- Мы не можем определить объект с шириной и/или высотой 0.Поэтому мы повторяем Икс и й до 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.(Обратите внимание, что это эффективно предотвратит соприкосновение элементов с правой и/или нижней частью подрамника.)
Теперь конечно вопрос:они допустили ошибку в своей реализации?Имеет ли смысл рассматривать объекты с нулевой поверхностью?Или я вижу это неправильно?
Решение
При ближайшем рассмотрении ваш код кажется мне правильным;что заставляет задуматься, была ли у первоначальных авторов ошибка с отклонением на единицу.Думаю, кому-то стоит посмотреть, как это реализовано в OpenCV!
Тем не менее, одно из предложений, облегчающих понимание, — перевернуть порядок для циклы, сначала просматривая все размеры, а затем перебирая возможные местоположения, заданные размером:
#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
Другие советы
все.В бумагах Виолы и Джонса все еще существует некоторая путаница.
В их статье CVPR'01 четко указано, что
«Более конкретно, мы используем тривиды особенностей.Стоимость элемент двух прямоугольников – разность между суммой пикселей в двух прямоугольных областях.Регионы имеют одинаковый размер и и являются горизонтальными или примыкают по вертикали (см. рис. 1). Объект из трех прямоугольников вычисляет сумму в пределах двух внешних прямоугольников, вычитаемых из суммы в прямоугольник в центре.Окончательно a Четырехпрямоугольный элемент".
В статье IJCV'04 говорится то же самое. Итак, всего 4 функции.Но как ни странно, на этот раз заявили, что полный набор функций — 45396!Похоже, это не окончательная версия. Я предполагаю, что там были введены некоторые дополнительные ограничения, такие как min_width, min_height, соотношение ширины/высоты и даже положение.
Обратите внимание, что обе статьи можно загрузить на его веб-страница.
Не прочитав всю статью, мне бросается в глаза формулировка вашей цитаты.
Учитывая, что базовое разрешение детектор 24х24, исчерпывающий набор прямоугольников довольно велик, более 180 000 .Обратите внимание, что в отличие от Базис Хаара, множество прямоугольника features является чрезмерно полным.
"Набор прямоугольных объектов является слишком полным" "Исчерпывающий набор"
для меня это звучит как установка, в которой я ожидаю, что автор статьи объяснит, как они сокращают пространство поиска до более эффективного набора, например, избавляясь от тривиальных случаев, таких как прямоугольники с нулем площадь поверхности.
редактировать:или использовать какой-то алгоритм машинного обучения, как намекает аннотация.Исчерпывающий набор подразумевает все возможности, а не только «разумные».
Нет никакой гарантии, что любой автор любой статьи прав во всех своих предположениях и выводах.Если вы считаете, что предположение № 4 верно, сохраните его и опробуйте свою теорию.Возможно, вы добьетесь большего успеха, чем оригинальные авторы.
Довольно хорошее наблюдение, но они могут неявно обнулить кадр 24x24 или «переполнить» и начать использовать первые пиксели, когда они выходят за пределы, как при вращательном сдвиге, или, как сказал Бретон, они могут рассматривать некоторые функции как «тривиальные функции». а затем отбросьте их с помощью AdaBoost.
Кроме того, я написал версии вашего кода для Python и 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 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)
Матлаб:
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)