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

Распознавание лиц - один из самых фундаментальных аспектов компьютерного зрения. Это основа для многих дальнейших исследований, таких как идентификация конкретных людей и выделение ключевых точек на лице. В последнее время это довольно часто упоминается в новостях из-за инцидентов с расовым профилированием, разработанных здесь и здесь, когда цветных людей идентифицируют чаще, чем белых. Поэтому крупные технологические компании, такие как IBM, Microsoft и Amazon, запретили использование своих систем полицией. Однако в этой статье мы не будем подробно останавливаться на этих аспектах, и мы просто попытаемся нарисовать ограничивающие рамки на лицах, используя предварительно обученные модели, такие как каскады Хаара, фронтальный детектор лиц dlib, MTCNN и модель Caffe с использованием модуля DNN OpenCV. Затем мы сравним их, чтобы выяснить, что лучше всего подходит для приложений реального времени.

Оглавление

  • Вступление
  • Установка
  • Кодирование моделей
  • Сравнение результатов на изображениях
  • Результаты сравнения видео с достигнутой частотой кадров
  • Заключение

Вступление

Мы будем использовать Haar, dlib, многозадачную каскадную сверточную нейронную сеть (MTCNN) и модуль DNN OpenCV. Если вы уже знаете о них или не хотите вдаваться в их технические подробности, не стесняйтесь пропустить этот раздел и сразу перейти к коду. В противном случае давайте узнаем, как они работают.

Каскады Хаара

Они были предложены еще в 2001 году Полом Виолой и Майклом Джонсом в их статье Быстрое обнаружение объектов с использованием усиленного каскада простых функций. С ним очень быстро работать, и, как и с простым CNN, он извлекает множество функций из изображений. Затем с помощью Adaboost отбираются лучшие функции. Это сокращает исходные 160000+ функций до 6000. Но применение всех этих функций в скользящем окне все равно займет много времени. Поэтому они ввели каскад классификаторов, в котором функции сгруппированы. Если окно выходит из строя на первом этапе, оставшиеся функции в этом каскаде не обрабатываются. Если он прошел, то тестируется следующая функция и повторяется та же процедура. Если окно может передавать все функции, оно классифицируется как область лица. Более подробное прочтение вы можете найти здесь.

Каскады Хаара требуют для тренировки множества положительных и отрицательных обучающих образов. К счастью, эти каскады поставляются в комплекте с библиотекой OpenCV вместе с обученными файлами XML.

Длиб Фронтальный Детектор Лица

Dlib - это набор инструментов C ++, содержащий алгоритмы машинного обучения, используемые для решения реальных проблем. Хотя он написан на C ++, у него есть привязки к python для его запуска на python. В нем также есть отличный детектор ключевых точек на лице, который я использовал в одной из своих предыдущих статей, чтобы создать систему отслеживания взгляда в реальном времени.



Детектор фронтального лица, предоставляемый dlib, работает с использованием функций, извлеченных с помощью гистограммы ориентированных градиентов (HOG), которые затем передаются через SVM. В дескрипторе объекта HOG в качестве признаков используется распределение направлений градиентов. Более того, Dlib предоставляет более продвинутый детектор лиц на основе CNN, который, однако, не работает в режиме реального времени на ЦП, что является одной из целей, к которым мы стремимся, поэтому в этой статье он был проигнорирован. Тем не менее, если вы хотите прочитать об этом, можете сослаться здесь.

MTCNN

Он был представлен Kaipeng Zhang и др. в 2016 году в своей статье Совместное обнаружение и выравнивание лиц с использованием многозадачных каскадных сверточных сетей. Он не только распознает лицо, но и определяет пять ключевых точек. Он использует каскадную структуру с тремя ступенями CNN. Во-первых, они используют полностью сверточную сеть для получения окон кандидатов и их векторов регрессии ограничивающей рамки, а сильно перекрывающиеся кандидаты перекрываются с использованием подавления по максимуму (NMS). Затем эти кандидаты передаются в другую CNN, которая отклоняет большое количество ложных срабатываний и выполняет калибровку ограничивающих прямоугольников. На завершающем этапе выполняется определение лицевых ориентиров.

