Хабрахабр

Распознавание лиц на коленно-прикладном уровне

В общем и целом, распознавание лиц и идентификация людей по их результатам выглядит для аксакалов как подростковый секс — все о нем много говорят, но мало кто практикует. Понятно, что мы уже не удивляемся, что после загрузки фоточки с дружеских посиделок Facebook/VK предлагает отметить обнаруженных на снимке персон, но тут мы интуитивно знаем, что у соцсетей есть хорошее подспорье в виде графа связей персоны. А если такого графа нет? Впрочем, начнем по порядку.

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

Поскольку что на одноплатнике, что на достаточно мощном железе питоновская библиотека была … скажем аккуратно, не очень быстрой, то процесс обработки решили построить следующим образом:
Поэтому буквально за неделю на коленке был собран прототип, состоящий из IP-камеры, одноплатника, датчика движения и питоновской библиотеки распознавания лиц face_recognition.

  • датчик движения определяет, есть ли движение в доверенной ему области пространства и сигнализирует о его наличии;
  • написанный сервис на базе gstreamer-а, который постоянно получает поток с IP-камеры, отрезает 5 секунд до и 10 секунд после детектирования и скармливает это на анализ библиотеке распознавания;
  • та, в свою очередь, просматривает видео, находит там лица, сопоставляет их с известными образцами и в случае обнаружения неизвестных отдает видео в Telegram-канал, в дальнейшем предполагалось там же сделать управление, чтобы сразу отсечь ложно-положительные срабатывания — например, когда сосед повернулся к камере не тем боком, что на семплах.

Весь процесс был склеен нашим любимым Erlang-ом и в процессе тестирования на коллегах доказал свою минимальную работоспособность.

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

Проект ушел на полку и периодически потыкивался палкой на предмет демонстраций при продажах и позывах к реинкарнации в личном хозяйстве.

Поскольку срезать углы в нем при помощи датчика движения не удалось бы прямо от постановки задачи, пришлось углубится в нюансы поиска и распознавания лиц в три головы (окей, две с половиной, если считать мою) непосредственно на потоке. Все поменялось с момента, когда у нас появился более конкретный и вполне коммерческий проект на ту же тематику. И тут случилось откровение.

Нисколько не умаляю заслуги ученых — среди найденных бумаг было немало полезного и интересного, но, увы, вынужден констатировать, что воспроизводимость работы их кода, выложенного на Github-е, оставляет желать лучшего или выглядит вообще сомнительной затеей с бесполезно потраченным временем в итоге. Беда в том, что большая часть обнаруженного по данному вопросу представляет собой чисто академические зарисовки на тему того, что “мне надо было написать статью в журнал на модную тему и получить галочку за публикацию”.

Иными словами, взять готовый пример и запустить его на целевом железе чтобы просто проверить, как оно вообще работает и работает ли, не получалось. Многочисленные фреймворки для нейронных сетей и машинного обучения, зачастую, тоже были тяжелы на подъем — для них распознавание лиц было отдельной узкой задачкой, малоинтересной в широком спектре проблем, которые они решали. Т.е. То не было примера, то необходимость его получения предполагала некислый квест из сборки определенных библиотек определенных версий под строго определенные ОС. чтобы взять и полететь с ходу — буквально крохи наподобие ранее упомянутой face_recognition, которую мы использовали для предыдущей поделки.

И Intel, и Nvidia давно прочувствовали набирающие обороты и коммерческую привлекательность этого класса задач, ну а, будучи поставщиками в первую очередь оборудования, они раздают свои фреймворки для решения конкретных прикладных задач бесплатно. Спасли нас, как всегда, большие компании.

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

Камера напрямую подключалась к неттопу и поставляла на него RTSP-поток с не очень большим FPS, исходя из предположения, что люди все-таки не будут бегать перед ней как на соревнованиях. Для начала мы собрали стенд, представляющий собой традиционно комплект из неттопа с Intel Core i3 процессором и IP-камеры из имеющихся на рынке китайских вендоров. Кроме того, у нас был еще и резервный план — у Intel-а есть специальный сопроцессор для ускорения расчетов нейросетей Neural Compute Stick 2, которую мы могли бы задействовать, если процессора общего назначения нам бы не хватило. Скорость обработки одного кадра (поиск и распознавание лиц) колебалась в районе десятков-сотен миллисекунд, что было вполне достаточно для встраивания еще и механизма поиска персон по имеющимся семплам. Но — пока обошлось.

После завершения сборки и проверки работоспособности базовых примеров — отличительная особенность SDK от Intel оказалась в пошаговом и весьма подробном руководстве к примерам — мы приступили к сборке ПО.

Соответственно, помимо распознавания лиц и сопоставления их с образцами (как это делать, на тот момент, вызывало ничуть не меньше вопросов, чем все остальное) нам было необходимо обеспечить и второстепенные вещи интерфейсного плана. Основная задача, стоявшая перед нами — поиск персоны в области видимости камеры, ее идентификация и своевременное оповещение о ее присутствии. Почему с той же камеры, думаю, тоже вполне очевидно — точка установки камеры на объекте и оптика объектива вносят определенные искажения, которые, предположительно, могут сказаться на качестве распознавания, используй мы другой источник исходных данных, нежели средство слежения. А именно — мы должны получать кадры с лицами необходимых персон с той же камеры для их последующей идентификации.

