
Вывод за десять секунд: используйте Python и OpenCV для создания приложения, которое автоматически делает селфи при обнаружении улыбки. А теперь перейдем к делу. :)
Я наткнулся на эту рекламу Oppo - телефон автоматически делает селфи, когда красивая актриса улыбается в камеру. Это казалось довольно простой задачей, учитывая замечательную библиотеку dlib от Python.
В этом посте я расскажу о том, как создать подобное приложение, которое снимает селфи с веб-камеры при обнаружении улыбки. Всего ~ 50 строк кода.
Обзор процесса
- Используйте детектор лицевых ориентиров в dlib, чтобы получить координаты рта
- Установите порог улыбки, используя соотношение сторон рта (MAR)
- Доступ к веб-камере для настройки прямой трансляции
- Захватить изображение
- Сохраните изображение
- Закройте подачу кулачка
Требуются библиотеки
- Numpy: используется для быстрых матричных вычислений и манипуляций.
- dlib: библиотека, содержащая лицевые ориентиры.
- Cv2: библиотека Open CV, используемая для обработки и сохранения изображений.
- Scipy.spatial: используется для расчета евклидова расстояния между точками лица.
- Imutils: библиотека для доступа к видеопотоку.
Все библиотеки можно установить с помощью pip, кроме dlib. Для dlib необходимо установить CMake и boost. Вот как их установить на macOS с помощью brew.
Если у вас нет brew, вот как установить Homebrew.
Установить CMake
brew install cmake
Установить ускорение
brew install boost brew install boost-python --with-python3
Вторая команда гарантирует, что boost можно использовать с Python 3.
Установить dlib
После этого мы можем установить dlib, используя
pip install dlib
Совет. Мне нравится использовать Anaconda, виртуальную среду для каждого отдельного проекта. Вот отличный блог о том, почему и как работает среда conda.
Импорт библиотек
from scipy.spatial import distance as dist from imutils.video import VideoStream, FPS from imutils import face_utils import imutils import numpy as np import time import dlib import cv2
Детектор лицевых ориентиров
Детектор лицевых ориентиров - это API, реализованный внутри dlib . Он создает 68 x-y-координат, которые соответствуют определенным структурам лица.
Это можно представить как:

Мы сосредоточимся на рте, к которому можно получить доступ через точечный диапазон [49,…, 68]. Есть двадцать координат.
Используя dlib, мы можем получить эти функции, используя следующий код:
shape_predictor= “../shape_predictor_68_face_landmarks.dat” detector = dlib.get_frontal_face_detector() predictor = dlib.shape_predictor(shape_predictor) (mStart, mEnd) = face_utils.FACIAL_LANDMARKS_IDXS[“mouth”]
(mStart, mEnd) дает нам первую и последнюю координаты рта.
Вы можете скачать заранее подготовленный файл ориентира здесь или просто напишите мне, и я пришлю его вам. Не забудьте извлечь его.
Функция улыбки
На изображении ниже показаны только двадцать координат рта:

Я создал соотношение сторон рта (MAR), вдохновленное двумя статьями об обнаружении моргания. Это Обнаружение моргания глаз в реальном времени с использованием ориентиров . и Обнаружение моргания глаз с помощью OpenCV, Python и dlib. Вторая статья расширяет первую. Оба обсуждают соотношение сторон, в данном случае для глаз (EAR):

Формула EAR:
D = расстояние между p1 и p4
L = среднее расстояние между p2 и p6; p3 и p5

EAR= L/D
В нашем случае MAR определяется просто как соотношение точек, показанных ниже.

Мы вычисляем расстояние между p49 и p55 как D и усредняем расстояния между:
p51 и p59
p52 и p58
p53 и p57
Назовем его L, используя ту же структуру именования:

MAR = L/D
Вот функция для расчета MAR.
def smile(mouth): A = dist.euclidean(mouth[3], mouth[9]) B = dist.euclidean(mouth[2], mouth[10]) C = dist.euclidean(mouth[4], mouth[8]) L = (A+B+C)/3 D = dist.euclidean(mouth[0], mouth[6]) mar=L/D return mar
Совет: когда мы объединяем массив, точка 49 становится первым элементом массива (0), и все остальные индексы корректируются соответствующим образом:
Улыбка с закрытым ртом увеличивает расстояние между точками p49 и p55 и уменьшает расстояние между верхней и нижней точками. Таким образом, L будет уменьшаться, а D увеличиваться.
Улыбка с открытым ртом приводит к уменьшению D и увеличению L.
Посмотрите, как меняется MAR, когда я меняю форму рта:

