Pull to refresh

Обучение OpenCV каскада Хаара

Reading time 8 min
Views 191K
На хабре уже есть несколько статей и про то, что такое каскад Хаара (раз, два, три). Есть даже одна, где затронут процесс обучения, но в отношении описанной задачи. На тему обучения есть пара неплохих статей на английском (первая, вторая, третья), но, на мой взгляд, они путанные: либо рассказывают очень мало, либо слишком много и обо всём — выделить нужную мысль сложно.
image
В этой статье я попробую показать, как обучить каскад с нуля за несколько часов, натренировав на поиск простого предмета в видеопотоке (примером будет очаровательная сова с фотографии). Все обучающие выборки и программы будут приложены.
Зачем всё это нужно? Каскад Хаара это один из простейших способов распознавания классов объектов с большой скоростью работы. К ним относятся лица и руки людей, номера автомобилей, пешеходы. Детектором Хаара просто находить животных в кадре (кстати, удивительно, что я не видел ещё ни одной автоматической кормушки для синиц на raspberry pi). К тому же, готовые реализации OpenCV есть под большинство существующих систем (даже для blackfin'a встречал). Всё это делает Хаара одним из самых удобных методов, позволяющих решать задачи видеообработки даже людям, которые никогда не работали с обработкой видео.


NB!!!


Статья которую вы читаете — из 2014 года. С тех пор произошла революция в обработке изображений. Сегодня не следует использовать каскады Хаара для детектирования чего бы то ни было. Появилось масса нейронных сетей которые работают быстрее и лучше. На телефонах появилась аппаратная поддержка исполнения нейронных сетей. Масса простых и удобных фреймворков для тренировки и исполнения нейронных сетей.
Тот же OpenCV, о котором тут речь, умеет исполнять практически любую заранее обученную нейронную сеть (почитать об этом можно, например, в другой моей статье).
Что использовать? Я не знаю в каком году вы читаете эту статью. Мои ответы за прошлые года 4 разительно менялись. Например в начале 2019 года я записывал такое видео. Но сейчас, в 2020, оно уже не очень актуально. Может быть лучше смотреть в сторону EfficientDet, Yolov4, и IterDet, и другие детекторы.
А TensorFlow Detection Api кардинально изменился с тех пор, в второй версии. Да и для новичков я бы советовал скорее PyTorch.
Короче, я бы советовал гуглить. Гуглите «neural network for detection», или «training detection network». И внимательно следите за годом!
И ещё. Если я правильно понимаю, то OpenCV в 2020 уже не имеет порядочный кусок из функций описанный в статье. Если вы все же хотите использовать написанное тут — используйте версию OpenCV тех лет.
А так, я часто пишу на своем канале (vk, telegram) про более новые методы/подходы.

Процесс

Весь процесс обучения выборки не требует навыков программирования. Для этого имеются уже готовые консольные программы, присутствующие в основной сборке OpenCV. Использование каскада требует минимального навыка программирования, достаточно изменить пару строк уже в готовом примере, которые есть под С, С++, С#, Java, Python и.т.д.

Что нам будет нужно?

  • Фотографии предмета в реальной среде обитания. Чем более похожа выборка будет на то, что мы будем распознавать, тем лучше будут результаты. Если обучать распознаватель лица по фотографиям людей из студии, то на улице уровень распознавания будет ниже, чем в студии. На это влияют как тени, одежда, так и выражение лица.
  • Выборка отрицательных фотографий, на которых нет объекта распознавания. Фотографии должны быть сделаны в той же среде где будет распознавание. Если выборка контрпримеров будет сделана по фотографиям на северном полюсе, а распознавать будете в тропических джунглях, то ничего не заработает.
  • OpenCV. В этой статье использовался актуальный сейчас 2.4.7. Все программы примеры, расположенные тут будут работать с ним. Но если делаете проект с нуля — лучше скачайте новый OpenCV.

Где достать примеры и контрпримеры?

Есть несколько способов:
  • Наснимать фотоаппаратом самому.
  • Использовать готовую базу, если она есть в интернете. Для лиц, номеров, глаз, эмоций, людей и.т.д. таких баз много.
  • Включить видеокамеру и сделать набор снимков из видеопотока.
  • Использовать софтину, приложенную к OpenCV и сгенерировать новые выборки из имеющихся 2-3 изображений. Этот вариант подробно описан тут, я не буду на нём останавливаться. Работает он плохо, для серьёзных целей не годится.

Для вариантов 1-3 есть несколько программ упрощающих жизнь. В первую очередь это программы, позволяющие разметить фотографии. В статьях на английском используется самописная программа " imageclipper". Мне она не понравилась, так как некорректно работает с большими фотографиями. Для себя я написал программу, с которой было удобно работать мне. Исходники и код приложены в разделе «Загрузки» этой статьи (программа PictureCropper).

Сколько нужно фотографий?

Для стабильно работающего детектора лиц это 3000-4000 положительных примеров и столько же отрицательных. Из 500 положительных и 1000 отрицательных я делал стабильный детектор номеров. Для детектора, который показан в этой статье, я взял 250 положительных и 500 негативных фотографий.
Чем больше и разнообразнее выборка, тем стабильнее работает и тем дольше обучается.

Приступаем к работе.

Для того, чтобы начать обучение, нам нужно иметь 2 папки с примерами. «Good» — папка с позитивными изображениями, «Bad» — с отрицательными. ВАЖНО! По крайней мере, в одной из прошлых версий программы обучения она плохо реагировала на наличие пробелов и точек в названии файлов. Русский не воспринимает никакая версия. Старайтесь называть изображения «0.bmp», «1. bmp » и.т.д. Форматы " bmp " и «jpg» работают стабильно, с остальными не проверял.
Для каждой папки нужно иметь текстовый файл, в котором описаны используемые изображения. Назовём их «Good.dat» и «Bad.dat». ВАЖНО! Этот файл должен лежать на том же уровне файловой системы, на котором лежит папка.
\Good
      \1. bmp
      \2. bmp
      \.... bmp
      \N. bmp
\Bad
      \1. bmp
      \2. bmp
      \.... bmp
      \N. bmp
Good.dat
Bad.dat

Файлы описания для отрицательных и положительных объектов имеют разную структуру. Для файла отрицательных примеров это просто список относительных путей к изображениям:
Bad\1. bmp
Bad\2. bmp
Bad\.... bmp
Bad\N. bmp

Для файлов с положительными примерами запись чуть хитрее. Кроме пути должно быть указанно положение рассматриваемого объекта и его размер. В принципе, каждое положительное изображение может содержать несколько примеров объектов. Но я так не советую. Лучше всего: один кадр — один объект.
Good \0.bmp  1  0 0 414 148
Good \1.bmp  1  0 0 568 164
Good \....bmp  1  0 0 440 144
Good \N.bmp  1  0 0 590 182

" Good \0.bmp " — адрес объекта относительно файла описания. «1» — количество положительных объектов на изображении. «0 0 414 148» — координаты прямоугольника на изображении в котором находится объект. Если объектов несколько, то запись приобретает вид: «Good \0.bmp 2 100 200 50 50 300 300 25 25».
Повторюсь, что удобнее всего, когда каждый объект представляет собой отдельный кадр, при этом координаты объекта равны размеру кадра.

Пример снимков положительной выборки:
image image image image image

Пример снимков отрицательной выборки:
image image image image image

Начинаем обучать!

Само обучение происходит в два этапа. Первый этап — все положительные изображения приводятся к общему формату. Делать это нужно расположенной в папке OpenCV программой. Возьмите ту, что соответствует вашей системе. У меня это " opencv\build\x64\vc10\bin ". Программа называется opencv_createsamples.exe.
Для создания пачки приведённых положительных изображений запустим opencv_createsamples через консоль:
opencv_createsamples.exe -info E:\BAZAS\Sova\Good.dat -vec samples.vec -w 20 -h 20

-info E:\BAZAS\Sova\Good.dat – файл описания положительных изображений. Указывается либо полный адрес, либо относительно программы opencv_createsamples.exe.
-vec samples.vec – файл, в который будет сохранена приведённая к общему формату база положительных изображений. Адрес должен быть указан относительно программы opencv_createsamples.exe (допустим полный путь в системе).
-w 20 -h 20 — размер шаблона. Должен приблизительно отражать пропорции искомого объекта. Например, для лиц или для совы наиболее подходящая пропорция высоты к ширине 1*1. Для номеров это 3*1. А для поиска карандаша логично поставить что-то вроде 8*1. Размер шаблона должен быть достаточно маленьким. Идеально ставить его таким, чтобы человек сам мог отличить изображённый объект, но не больше того. Чем больше шаблон, тем дольше обучение.
Результатом работы программы является файл samples.vec, в котором будут лежать все ваши положительные изображения в формате, близком к bmp и с размером w*h.

Создаём итоговый каскад

Для подсчёта итогового каскада используется программа «opencv_traincascade.exe», лежащая в той же папке, что и opencv_createsamples.exe. Работает долго. Даже очень долго. Обучение каскада на 500-1000 объектов займёт почти целый день. Пример обучался часа 2. При вызове:
opencv_traincascade.exe -data haarcascade -vec samples.vec -bg E:\BAZAS\Sova\Bad.dat -numStages 16 -minhitrate 0.999 -maxFalseAlarmRate 0.4 -numPos 200 -numNeg 500 -w 20 -h 20 -mode ALL -precalcValBufSize 1024 -precalcIdxBufSize 1024

-data haarcascade — адрес папки, куда класть полученные результаты. Отсчитывается от корневой папки программы. Нужно создать заранее, а то всё вылетит.
-vec samples.vec — адрес посчитанного в прошлом пункте файла с положительными примерами
-bg E:\BAZAS\Sova\Bad.dat — адрес файла-описания отрицательных примеров
-numStages 16 — количество уровней каскада, которые программа будет обучать. Чем больше уровней, тем точнее, но тем дольше. Нормальное их количество от 16 до 25.
-minhitrate 0.999 — коэффициент, определяющий качество обучения. По сути, это процент “правильных” обнаружений. Если установлено .999, то есть по исходной выборке будет не более, чем 1- 0.999 =0.1% пропусков целей. Чем выше коэффициент, тем выше уровень ложных тревог. В принципе, если выборка хорошая, можно ставить 0.99-0.999. Если плохая ( объектов мало, они смешиваются с фоном) — то следует опускать.
-maxFalseAlarmRate 0.4 — уровень ложной тревоги. AdaBoost — такой алгоритм, который может любой уровень ложной тревоги по выборке натянуть. Но лучше что-то разумное сделать. По умолчанию все ставят 0.5. Но, возможно, будет иметь смысл поиграться. В случае, если выборка очень хорошая, то уровень требуемой тревоги будет быстро достигнут, и обучение будет остановлено.
-numPos 200 — количество позитивных примеров. ВАЖНО! Казалось бы, тут должно стоять число файлов, которые у вас были. Но это не так (в большинстве руководств это не отмечено). Чем ниже коэффициент «minhitrate », тем больше ваших файлов будет считаться непригодными. В большинстве случаев достаточно поставить numPos 80% от имеющихся у вас положительных файлов. Лучше перестраховаться, чтобы через день работы программа не вылетела с ошибкой:)
-numNeg 500 — количество имеющихся у вас негативных примеров. Что есть — то и пишем.
-w 20 -h 20 — размер примитива из прошлого пункта.
-mode ALL — использовать или нет полный комплект Хаар-признаков. От этого зависит скорость работы и точность алгоритма. Но есть ситуации, когда полного комплекта признаков не нужно (например, если ваш объект не меняет ориентацию).
-precalcValBufSize 1024 -precalcIdxBufSize 1024 — выделяемая под процесс память. Вроде, в последней версии OpenCV, сколько я заявил, примерно столько программа и съела, но чуть более ранние версии ели где-то в 2 раза больше. Если во время обучения вы планируете пользоваться компьютером, то ставьте столько памяти, чтобы вам хватило на дальнейшую работу.