помимо собственно обработчика потока нам потребуется как минимум видео-архив и анализатор видео-файлов, который позволит вычленить все обнаруженные лица с записи и сохранить наиболее подходящие из них как опорные. Т.е.

Помимо этого нам потребовалось web-UI для обеспечения минимального набора процедур по управлению комплексом, который наш коллега-фронтэндер запилил на VueJS. Как всегда мы взяли привычные Erlang и PostgreSQL в качестве клея между ffmpeg, приложениями на OpenVINO и Telegram Bot API для оповещения.

Логика работы сложилась следующая:

  • под управлением control plane (на Erlang) ffmpeg пишет поток с камеры в видео пятиминутными срезами, отдельный процесс следит за тем, чтобы записи хранились в строго оговоренном объеме и зачищает наиболее старые по достижению этого порога;
  • через web-UI можно просмотреть любую запись, они выстроены в хронологическом порядке, что, хоть и не без труда, позволяет вычленить нужный фрагмент и отправить его на обработку;
  • обработка заключается в анализе видео и выделении кадров с обнаруженными лицами, это как раз делает ПО на базе OpenVINO (надо сказать, тут у нас получилось немного срезать угол — ПО для анализа потока и анализа файлов практически идентичное, из-за чего большая часть ушла в общую библиотеку, а сами утилиты отличаются только цепочкой обработки а-ля модульный gstreamer). Обработка проходит по видео, вычленяя найденные лица при помощи специально обученной нейросети. Полученные фрагменты кадра, содержащие лица, попадают в другую нейросеть, которая формирует 256-элементный вектор, являющийся, по сути координатами опорных точек лица человека. Этот вектор, обнаруженный кадр и координаты прямоугольника найденного лица сохраняются в БД;
  • далее, после завершения обработки оператор открывает многообразие выдернутых кадров, ужасается их количеству и приступает к поиску целевых персон. Выбранные семплы можно добавить уже к существующей персоне или же создать новую. После завершения обработки задачи результаты анализа удаляются, за исключением сохраненных векторов, сопоставленных с записями о наблюдаемых;
  • соответственно, мы можем в любой момент посмотреть и кадры и вектора обнаружения и отредактировать, удалив неудачные семплы;
  • параллельно циклу обнаружения в фоне всегда работает сервис анализа потока, который делает все тоже самое, но уже с потоком с камеры. Он выделяет лица в наблюдаемом потоке и производит их сравнение с образцами из БД, что основывается на простом предположении, что вектора одной персоны будут ближе к друг другу, чем ко всем остальным векторам. Происходит попарное вычисление дистанции между векторами, по достижении порога срабатывания в базу кладется запись об обнаружении и кадр. Помимо этого происходит добавление персоны в стоп-лист на ближайшее время, что позволяет избежать многократных уведомлений об одном и том же человеке;
  • control plane периодически проверяет журнал обнаружения и в случае появления новых записей нотифицирует сообщением с прилагаемым фото и выделением лица через бота тем, кому это разрешено согласно настройкам.

Выглядит это примерно так:

Так мы можем потыкать в архив
Просмотр архива

А так - потыкать в рожицы, засветившиеся в ролике
Результаты анализа видео

А вот и они, эти ребята!
Список наблюдаемых личностей

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

За это время были отмечены следующие наблюдения:
Собранная система тестировалась в тепличных офисных условиях в течение недели.

  • есть четкая зависимость качества распознавания от качества исходных семплов. Если наблюдаемый человек проходит через зону наблюдения слишком быстро, то с большой долей вероятности он не оставит данные для семплирования и не будет распознан. Впрочем, думаю, это вопрос тонкой настройки системы, включая освещение и параметры видеопотока;
  • поскольку система оперирует распознаванием элементов лиц (глаз, носа, рта, надбровных дуг и т.д.), то ее легко обмануть выставлением визуального препятствия между лицом и камерой (волосы, темные очки, надетый капюшон и т.п.) — лицо, скорее всего, будет найдено, но сопоставление с образцами не пройдет из-за сильного расхождения векторов обнаружения и семплов;
  • обычные очки влияют не слишком значительно — у нас были примеры положительных срабатываний на людях в очках и ложно-отрицательные срабатывания на людях, которые надевали очки для проверки;
  • если борода была на исходных семплах, а потом ее не стало, то количество срабатываний уменьшается (автор этих строк подровнял свою бороду до 2 мм и количество срабатываний на нем сократилось вдвое);
  • ложно-положительные срабатывания также имели место, это повод для дальнейшего погружения в математику вопроса и, возможно, решение вопроса о частичном соответствии векторов и оптимальной методике расчета расстояния между ними. Впрочем, тестирование в полевых условиях должно вскрыть еще больше проблем в этом аспекте.

Что предстоит? Проверка системы боем, оптимизация цикла обработки обнаружений, упрощение процедуры поиска событий в видео-архиве, добавление большего количества данных в анализ (возраст, пол, эмоции) и еще 100500 мелких и не очень задачек, которые еще предстоит сделать. Но первый шаг в пути из тысячи шагов мы уже сделали. Если кто поделится своим опытом в решении подобных задач или даст интересные ссылки по этому вопросу — буду весьма признателен.

Показать больше

Похожие публикации

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»