OpenCV, Машинное зрение на Python: Поиск лица на фото. Часть 4

Вот мы с вами и подошли к самому интересному. К поиску лица\лиц на фото или в видеопотоке. Для поиска мы будем использовать Каскад Хаара.

Каскад Хаара — способ обнаружения объектов на изображении, основанный на машинном обучении, идея которого была была предложена в статье за авторством Пола Виолы (Paul Viola) и Майкла Джонса (Michael Jones). Обученный каскад Хаара, принимая на вход изображение, определяет, есть ли на нем искомый объект, т.е. выполняет задачу классификации, разделяя входные данные на два класса (есть искомый объект, нет искомого объекта) . Собственно сам алгоритм работы сводиться к тому что есть Признак Хаара (набором прямоугольных областей) которые проходят по изображению и находят искомый объект. Я не очень силен в объяснение теория, кому интересны подробности ищем в интернете.

Что нам важно знать : все это уже есть в библиотеке OpenCV. И натренированные признаки и функции реализации алгоритма. По этому сразу код, потом будут пояснения :

import cv2

faceCascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FPS, 24) # Чистота кадров

while True:
    ret, img = cap.read()
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    faces = faceCascade.detectMultiScale(
        gray,               #
        scaleFactor=1.2,    #
        minNeighbors=5,     #
        minSize=(20, 20)    #
    )

    for (x, y, w, h) in faces:
        cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
    cv2.imshow("camera", img)
    if cv2.waitKey(10) == 27:  # Esc key
        break
cap.release()
cv2.destroyAllWindows()

faceCascade = cv2.CascadeClassifier(‘haarcascade_frontalface_default.xml’) .

Собственно этой командой мы загружаем уже обученные классификаторы haarcascade_frontalface_default.xml . Взять их можно с нашего сайта или Github OpenCV.

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

Переводим изображение в серый цвет, алгоритм лучше работает с черно-белым изображением.

faces = faceCascade.detectMultiScale(
gray, #
scaleFactor=1.2, #
minNeighbors=5, #
minSize=(20, 20) #
)

Это функция поиска лиц.

  • scaleFactor=1.2 — Параметр, указывающий, на сколько уменьшается размер изображения при каждом масштабе изображения. Он используется для создания масштабной пирамиды.
  • minNeighbors=5 — Параметр, указывающий, сколько соседей должен иметь каждый прямоугольник-кандидат для его сохранения. (чем выше , тем больше точность).
  • minSize=(20, 20) — Минимально возможный размер объекта. Объекты меньшего размера игнорируются.

for (x, y, w, h) in faces:
cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)

Рисуем прямоугольники во круг найденого лица.

Конечно бывают ложные срабатывания или наоборот не видет лицо алгоритм. Можно попробовать другие классификаторы, поиграться с параметрами. Все очень сильно зависит от освещения и т.д. Для более точного распознавания прибегают к разнообразным методам нормализации изображения.

Например нормализовать среднеквадратическое отклонение. Это необходимо для того, чтобы разница в освещенности на фотографиях оказывала минимум влияния на результат классификации.

Давайте добавим поиск глаз :

import cv2

faceCascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
# Загружаем каскады для глаз.
eyeCascade = cv2.CascadeClassifier('haarcascade_eye.xml')

img = cv2.imread('semia.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

faces = faceCascade.detectMultiScale(
        gray,               #
        scaleFactor=1.2,    # Находим лица на фото
        minNeighbors=4,     #
        minSize=(20, 20)    #
    )

for (x, y, w, h) in faces:
    roi_gray = gray[y:y + h, x:x + w] # Вырезаем область с лицами
    roi_color = img[y:y + h, x:x + w]
    cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
    eyes = eyeCascade.detectMultiScale(
        roi_gray,              #
        scaleFactor=1.2,       # Ищем глаза в области с лицом
        minNeighbors=4,
        minSize=(5, 5),
    )
    for (ex, ey, ew, eh) in eyes:
        cv2.rectangle(roi_color, (ex, ey), (ex + ew, ey + eh), (0, 255, 0), 2)  # Рисуем область глаз

cv2.imshow("camera", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

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