Исходя из этого, я установил для улыбки значение MAR, равное ‹0,3 или› 0,38. Я мог бы взять только D, так как D всегда увеличивается, когда человек улыбается. Но D не будет одинаковым для всех, поскольку у людей разные формы рта.
Это грубые оценки и могут включать другие эмоции, такие как «трепет». Чтобы преодолеть это, вы можете создать более продвинутую модель. Вы можете принять во внимание больше черт лица или просто обучить классификатор эмоций на основе резюме.
Теперь, когда у нас есть функция улыбки, мы можем реализовать захват видео.
Захват видео
Доступ к веб-камере
Мы можем получить доступ к веб-камере через библиотеку imutils, используя следующую команду. cv2.namedWindow создает новое окно:
vs = VideoStream(src=0).start()
fileStream = False
time.sleep(1.0)
cv2.namedWindow('frame',cv2.WINDOW_NORMAL)
Распознавание лиц
Теперь мы подошли к основному циклу, в котором происходит волшебство. Сначала мы захватываем один кадр и конвертируем его в оттенки серого для упрощения вычислений. Мы используем это для обнаружения лица. cv2.convexHull(mouth) определяет контур рта и cv2.drawContours обводит его зеленым контуром.
while True: frame = vs.read() frame = imutils.resize(frame, width=450) gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) rects = detector(gray, 0) for rect in rects: shape = predictor(gray, rect) shape = face_utils.shape_to_np(shape) mouth= shape[mStart:mEnd] mar= smile(mouth) mouthHull = cv2.convexHull(mouth) cv2.drawContours(frame, [mouthHull], -1, (0, 255, 0), 1)
Совет: эта настройка позволяет обнаруживать несколько улыбок в одном кадре.
Автозахват
Далее мы устанавливаем условие автоматического захвата:
if mar <= .3 or mar > .38 :
COUNTER += 1
else:
if COUNTER >= 15:
TOTAL += 1
frame = vs.read()
time.sleep(0.3)
img_name = “opencv_frame_{}.png”.format(TOTAL)
cv2.imwrite(img_name, frame)
print(“{} written!”.format(img_name))
cv2.destroyWindow(“test”)
COUNTER = 0
Здесь я считаю улыбку «достойной селфи», если человек держит ее полсекунды или 30 кадров.
Мы проверяем, равен ли MAR ‹.3 или› .38 хотя бы для 15 кадров, а затем сохраняем 16-й кадр. Файл сохраняется в той же папке, что и код, с именем «opencv_frame_ ‹counter› .png».
Я добавил несколько time.sleep функций, чтобы упростить работу. Телефоны обычно решают эти проблемы с оборудованием с помощью таких приемов, как анимация или загрузочные экраны.
Совет. Эта часть находится внутри цикла while.
Также печатаем MAR на фрейме функцией cv2.putText:
cv2.putText(frame, “MAR: {}”.format(mar), (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)
Совет. У моего Mac камера со скоростью 30 кадров в секунду, поэтому я использовал 30 в качестве количества кадров. Вы можете изменить это соответствующим образом. Более простой способ найти fps - использовать функцию fps в imutils.
Выйти из потокового видео
Наконец, введите команду выхода, которая останавливает потоковое видео при нажатии клавиши «q». Это достигается добавлением:
key2 = cv2.waitKey(1) & 0xFF if key2 == ord(‘q’): break
Наконец, мы уничтожаем окно, используя
cv2.destroyAllWindows() vs.stop()
и мы закончили!
Весь код в действии:

Вы можете найти весь код на моем GitHub.
Это было базовое приложение замечательной библиотеки dlib. Отсюда вы можете создавать такие вещи, как ваши собственные фильтры для снэпчата, высокотехнологичные системы домашнего наблюдения или даже детектор пост-оруэлловского счастья.
Напиши мне в Твиттере на случай, если ты будешь делать с этим еще что-нибудь интересное или найдешь лучший детектор улыбки. Еще одна интересная идея - сделать некоторую пост-обработку захваченного изображения (как в рекламе), чтобы сделать изображение красивее.
Спасибо за прочтение. Если вам понравилось то, что вы читаете, хлопайте в ладоши и подписывайтесь на меня. Это будет много значить и побудит меня писать больше. Давайте также подключимся к Twitter и Linkedin :)