Обнаружение лиц в Python с OpenCV

Введение Обнаружение лиц - мощный и распространенный вариант использования машинного обучения. Его можно использовать для автоматизации ручных задач, таких как посещение школы и правоохранительные органы. С другой стороны, его можно использовать для биометрической авторизации. В этой статье мы выполним обнаружение лиц в Python, используя OpenCV. OpenCV OpenCV - одна из самых популярных библиотек компьютерного зрения. Он был написан на C и C ++, а также обеспечивает поддержку Python, помимо Java и MATLAB. Пока не самый быстрый ли

Вступление

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

В этой статье мы выполним обнаружение лиц в Python, используя OpenCV.

OpenCV

OpenCV - одна из самых популярных библиотек компьютерного зрения. Он был написан на C и C ++, а также обеспечивает поддержку Python, помимо Java и MATLAB. Хотя это не самая быстрая библиотека, с ней легко работать, и она предоставляет высокоуровневый интерфейс, позволяющий разработчикам писать стабильный код.

Давайте установим OpenCV, чтобы мы могли использовать его в нашем коде Python:

 $ pip install opencv-contrib-python 

В качестве альтернативы вы можете установить opencv-python только для основных модулей OpenCV. opencv-contrib-python содержит основные модули, а также модули contrib, которые обеспечивают расширенную функциональность.

Обнаружение лиц на изображении с помощью OpenCV

Установив OpenCV, мы можем импортировать его как cv2 в наш код.

Чтобы прочитать изображение, мы будем использовать imread() вместе с путем к изображению, которое мы хотим обработать. Функция imread() просто загружает изображение из указанного файла в ndarray . Если изображение не может быть прочитано, например, в случае отсутствия файла или неподдерживаемого формата, функция вернет None .

Мы будем использовать изображение из набора данных Kaggle :

 import cv2 
 
 path_to_image = 'Parade_12.jpg' 
 original_image = cv2.imread(path_to_image) 

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

Примечание: в случае цветных изображений декодированные изображения будут иметь каналы, сохраненные в порядке BGR, поэтому при изменении их на оттенки серого нам нужно использовать флаг cv2.COLOR_BGR2GRAY

 image = cv2.cvtColor(original_image, cv2.COLOR_BGR2GRAY) 

Это можно было сделать напрямую при использовании imread() , установив флаг cv2.IMREAD_GRAYSCALE

 original_image = cv2.imread(path_to_image, cv2.IMREAD_GRAYSCALE) 

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

Функции Haar для обнаружения этих объектов хранятся в виде XML и, в зависимости от того, как вы установили OpenCV, чаще всего могут быть найдены в Lib\site-packages\cv2\data . Их также можно найти в репозитории OpenCVÂ GitHub .

Чтобы получить к ним доступ из кода, вы можете использовать cv2.data.haarcascades и добавить имя XML-файла, который вы хотите использовать.

Мы можем выбрать, какие функции Haar мы хотим использовать для обнаружения объектов, добавив путь к CascadeClassifier() , который использует предварительно обученные модели для обнаружения объектов:

 face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_frontalface_default.xml") 

Теперь мы можем использовать этот face_cascade для обнаружения лиц на изображении:

 detected_faces = face_cascade.detectMultiScale(image=image, scaleFactor=1.3, minNeighbors=4) 

Когда модели обнаружения объектов обучаются, они обучаются обнаруживать лица определенного размера и могут пропускать лица, которые больше или меньше, чем они ожидают. Имея это в виду, размер изображения несколько раз изменяется в надежде, что лицо в конечном итоге станет "обнаруживаемым" размером. scaleFactor позволяет OpenCV знать, насколько масштабировать изображения. В нашем случае 1.3 означает, что его можно уменьшить на 30% , чтобы попытаться лучше сопоставить лица.

Что касается minNeighbors , он используется для контроля количества ложных срабатываний и ложных отрицаний. Он определяет минимальное количество положительных прямоугольников (определение черт лица), которые должны быть рядом с положительным прямоугольником, чтобы он считался действительно положительным. Если minNeighbors установлено в 0 , малейший намек на лицо будет считаться окончательным, даже если рядом с ним не обнаружены другие черты лица.

Оба параметра scaleFactor и minNeighbors в некоторой степени произвольны и устанавливаются экспериментально. Мы выбрали значения, которые хорошо работали для нас и не давали ложных срабатываний, за счет большего количества ложноотрицательных результатов (необнаруженных лиц).

Метод detectMultiScale() возвращает список прямоугольников всех обнаруженных объектов (в нашем первом случае лица). Каждый элемент в списке представляет собой уникальное лицо. Этот список содержит кортежи (x, y, w, h) , где значения x, y представляют верхние левые координаты прямоугольника, а значения w, h представляют ширину и высоту прямоугольника соответственно.

Мы можем использовать возвращенный список прямоугольников и использовать cv2.rectangle() чтобы легко рисовать прямоугольники, в которых было обнаружено лицо. Имейте в виду, что предоставленный цвет должен быть кортежем в порядке RGB:

 for (x, y, width, height) in detected_faces: 
 cv2.rectangle( 
 image, 
 (x, y), 
 (x + width, y + height), 
 color, 
 thickness=2 
 ) 