Детектор лиц DNN в OpenCV

Это модель Caffe, которая основана на детекторе Single Shot-Multibox (SSD) и использует архитектуру ResNet-10 в качестве основы. Он был представлен после OpenCV 3.3 в модуле глубокой нейронной сети. Существует также квантованная версия Tensorflow, которую можно использовать, но мы будем использовать модель Caffe.

Установка

Dlib и MTCNN могут устанавливаться по пипу, тогда как для детекторов лиц Haar Cascades и DNN требуется OpenCV.

pip install opencv-python
pip install dlib
pip install mtcnn

Если вы используете Anaconda, установите их с помощью команд conda:

conda install -c conda-forge opencv
conda install -c menpo dlib
conda install -c conda-forge mtcnn

Кодирование моделей

В этом разделе я объясню код всех этих различных моделей. Веса дескриптора Dlib и MTCNN на основе HOG уже поставляются вместе с их установкой. Каскадные XML-файлы Хаара вместе с весами и файлом слоев детектора лиц модуля DNN можно загрузить из моего репозитория на Github.

Хаар Каскад

import cv2
classifier = cv2.CascadeClassifier('models/haarcascade_frontalface2.xml')
img = cv2.imread('test.jpg')
faces = classifier.detectMultiScale(img)# result
#to draw faces on image
for result in faces:
    x, y, w, h = result
    x1, y1 = x + w, y + h
    cv2.rectangle(img, (x, y), (x1, y1), (0, 0, 255), 2)

Как видите, делать прогнозы с помощью каскадов Хаара очень просто. Просто инициализируйте модель с помощью cv2.CascadeClassifier с последующим обнаружением с помощью cv2.detectMultiScle. Затем обведите все лица петлей и нарисуйте их на изображении.

Фронтальный детектор лица на базе Dlib HOG

