Computer Vision, Machine Learning
51,5
рейтинг
4 января 2014 в 05:38

Разработка → Обучение OpenCV каскада Хаара tutorial

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

Процесс

Весь процесс обучения выборки не требует навыков программирования. Для этого имеются уже готовые консольные программы, присутствующие в основной сборке 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 — файл с набором положительных изображений, подготовленный для обучения
Мальцев Антон @ZlodeiBaal
карма
266,7
рейтинг 51,5
Computer Vision, Machine Learning
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (18)

  • +6
    Но для выборки, в которой всего две сотни примеров, это неплохой результат.

    200 примеров это ведь, вообще говоря, очень много. Странно что только треть кадров (субъективно) распозналась, как содержащие искомый объект.
    В чем причина таких результатов — плохое обучение?
    Т.к. с лицами детекторы Хаара работают хорошо.
    • +5
      Для лиц используется более нескольких тысяч примеров обычно. Плюс я не использовал максимальную сложность обучения (где-то два часа считало всего, а для тех же лиц обучение на неделю — это норма).
      200 примеров не очень много. Всё-таки 3d объект. Я старался сделать кадры в разных проекциях + разный размер (хотя это немного спорное решение, не думаю, что это повысило сильно качество). Если сравнить размер итогового каскада для совы (46 Кб) и для лиц (около 1.5Мб), то видно, что для лиц сложность обучения на порядки выше.
      Ещё, кстати, есть момент, что лица при обучении обычно фотографируют для идеальных условий, но полностью покрывая интересующую область детектирования (шаг поворота, освещение, размер). Тут такая методология не применялась.

      В целом, ответ на вопрос думаю такой:
      1) Для обучения использовал достаточно слабый набор алгоритмов, ускоряющих это самое обучение. Обучение не полное.
      2) Для обучения использовалась база, не полностью описывающая все возможные сдвиги и повороты.
      3) Тестирование делалась на фоне той же стены, на которой производилась съёмка отрицательной выборки. Есть шанс, что часть кадров с совой имеют слишком большое пересечение с отрицательной выборкой, поетому не распознаются.
      • 0
        Скажите, не было проблем с зависанием обучения каскада. К тому же у меня были вылеты после 6-9 прохода.
        • 0
          Да, были. Именно из-за них я абзац «Известные баги» вставил. Мне помогло увеличить размер выборки + чуть-чуть подвинуть пороги правильных обнаружений и ложных тревог.
          • 0
            Делал на выборке: 1к позитивов и 5к негативов, однако зависало, что-то с параметрами нужно шаманить я думаю.
            • 0
              Какая версия OpenCV? Просто последняя версия на порядки меньше глючила у меня. Плюс причины отказа писала.
              У вас параметр numPos был меньше, ч ем число положительных примеров?
              • 0
                Да вот это я не учел. Ставил количество позитивов.
  • 0
    Спасибо за интересный материал!
    Имеет ли смылс бинаризировать изображение (для уменьшения влияния теней и полутонов) и уже потом раскладывать в папки Good\Bad?
    • +1
      На мой взгляд не имеет. Каскад Хаара вычисляет признаки в интегральной картинке. В случае бинаризации на одном изображении тень на лице быть +1, а на соседнем изображении — 0. При интегрировании это даст достаточно много шумов.
      А подсчёт признака в интегральном изображении, который Хаар делает сам по себе будет давать нормировку, при этом нормировка будет локальной, что заведомо лучше нормировки, которую сделает бинаризация.
  • +3
    Воспользуйтесь видео-потоком, как дополнительным источником для аналитического обучения.

    Если между «узнаваниями» было меньше N кадров, они собираются, интерполируется перемещение найденного объекта (принимается, что оно линейное + погрешность), проверяется, что разница между изображением и вырезанным кадром не более D (объект не пропадал полностью из области из-за помех). При выполнении всех условий вырезанный кадр добавляется к позитивной выборке и используется для обучения.

    Таким образом, точность узнавания будет прогрессивно расти, улучшая результаты с каждым полученным материалом.
    • 0
      Как развитие, Вы можете обеспечить узнавание объекта со всех сторон, добавив анализ изменения геометрии и перемещения контрольных точек, чтобы определить поворот объекта в пространстве. Тогда запомнив только «лицо» объекта, Ваша программа сможет обнаружить его вращение на кадре и ассоциировать найденные углы обзора на объект с самим объектом. Улучшить алгоритм можно будет распараллеливанием: один поток работает в режиме реального времени с видео-потоком, ведет анализ пропущенных кадров, остальные потоки анализируют кешированные последние N минут видео для поиска объекта с новыми полученными первым потоком знаниями: например, в случае быстрого поворота объекта в первых минутах видео нельзя было ассоциировать новое положение объекта с объектом, тогда «узнав» больше признаком в дальнейшем, можно будет вернуться к началу видео и разобрать пропущенные кадры после проведения повторного поиска.
      • +1
        Гхм:)
        Да, я прекрасно знаю, как это делается… Но статья была как-бы не об этом:) К тому же при использовании штатного OpenCV-обучения пересчёт каскада невозможен. А с нуля да, можно, хотя наибольшую сложность там будет составлять именно написание такого алгоритма обучения, который может на ходу обучаться (но исходники того же predator где-то по интернетам бродили).
        А для связи соседних кадров много можно способов использовать. Например тот, который я в своей позапрошлой статье упоминал — тоже неплохо работать будет. Хотя через оптический поток, конечно менее затратно по вычислениям будет.
  • 0
    Как лучше поступить: создать каскады для всех возможных видов объекта или сделать отдельный для вида спереди, сзади и т.д?
    • 0
      Лучше создавать отдельные каскады, насколько я понимаю теорию обучения AdaBoost. Явных ограничений там вроде нет, но всё-таки она затачивается на то, что есть две связанные области.
  • 0
    Как-то статья неожиданно оборвалась. Вот обучили мы каскад Хаара, и что у нас получилось? Какой-то файл с данными? И что с ним делать? У вас сразу видео идёт, а как вы его сделали непонятно.
    • 0
      Хм. Да, наверное стоит чуть подробнее объяснить, как-то глаз за это не зацепился. Но там всё действительно просто. Достаточно полученный файл положить в папку с программой распознавания и всё будет работать. Сейчас до дома доберусь, опишу поподробнее.
  • 0
    А если стоит задача различать объекты примерно одной формы, но разного цвета? Какими средствами ее оптимально решать? Например, домофон, который пускает только белых людей, а негров нет (утрированно)?
    • 0
      Нужно смотреть под каждую конкретную задачу. Можно например работать в канале H пространства HSV. А с неграми очень просто. Выделяется сначала лицо, а потом по лицу анализируется цвет.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.