Виктор кинько

Распознавание образов

Одно из важных современных направлений в программном обеспечении — программы, обладающие компьютерным зрением. Данная технология позволяет анализировать информацию в изображениях и видео-файлах. Например, читать текст или обнаруживать расположение определенных объектов.

Для практического изучения данной технологии мной была поставлена задача определения кружки на фотографии. Для реализации было решено использовать android + OpenCV (http://opencv.org/). OpenCV — это библиотека компьютерного зрения с открытым исходным кодом, разработанная для С++, python, java и многих других языков. Она имеет множество функций, но нас интересует возможность обрабатывать изображения и проводить на них поиск объектов с помощью каскадного алгоритма Виолы-Джонса.

Алгоритм Виолы-Джонса — это метод обнаружения объектов на изображениях, основанный на признаках Хаара. Основные его особенности — высокая скорость работы и низкая частота ложных срабатываний. Изначально алгоритм был разработан для обнаружения лиц на изображениях, но его можно натренировать на обнаружение других объектов. Для своей работы он использует разбиения (splitting) изображения на области, оценку яркости в этих областях и отсечения областей, где классифицируемый объект однозначно не находится. Данный алгоритм реализован в openCV отдельной функцией, которой на вход требуется файл-классификатор, определяющий веса для работы алгоритма и изображение, на котором будет проводиться поиск.

Для тренировки классификатора я использовал программу Cascade-Trainer-GUI (http://amin-ahmadi.com/cascade-trainer-gui/), которая предоставляет оконный интерфейс для стандартных программ из набора OpenCV — opencv_createsamples и opencv_traincascade.
Интерфейс программы Cascade-Trainer-GUI
Процесс тренировки начинается с подготовки исходных данных. В качестве исходных данных выступают изображения, содержащие и не содержащие исходный объект. Изображения с объектом считаются позитивными и отправляются в папку p, а те, на которых объект отсутствует — негативными и помещаются в папку n. Стоит заметить, что позитивные изображения должны содержать только распознаваемый объект и ничего больше. Иначе придётся создать файл, который будет содержать координаты объекта на изображении.

opencv_createsamples - это программа, которая генерирует исходные файлы для opencv_traincascade. Негативы формируются по принципу нарезки: из негативной фотографии вырезается случайная область. Позитивы создаются путем помещения какого-нибудь позитивного изображения объекта на негативное, незначительных изменений яркости, поворота и перспективы

После создания этих изображений используется opencv_traincascade, которая принимает полученные образцы и на их основе определяет веса и пропускные пороги для каскадного классификатора. Веса должны быть подобраны так, чтобы сеть отвергала все негативные изображения и принимала все позитивные.

Но это только теория. На практике эти процессы осуществляет Cascade-Trainer-GUI, которому для начала работы требуется только две папки с фотографиями, одна из которых называется p, а другая n. В них хранятся позитивные и негативные образцы соответственно. Для того, чтобы натренировать сеть, мне потребовалось 47 фотографий моего объекта с разным углом камеры, углом падения света, наклоном и яркостью. После этого я удвоил данное число путем зеркального отражения. Негативных фотографий было только 42, но с помощью нарезки изображений было создано 1000 негативных образцов. Часть негативных изображений для разнообразия была взята из интернета.
Положительные образцы из папки p
Отрицательные образцы из папки p
После подготовки данных настраиваем инструмент для тренировки. По большому счёту, большинство настроек не требуется менять, они уже установлены в оптимальные значения, но мне потребовалось изменить пару опций во вкладке train-cascade, а именно sample width и sample height. Эти опции задают пропорции для образцов, для области, которую классификатор будет впоследствии обнаруживать. И если оставить их как есть (обе равны 24 по умолчанию), то обнаруживаемая область будет квадратной. Так как кружка плохо вписывается в квадратную область, то я задал эти параметры равными 30 и 40 соответственно, что исходило из пропорций моих позитивных образцов.
Настройки программы Cascade-Trainer-GUI
Для получения результатов запускаем процесс тренировки. В зависимости от количества входных образцов он занимает различное время. Изначально было использовано малое количество образцов, что привело к плохому результату работы классификатора, но тренировка происходила достаточно быстро (около пяти минут). При 94 позитивных снимках процесс тренировки классификатора занял около трёх часов.
Пример файла классификатора
Имея классификатор, напишем небольшую программу для Android, которая будет снимать изображение на камеру, а после анализировать его с помощью классификатора и выделять на снимке области, содержащие искомый объект. Ниже приведу основные моменты кода, имеющие отношение к нашей задаче.

Инициализация OpenCV:
Стоит обратить внимание на то, что OpenCV инициализируется с помощью функции initDebug, а не initAsync. Это связано c тем, что библиотеки OpenCV в данном случае подключены к проекту напрямую.

Открытие файла классификатора:
Использование классификатора для получения списка областей:
Это функция распознавания объекта на изображении. Она возвращает матрицу объектов типа Rect, то есть распознанных областей. Строка

detector.detectMultiScale(mat, items, 1.1, 3, 0, new Size(25, 25), new Size());
имеет множество параметров. Первый — исходное изображение в формате матрицы OpenCV. Второй — матрица результатов. Остальные параметры: фактор увеличения (насколько меняется размер кадрированного изображения после каждого прохода алгоритма, по умолчанию 1.1), минимальное соседство (помогает устранить ложные срабатывания и обратить множественные срабатывания в одну область, по умолчанию 3), флаги (неиспользуемый legacy-параметр), максимальный и минимальный размер (определяют границы для распознаваемой области). Минимальный размер установлен в 25 пикселей, потому что на меньших областях ложные срабатывания происходят чаще. Максимальный же размер оставлен без ограничений.

Результат работы — программа для телефона, выделяющая на фотографиях кружку зелёным прямоугольником. Не удалось полностью устранить ложные срабатывания, потому иногда детектор выделяет, как кажется, совершенно случайные области. Но тем не менее искомый объект практически всегда выделен на фотографиях.
Пример правильного срабатывания классификатора
Пример правильного срабатывания классификатора
Пример ложного срабатывания классификатора (выделение вокруг тени)
Пример отсутствия объекта на изображении
В итоге можно сказать, что распознавать объекты на фотографиях — не особо сложная задача. Для ее достижения достаточно потратить несколько часов на подготовку образцов и создание классификатора. Единственное препятствие заключается в самих библиотеках OpenCV. Их можно подключить напрямую, включив в проект, но они имеют большой размер. Плюс к этому, такой способ отмечен разработчиками OpenCV, как debug-подключение. Правильным вариантом считается тот, при котором во время инициализации OpenCV приложение предлагает пользователю скачать библиотеки отдельно на телефон. Проблема такого подхода в том, что придётся как-то объяснить пользователю, что для того, чтобы подключить функции распознавания, ему потребуется скачать отдельное приложение.

Альтернатива OpenCV — веб-сервисы для распознавания изображений, к примеру, Clarifai (https://www.clarifai.com/). Такой способ будет работать медленнее и не подойдёт для распознавания объектов в реальном времени, но значительно уменьшит вес итогового приложения. В случае же, если размер итогового приложения (или установка стороннего приложения OpenCV для пользователя) не является проблемой, то такой подход будет верным.
Спасибо за внимание!