import dlib
import cv2
detector = dlib.get_frontal_face_detector()
img = cv2.imread('test.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = detector(gray, 1) # result
#to draw faces on image
for result in faces:
    x = result.left()
    y = result.top()
    x1 = result.right()
    y1 = result.bottom()
    cv2.rectangle(img, (x, y), (x1, y1), (0, 0, 255), 2)

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

MTCNN

import cv2
from mtcnn.mtcnn import MTCNN
detector = MTCNN()
img = cv2.imread('test.jpg')
faces = detector.detect_faces(img)# result
#to draw faces on image
for result in faces:
    x, y, w, h = result['box']
    x1, y1 = x + w, y + h
    cv2.rectangle(img, (x, y), (x1, y1), (0, 0, 255), 2)

Загрузите модуль MTCNN из mtcnn.mtcnn и инициализируйте его. Функция detect_faces используется для поиска результатов. Это возвращает словарь стиля JSON, который содержит координаты лиц, а также их уверенность в предсказании и координаты обнаруженных ориентиров на лицах.

Фронтальный детектор лица модуля DNN

import cv2
import numpy as np
modelFile = "models/res10_300x300_ssd_iter_140000.caffemodel"
configFile = "models/deploy.prototxt.txt"
net = cv2.dnn.readNetFromCaffe(configFile, modelFile)
img = cv2.imread('test.jpg')
h, w = img.shape[:2]
blob = cv2.dnn.blobFromImage(cv2.resize(img, (300, 300)), 1.0,
(300, 300), (104.0, 117.0, 123.0))
net.setInput(blob)
faces = net.forward()
#to draw faces on image
for i in range(faces.shape[2]):
        confidence = faces[0, 0, i, 2]
        if confidence > 0.5:
            box = faces[0, 0, i, 3:7] * np.array([w, h, w, h])
            (x, y, x1, y1) = box.astype("int")
            cv2.rectangle(img, (x, y), (x1, y1), (0, 0, 255), 2)

Загрузите сеть с помощью cv2.dnn.readNetFromCaffe и передайте слои и веса модели в качестве аргументов. Это находится на странице Github OpenCV DNN.

Для достижения максимальной точности запустите модель на изображениях BGR с размером 300x300, применяя среднее вычитание значений (104, 177, 123) для каждого синего, зеленого и красного каналов соответственно.

В отношении ценности зеленого цвета существует много несоответствий. В статьях pyimagesearch и Learnopencv я обнаружил, что оба они использовали 117 вместо 177, поэтому я использовал 117 в функции cv2.dnn.blobFromImage. Наконец, возвращается четырехмерный массив, который содержит достоверность и координаты, уменьшенные до диапазона от 0 до 1, так что путем их умножения на исходную ширину и высоту можно получить прогнозы для исходного изображения, а не 300x300 на котором предсказывала модель.

Сравнение результатов на изображениях

Я создал две небольшие базы данных, содержащие 10 изображений, каждая из которых создана из фотографий из Unsplash, а другая из Google, чтобы увидеть, как эти методы работают как с большими, так и с маленькими изображениями. Давайте посмотрим на них один за другим.

Unsplash

Прежде чем я начну, я хотел бы отдать должное Брюсу Диксону, Крису Карри, Крису Мюррею, Итану Джонсону, Джерри Чжану, Джессике Уилсон, Роланду Сэмюэлю и Тиму. Mossholder », изображения которого я использовал. Поскольку средние размеры изображений составляли около 5000x5000, высота и ширина были уменьшены вдвое перед обработкой.

Каскады Хаара, как и ожидалось, показали худшие результаты из всех, также имея много ложных срабатываний. Dlib и MTCNN показали довольно равномерную производительность, при этом одна кромка опережала другие и наоборот. Модуль DNN работал по принципу «все или ничего». При ближайшем рассмотрении мы видим, что он не работал хорошо с изображениями с маленькими размерами лица, что могло произойти из-за изменения его размера до 300x300 перед запуском, поэтому давайте посмотрим, как это было бы, если бы был взят исходный размер. Для этого просто измените (300, 300) в cv2.dnn.blobFromImage() на исходную ширину и высоту соответственно и удалите функцию изменения размера.

Таким образом, результаты были значительно улучшены за счет получения полноразмерных изображений, однако, таким образом, модуль DNN не смог сделать никаких прогнозов, если размер лица большой. Пример:

Google картинки

Эти изображения из Unsplash были очень большими, поэтому я решил также проверить несколько небольших изображений, чтобы увидеть их производительность. Все сделанные изображения имели лицензию на повторное использование с модификациями. Средние размеры составляют 220x220, и они обрабатываются как есть, за исключением модуля DNN, где изображения изменяются до 300x300, и результаты не были хорошими, если использовались изображения исходного размера.

Это создало проблему для детектора лиц Dlib, поскольку он не может обнаруживать лица размером менее 80x80, а поскольку изображения были очень маленькими, лица были еще меньше. Таким образом, изображение было увеличено в 2 раза для тестирования, но это огромная проблема при использовании Dlib, поскольку размер лица не может быть очень маленьким, а повышающая дискретизация изображения приведет к увеличению времени обработки.

И снова, как и ожидалось, Хаар показал худшее. MTCNN дал отличные результаты, за исключением пары изображений, и не смог идентифицировать всего 2 лица. DNN заняла второе место и не смогла идентифицировать 3 лица. Dlib пропустил намного больше лиц, и мы также не должны забывать, что у него уже были увеличены изображения в 2 раза.

Итак, прежде чем перейти к видео-части, давайте подведем итоги того, что мы узнали из результатов этого раздела.

  • Хаар довольно устарел и обычно дает худшие результаты.
  • Модель обнаружения лиц модуля DNN OpenCV работает хорошо, но если размер изображения очень большой, это может вызвать проблемы. Как правило, мы не работаем с такими изображениями размером 3000x3000, поэтому это не должно быть проблемой.
  • Dlib не обнаруживает лица размером менее 80x80, поэтому при работе с небольшими изображениями убедитесь, что вы увеличили их масштаб, но это увеличит время обработки.
  • Итак, учитывая два вышеупомянутых пункта, MTCNN был бы лучшим выбором, если бы мы имели дело с экстремальными размерами лица и, можно сказать, до сих пор лидировал в соревнованиях.

Примечание. В прогнозе Длиба иногда не хватает подбородка или лба из-за лица, которое было вручную аннотировано Дэвисом Кингом, автором Dlib, поэтому, если задача, над которой вы работаете, не может себе этого позволить, не делайте этого. используйте Dlib.

Сравнение моделей на видео

Прежде чем начать, почему бы не уточнить, на каких задачах мы будем тестировать наши модели:

  • Разные углы лица
  • Голова движется
  • Окклюзия лица
  • Различные условия освещения
  • Достигнута частота кадров

Размер каждого кадра, передаваемого в модели, составляет 640x360, и они обрабатываются как есть, за исключением модели DNN, которая уменьшена до 300x300.

Различные углы движения лица и головы

Модуль OpenCV DNN добился успеха здесь. Он мог обнаруживать боковые грани под безумными углами, а также его не беспокоило быстрое движение головы. Остальные не смогли ему противостоять и потерпели неудачу при больших углах и быстром движении.

Окклюзия лица

Опять же, явным победителем здесь является модуль распознавания лиц DNN OpenCV. Позвольте мне привести точные результаты. Всего в этом видео 642 кадра. Модуль DNN смог обнаружить лица у 601 из них! Для сравнения, второе место занял Хаар, да Хаар, который получил лицо в 479 из них, за ним следует третье место в MTCNN с 464 кадрами. Длиб сильно отстал с лицом, обнаруженным всего в 401 кадре.

Различные условия освещения

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

Давайте воздадим должное, поскольку только каскад Хаара был единственной моделью, способной обнаруживать лицо в темноте за пару кадров, в то время как модель DNN дала ложное срабатывание в течение этого времени. Когда свет был включен, модуль DNN вернулся к работе, давая совершенно точные прогнозы. Вывод Dlib был немного нестабильным, но лучше, чем каскад Хаара, который мог предсказывать еще меньше кадров и также давал несколько ложных срабатываний. Настоящим сюрпризом стал MTCNN. Он не смог обнаружить лицо даже в одном кадре, что говорит о том, что условия освещения должны быть хорошими, чтобы его можно было использовать.

Частота кадров

Приведенные значения получены с использованием процессора Intel i5 7-го поколения, а размер передаваемого изображения составляет 640x360, за исключением модуля DNN, которому передается изображение 300x300, как это делалось до сих пор.

Хаар - 9,25 кадра в секунду

Dlib - 5,41 кадра в секунду

MTCNN - 7,92 кадра в секунду

Модуль DNN OpenCV - 12,95 кадра в секунду

Заключение

  • Классификатор Haar Cascade дал худшие результаты в большинстве тестов наряду с множеством ложных срабатываний.
  • Dlib и MTCNN дали очень похожие результаты с небольшим преимуществом по сравнению с MTCNN, но Dlib не может идентифицировать очень маленькие лица. Также, если размер изображений очень велик и есть уверенность в том, что освещение будет хорошим с минимальной окклюзией и, в основном, лицевыми сторонами, MTCNN может дать лучшие результаты, как это было видно при сравнении изображений.
  • Для решения общих проблем компьютерного зрения лучше всего подходит модель OpenCV Caffe модуля DNN. Он хорошо работает с окклюзией, быстрыми движениями головы, а также может определять боковые лица. Более того, он также показал самый быстрый fps среди всех.

Все коды и файлы можно найти здесь, в моем репозитории на Github. Эта цель заключалась в том, чтобы найти модель обнаружения лиц, наиболее подходящую для обнаружения лиц в сценарии онлайн-контроля. Если вам интересно узнать об этом больше, вы можете прочитать эту статью.