Введение
Захват видеопотока с камеры и выделение лица
Выделение особых точек лица (Facial Landmark Detection)
Выбор признаков для фильтрации изображений и распознавания лиц
Алгоритм распознавания лиц по 2D-каркасу точек
Программа сравнения лиц по одному признаку
3D- реконструкция ASM (Active Shape Models)
Идентификация по множеству признаков. Основы
Идентификация по множеству признаков при помощи нейросети
Машинное обучение распознавать поворот лица
Полезные ссылки
Введение
Как может работать базовый процесс распознавания лиц:
- Обнаружение лица на изображении
- Выделение особенностей на лице
- Преобразования для сравнения с лицами в базе данных
- Заключение (определение соответствия между лицами)
Для обнаружения лиц, как правило, используется метод Виолы-Джонса.
Для идентификации лиц можно использовать модель ASM (Active Shape Models). Основная идея заключается в учете статистических связей между расположением антропометрических точек лица. На каждом изображении лица точки пронумерованы в одинаковом порядке. По их взаимному расположению осуществляется сравнение лиц.
Для сравнения лиц можно использовать точечный 2D-каркас одного и того же положения лица относительно камеры. Более предпочтителен для этого точечный 3D-каркас.
Захват видеопотока с камеры и выделение лица
На основе фрагментов программ получил приложение, которое, обеспечивает захват видеопотока с камеры и выделение лица (используя Haar-Cascade классификатор).
#include <opencv2/opencv.hpp> using namespace cv; int main() { // Load Face cascade (.xml file) CascadeClassifier face_cascade; face_cascade.load("haarcascade_frontalface_alt2.xml"); Mat img; VideoCapture cap(0); while (true) { cap >> img; //cvtColor(img, img, CV_BGR2GRAY); // Detect faces std::vector<Rect> faces; face_cascade.detectMultiScale(img, faces, 1.1, 2, 0 | CV_HAAR_SCALE_IMAGE, Size(30, 30)); // Draw circles on the detected faces for (int i = 0; i < faces.size(); i++) { Point center(faces[i].x + faces[i].width*0.5, faces[i].y + faces[i].height*0.5); ellipse(img, center, Size(faces[i].width*0.5, faces[i].height*0.5), 0, 0, 360, Scalar(255, 0, 255), 4, 8, 0); } imshow("Detected Face", img); waitKey(1); } return 0; }
Файлы каскадов находятся в директории c:\opencv\build\etc\… Нужный каскад размещаете в директории проекта, там же, где и исходный файл main.cpp.
Выделение особых точек лица
Приложение создано на основе C++ code for OpenCV Facemark
#include <iostream> #include <conio.h> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/objdetect/objdetect.hpp> #include <opencv2/face.hpp> #include "drawLandmarks.hpp" using namespace std; using namespace cv; using namespace cv::face; int main(int argc, char** argv) { // Load Face Detector CascadeClassifier faceDetector("haarcascade_frontalface_alt2.xml"); // Create an instance of Facemark Ptr<Facemark> facemark = FacemarkLBF::create(); // Load landmark detector facemark->loadModel("lbfmodel.yaml"); // Set up webcam for video capture VideoCapture cam(0); // Variable to store a video frame and its grayscale Mat frame, gray; // Read a frame while (cam.read(frame)) { // Find face vector<Rect> faces; // Convert frame to grayscale because // faceDetector requires grayscale image. cvtColor(frame, gray, COLOR_BGR2GRAY); // Detect faces faceDetector.detectMultiScale(gray, faces); // Variable for landmarks. // Landmarks for one face is a vector of points // There can be more than one face in the image. Hence, we // use a vector of vector of points. vector< vector<Point2f> > landmarks; // Run landmark detector bool success = facemark->fit(frame, faces, landmarks); if (success) { // If successful, render the landmarks on the face for (size_t i = 0; i < faces.size(); i++) { cv::rectangle(frame, faces[i], Scalar(0, 255, 0), 3); } for (int i = 0; i < landmarks.size(); i++) { drawLandmarks(frame, landmarks[i]); /*for (size_t j = 0; j < landmarks[i].size(); j++) circle(frame, Point(landmarks[i][j].x, landmarks[i][j].y), 1, Scalar(255, 0, 0), 2);*/ } } // Display results imshow("Facial Landmark Detection", frame); // Exit loop if ESC is pressed if (waitKey(1) == 27) break; } return 0; }
В проекте приложения, там же где и файл main.cpp, разместил файлы haarcascade_frontalface_alt2.xml, drawLandmarks.hpp и lbfmodel.yaml , на которые есть ссылки в коде. Файлы каскадов находятся в директории c:\opencv\build\etc\… Файлы drawLandmarks.hpp и lbfmodel.yaml есть в архиве Facemark_LBF.rar.
После вставки кода появились ошибки из-за того, что в OpenCV 3.4.3-vc14-vc15 отсутствуют ряд библиотек, необходимых для запуска приложения. Скомпоновал свою библиотеку OpenCV с добавлением новых модулей (скачать opencv_new.zip) и установил ее в корень диска C (C:\opencv-new).
Теперь, все настройки, которые выполнялись при инстилляции OpenCV 3.4.3-vc14-vc15, необходимо выполнить и для opencv-new:
Выполняю настройки в Windows. Выхожу на окно «Изменить переменную среды» (кнопки Windows->Служебные->Панель управления -> Система и безопасность -> Система -> Дополнительные параметры системы -> Переменные среды -> Path ->Изменить). В этом окне создаю переменную C:\opencv-new\x64\vc14\bin. Перезагружаю Windows.
В свойствах проекта также ссылаюсь на библиотеку opencv_new (вместо opencv). В окне «Property Pages» выполняю действия:
- C/C++ -> General -> Additional Include Directories -> C:\opencv-new\include
- Linker -> General -> Additional Library Directories -> C:\opencv-new\x64\vc14\lib
- Linker -> Input -> Additional Dependencies -> opencv_core400.lib; opencv_face400.lib; opencv_videoio400.lib; opencv_objdetect400.lib; opencv_imgproc400.lib; opencv_highgui400.lib
При запуске программа выдает ошибку, если в установках проекта Debug. Для Release, запуск успешный.
Выбор признаков для фильтрации изображений и распознавания лиц
Точечный каркас лица отображается по разному в зависимости от объективных и субъективных факторов.
Объективные факторы — положение лица относительно камеры.
Субъективные факторы — неравномерное или слабое освещение, искажение лица вследствие эмоций, прищуривание глаз и т.п. В этих случаях точечный каркас может быть некорректным, точки могут даже быть оторваны от лица:
При видеозахвате иногда проскакивают и такие изображения. Их нужно отфильтровывать — как при обучении так и распознавании.
Некоторые из точек есть наиболее стабильными и информативными. Они жестко привязаны к лицу, независимо от его положения относительно камеры. Кроме того, они хорошо характеризуют специфику лица. Эти точки могут быть использованы как основа для моделирования системы признаков.
Для сравнения лиц можно использовать точечный 2D каркас одного и того же положения лица. Какое положение лица относительно камеры есть наиболее информативным? Очевидно, что фронтальное. Не зря в криминалистике делают фото в анфас и профиль. Пока ограничимся анфасом.
Все признаки (расстояния) должны быть безразмерные (нормализованые), т.е., соотнесены к какому-то размеру(расстоянию). Предполагаю, что наиболее подходящий для этого размер — расстояние между серединами угловых точек глаз. А почему, например, не внешними угловыми точками глаз, которые реально определены в массиве landmarks? Дело в том, что угловые точки глаз раздвигаются (сближаются) при реагировании на изменение цвета, выражении удивления, моргании и т.п. Расстояние между серединами глаз нивелирует эти колебания и поэтому более предпочтительно.
Какой признак возьмем за основу в первом приближении? Предполагаю, расстояние от верхней точки переносицы к нижней точки подбородка. Судя по фото этот признак может существенно отличаться для различных лиц.
Итак, прежде чем формировать признаки для обучения и сравнения, необходимо отфильтровать полученные видеозахватом точечные каркасы лиц, которые по субъективным или объективным причинам не есть правильное фронтальное изображение лица (анфас).
Оставляем только те точечные каркасы, которые проходят по следующим признакам:
- Прямая, которая проходит через крайние точки глаз (линия глаз), перпендикулярна прямой, которая проходит через крайние точки носа (линия носа).
- Линия глаз параллельна прямой, которая проходит через точки уголков рта (линия рта).
- Соблюдается симметрия указанных выше точек относительно линии носа.
- Угловые точки глаз (внешние и внутренние) находятся на одной прямой.
Пример фронтальных изображений, которые проходят по всем признакам:
Пример изображений, которые отфильтровываются:
Попробуйте сами определить, по какому из признаков изображения не проходят.
Как формализуются признаки, которые обеспечивают фильтрацию и распознавание лиц? В основном они построены на условиях определении расстояний между точками, условий параллельности и перпендикулярности. Задача формализации таких признаков рассмотрена в теме Алгоритмы распознавания фигур.
Алгоритм распознавания лиц по 2D-каркасу точек
Координаты точек каркаса лица изначально задаются в системе координат, которая привязана к верхней левой точке окна. При этом ось Y направлена вниз.
Для удобства определения признаков используем пользовательскую систему координат (ПСК), ось X которой проходит через отрезок между серединами глаз, а ось Y — перпендикулярно этому отрезку через его середину в направлении вверх. Координаты ПСК (от -1 до +1) нормализованы — соотнесены с расстоянием между средними точками глаз.
ПСК обеспечивает удобство и простоту определения признаков. Например, положение лица в анфас определяется признаком симметрии соответствующих точек глаз относительно линии носа. Этот признак формализуется совпадением линии носа с осью Y, т.е X1=X2=0, где X1 и X2 — координаты крайних точек носа (27 и 30) в ПСК.
Определяем относительно оконной СК
Координаты средних точек левого и правого глаз (Left и Right):
XL = (X45 + X42) /2 ; YL = (Y45 + Y42) /2 ; XR = (X39 + X 36) /2; YR = (Y39 + Y 36) /2;
Начало ПСК:
X0 =( XL + XR)/2; Y0 =( YL + YR)/2;
Расстояния между средними точками глаз вдоль осей Х и Y:
DX = XR — XL; DY = YR — YL;
Действительное расстояние L между средними точками глаз (по теореме Пифагора):
L = sqrt ( DX** 2 + DY**2)
Тригонометрические функции угла поворота ПСК:
sin_AL = DY/L
cos_AL = DX/L
Переходим от координат в оконной СК к координатам в ПСК, используя параметры X0,Y0, L, sin AL, cos AL:
X_User_0 = 2 (X_Window — X0 ) / L;
Y_User_0 = — 2 (Y_Window — Y0 ) / L ;
X_User = X_User_0 * cos_AL — Y_User_0 * sin_AL;
Y_User = X_User_0 * sin_AL + Y_User_0 * cos_AL;
Реализуем фильтрацию изображений последовательно проверяя признаки:
1.Признак перпендикулярности линий носа и глаз, а также симметрии угловых точек глаз. Линия носа определяется точками 27 и 30 (см. рисунок во Введении). Оба признака выполняются, если в ПСК координаты этих точек X1 = X2= 0 (т.е., линия носа совпадает с осью Y).
2.Признак параллельности линии глаз и линии рта. Линия рта определяется точками 48 и 54 (см. рисунок во Введении). Признак выполняется, если в ПСК Y1-Y2=0.
3. Признак симметрии угловых точек рта. Линия рта определяется точками 48 и 54 (см. рисунок во Введении). Признак выполняется, если в ПСК X1+X2 =0
4. Признак «Угловые точки глаз находятся на одной прямой». Прямые определяются парами точек: (36 и 45), а также (39 и 42). Поскольку тест по признаку 1 уже пройден, достаточно лишь определить в ПСК признак Y2-Y1 =0 лишь для точек 36 и 39.
Абсолютного равенства нулю быть не может, поэтому признаки сравниваются с допустимо маленькой величиной.
Программа сравнения лиц по одному признаку
В качестве признака берется расстояние между точками переносицы и подбородка (Landmarks точками 27 и 8, см. рисунок во Введении). Признак, нормализован, определяется в ПСК отношением: (Y1 — Y2)/L , где L — расстояние между центрами глаз. При обучении программы признак для конкретного лица определяется числом, которое высвечивается рядом с отслеживаемым лицом (эта часть кода в программе закомментирована). При распознавании значение признака сравнивается с введенным в программу конкретным признаком для каждого лица. При положительном результате сравнения рядом с лицом появляется его идентификатор.
Программа распознает и по фото, на котором я на 15 лет моложе, да и при том, еще с усами. Различие на фото существенное, не каждый человек уловит. Но компьютерную программу не обманешь.
Контрольные задания:
- Ознакомиться с программой.
- Определить значение признака для своего лица и нескольких своих коллег.
- Протестировать программу на предмет идентификации лиц (своего и коллег).
#include <iostream> #include <conio.h> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/objdetect/objdetect.hpp> #include <opencv2/face.hpp> #include "drawLandmarks.hpp" using namespace std; using namespace cv; using namespace cv::face; int main(int argc, char** argv) { // Load Face Detector CascadeClassifier faceDetector("haarcascade_frontalface_alt2.xml"); // Create an instance of Facemark Ptr<Facemark> facemark = FacemarkLBF::create(); // Load landmark detector facemark->loadModel("lbfmodel.yaml"); // Set up webcam for video capture VideoCapture cam(0); // Variable to store a video frame and its grayscale Mat frame, gray; // Read a frame while (cam.read(frame)) { // Find face vector<Rect> faces; // Convert frame to grayscale because // faceDetector requires grayscale image. cvtColor(frame, gray, COLOR_BGR2GRAY); // Detect faces faceDetector.detectMultiScale(gray, faces); // Variable for landmarks. // Landmarks for one face is a vector of points // There can be more than one face in the image. Hence, we // use a vector of vector of points. vector< vector<Point2f> > landmarks; // Run landmark detector bool success = facemark->fit(frame, faces, landmarks); if (success) { // If successful, render the landmarks on the face for (size_t i = 0; i < faces.size(); i++) { cv::rectangle(frame, faces[i], Scalar(0, 255, 0), 3); } for (int i = 0; i < landmarks.size(); i++) { //if((i >=30)&&(i <= 35)) drawLandmarks(frame, landmarks[i]); for (size_t j = 0; j < landmarks[i].size(); j++) { circle(frame, Point(landmarks[i][j].x, landmarks[i][j].y), 1, Scalar(255, 0, 0), 2); } line(frame, Point(landmarks[i][27].x, landmarks[i][27].y), Point(landmarks[i][8].x, landmarks[i][8].y), Scalar(0, 0, 255), 2); float XL = (landmarks[i][45].x + landmarks[i][42].x) / 2; float YL = (landmarks[i][45].y + landmarks[i][42].y) / 2; float XR = (landmarks[i][39].x + landmarks[i][36].x) / 2; float YR = (landmarks[i][39].y + landmarks[i][36].y) / 2; line(frame, Point(XL, YL), Point(XR, YR), Scalar(0, 0, 255), 2); float DX = XR - XL; float DY = YR - YL; float L = sqrt(DX * DX + DY * DY); float X1 = (landmarks[i][27].x); float Y1 = (landmarks[i][27].y); float X2 = (landmarks[i][8].x); float Y2 = (landmarks[i][8].y); float DX1 = abs(X1 - X2); float DY1 = abs(Y1 - Y2); float L1 = sqrt(DX1 * DX1 + DY1 * DY1); float X0 = (XL + XR) / 2; float Y0 = (YL + YR) / 2; float sin_AL = DY / L; float cos_AL = DX / L; float X_User_0 = (landmarks[i][27].x - X0) / L; float Y_User_0 = -(landmarks[i][27].y - Y0) / L; float X_User27 = X_User_0 * cos_AL - Y_User_0 * sin_AL; float Y_User27 = X_User_0 * sin_AL + Y_User_0 * cos_AL; X_User_0 = (landmarks[i][30].x - X0) / L; Y_User_0 = -(landmarks[i][30].y - Y0) / L; float X_User30 = X_User_0 * cos_AL - Y_User_0 * sin_AL; float Y_User30 = X_User_0 * sin_AL + Y_User_0 * cos_AL; if (abs(X_User27 - X_User30) <= 0.1) { //putText(frame, std::to_string(abs(L1 / L)), Point(landmarks[i][27].x, landmarks[i][27].y), 1, 2, Scalar(0, 0, 255), 2); if (abs((L1 / L) - 1.6) < 0.1) { putText(frame, "Roman", Point(landmarks[i][27].x, landmarks[i][27].y), 1, 2, Scalar(0, 0, 255), 2); } if (abs((L1 / L) - 1.9) < 0.1) { putText(frame, "Pasha", Point(landmarks[i][27].x, landmarks[i][27].y), 1, 2, Scalar(0, 0, 255), 2); } if (abs((L1 / L) - 2.1) < 0.1) { putText(frame, "Svirnesvkiy", Point(landmarks[i][27].x, landmarks[i][27].y), 1, 2, Scalar(0, 0, 255), 2); } } putText(frame, "Incorrect", Point(landmarks[i][27].x, landmarks[i][27].y), 1, 2, Scalar(0, 0, 255), 2); } } // Display results imshow("Facial Landmark Detection", frame); // Exit loop if ESC is pressed if (waitKey(1) == 27) break; } return 0; }
- 3D- реконструкция ASM (Active Shape Models)
- Идентификация по множеству признаков. Основы
- Идентификация по множеству признаков при помощи нейросети
- Система машинного обучения распознавания лиц с веб-камеры
Полезные ссылки
- Human Face detection and Recognition-Theoretical approach
- Look at Boundary: A Boundary-Aware Face Alignment Algorithm
- Face detection with Haar cascade and pedestrian detection with HOG+SVM
- Выделение объектов на изображении по методу Виолы-Джонса
- The technology behind Face Filters
- Face Detection Explained: State-of-the-Art Methods and Best Tools
- Как работает РАСПОЗНАВАНИЕ ЛИЦ? | РАЗБОР
- Face Recognition for Beginners
- Face Recognition with OpenCV
- Технология распознавания лиц
- Туториалы по работе с Face SDK
- Система машинного обучения распознавания лица с веб-камеры
- Современное распознавание лиц с глубинным обучением
- Исследование алгоритмов распознавания лиц
- Анализ существующих подходов к распознаванию лиц
- 3D Face Reconstruction from a Single Image
- Large Pose 3D Face Reconstruction from a Single Image via Direct Volumetric CNN Regression
- C++ дайджест #13: OpenCV
- Идентификация лиц по видеофиксации в реальном времени
- Распознавание лиц: как это работает и что с ним будет дальше?
- Современные биометрические методы идентификации
- Facial Key Point Detection
- ИССЛЕДОВАНИЕ АЛГОРИТМОВ РАСПОЗНАВАНИЯ ОБРАЗОВ НА ОСНОВЕ ГЕОМЕТРИИ ТОЧЕК И СКРЫТЫХ МАРКОВСКИХ МОДЕЛЕЙ
- Исследование рынка систем распознавания эмоций
- Cutting-Edge Face Recognition is Complicated. These Spreadsheets Make it Easier.
- Facial recognition system
- FaceNet — пример простой системы распознавания лиц с открытым кодом Github
- Anatomically-Aware Facial Animation from a Single Image