А теперь давайте соберем все это вместе:

 import cv2 
 
 def draw_found_faces(detected, image, color: tuple): 
 for (x, y, width, height) in detected: 
 cv2.rectangle( 
 image, 
 (x, y), 
 (x + width, y + height), 
 color, 
 thickness=2 
 ) 
 
 path_to_image = 'Parade_12.jpg' 
 original_image = cv2.imread(path_to_image) 
 
 if original_image is not None: 
 # Convert image to grayscale 
 image = cv2.cvtColor(original_image, cv2.COLOR_BGR2GRAY) 
 
 # Create Cascade Classifiers 
 face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_frontalface_default.xml") 
 profile_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_profileface.xml") 
 
 # Detect faces using the classifiers 
 detected_faces = face_cascade.detectMultiScale(image=image, scaleFactor=1.3, minNeighbors=4) 
 detected_profiles = profile_cascade.detectMultiScale(image=image, scaleFactor=1.3, minNeighbors=4) 
 
 # Filter out profiles 
 profiles_not_faces = [x for x in detected_profiles if x not in detected_faces] 
 
 # Draw rectangles around faces on the original, colored image 
 draw_found_faces(detected_faces, original_image, (0, 255, 0)) # RGB - green 
 draw_found_faces(detected_profiles, original_image, (0, 0, 255)) # RGB - red 
 
 # Open a window to display the results 
 cv2.imshow(f'Detected Faces in {path_to_image}', original_image) 
 # The window will close as soon as any key is pressed (not a mouse click) 
 cv2.waitKey(0) 
 cv2.destroyAllWindows() 
 else: 
 print(f'En error occurred while trying to load {path_to_image}') 

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

Лица, обнаруженные с frontalface зеленым, а лица, обнаруженные с profileface красным. Большинство лиц, найденных первой моделью, также были бы найдены второй, поэтому мы нарисовали только красные прямоугольники там, где profileface лица обнаружила лицо, а frontalface нет:

 profiles_not_faces = [x for x in detected_profiles if x not in detected_faces] 

Метод imshow() просто показывает переданное изображение в окне с заданным заголовком. С выбранным нами изображением это даст следующий результат:

фронтальное и профильное распознаваниелиц{.ezlazyload}

Использование разных значений для scaleFactor и minNeighbors даст разные результаты. Например, использование scaleFactor = 1.1 и minNeighbors = 4 дает нам больше ложных срабатываний и истинных срабатываний с обеими моделями:

нижний масштабный коэффициент распознаваниялиц{.ezlazyload}

Мы видим, что алгоритм не идеален, но очень эффективен. Это особенно заметно при работе с данными в реальном времени, такими как видеопоток с веб-камеры.

Обнаружение лица в реальном времени с помощью веб-камеры

Видеопотоки - это просто потоки изображений. Благодаря эффективности алгоритма Виолы-Джонса мы можем обнаруживать лица в режиме реального времени.

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

Для получения видеопотока воспользуемся классом cv2.VideoCapture Конструктор этого класса принимает целочисленный параметр, представляющий видеопоток. На большинстве машин к веб-камере можно получить доступ, передав 0 , но на машинах с несколькими видеопотоками вам может потребоваться попробовать другие значения.

Далее нам нужно прочитать отдельные изображения из входного потока. Это делается с помощью функции read() , которая возвращает retval и image . image - это просто полученный кадр. retval используется для определения того, был ли получен кадр, и будет иметь значение False если это не так.

Однако, как правило, это несовместимо с потоками видеовхода (например, не определяет, что веб-камера была отключена), поэтому мы будем игнорировать это значение.

Давайте продолжим и изменим предыдущий код для обработки видеопотока:

 import cv2 
 
 def draw_found_faces(detected, image, color: tuple): 
 for (x, y, width, height) in detected: 
 cv2.rectangle( 
 image, 
 (x, y), 
 (x + width, y + height), 
 color, 
 thickness=2 
 ) 
 
 # Capturing the Video Stream 
 video_capture = cv2.VideoCapture(0) 
 
 # Creating the cascade objects 
 face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_frontalface_default.xml") 
 eye_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_eye_tree_eyeglasses.xml") 
 
 while True: 
 # Get individual frame 
 _, frame = video_capture.read() 
 # Covert the frame to grayscale 
 grayscale_image = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) 
 
 # Detect all the faces in that frame 
 detected_faces = face_cascade.detectMultiScale(image=grayscale_image, scaleFactor=1.3, minNeighbors=4) 
 detected_eyes = eye_cascade.detectMultiScale(image=grayscale_image, scaleFactor=1.3, minNeighbors=4) 
 draw_found_faces(detected_faces, frame, (0, 0, 255)) 
 draw_found_faces(detected_eyes, frame, (0, 255, 0)) 
 
 # Display the updated frame as a video stream 
 cv2.imshow('Webcam Face Detection', frame) 
 
 # Press the ESC key to exit the loop 
 # 27 is the code for the ESC key 
 if cv2.waitKey(1) == 27: 
 break 
 
 # Releasing the webcam resource 
 video_capture.release() 
 
 # Destroy the window that was showing the video stream 
 cv2.destroyAllWindows() 

Заключение

В этой статье мы создали приложение для распознавания лиц с использованием Python и OpenCV.

Библиотека OpenCV очень проста в использовании для базовых программ обнаружения объектов. Экспериментальная настройка параметров scaleFactor и minNeighbors для типов изображений, которые вы хотите обработать, может дать довольно точные результаты и очень эффективно.

comments powered by Disqus