Известные баги

Нужно сказать, что обучение не страдает юзабельностью. Есть много багов. Но потихоньку OpenCV исправляется. В последнем OpenCV достаточно подробно объясняются большинство причин, по которым вылетает программа. Как правило, это нехватка положительных или отрицательных примеров, недостижимые характеристики, криво написанные адреса. Правда, был какой-то глюк с подвисанием обучения, когда я обучал выборку по сове. Cудя по всему, было слишком мало тестовых примеров (я тогда использовал 150 сов и 200 контр-примеров).

Результаты

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


Исходники

Как и обещал, пример проекта и несколько программок, облегчающих жизнь. Скачать целиком можно либо тут (rar-архив на яндекс-диске), либо тут (github). Но на гитхабе максимальный объем файла 100 мегов, а сборка Emgu (OpenCV для C#), которую я использую, тянет два больших файла OpenCV-шных, которые не используются, но которые нельзя исключить из проекта. Оба этих файла лежат внутри папки Bin\x86, заархивированы в архиве «lagedll.rar», их нужно просто вытащить наружу.
Весь проект на VS2010, Windows 7. Все исполняемые программы лежат в папке " Bin".
VideoCropper — Программа для создания последовательности с видеокамеры. При старте нужно указать папку для сохранения и режим работы (создание положительной или отрицательной выборки). Мышкой выделяется область, которая будет сохранена, по пробелу происходит сохранение области.
PictureCropper — Программа для нарезки имеющейся базы фотографий. При старте указывается рабочая папка. Создает подпапку с нарезанными изображениями. Мышкой выделяется область которая должна быть сохранена. По «s» происходит сохранение. По «r» – сохранение и переход к следующему изображению. По пробелу — просто переход к следующему изображению.
OwlDetector — итоговая программа, ищущая сову
Bad, Good — папки с отрицательными и положительными примерами
haarcascade — Итоговые каскады, полученные при обучении
Bad.dat, Good.dat — файлы описания изображений
samples.vec — файл с набором положительных изображений, подготовленный для обучения
Tags:
Hubs:
+55
Comments 19
Comments Comments 19

Articles