Распознавание лиц на основе OpenCV для C++

Автор: | 31.10.2018

Введение
Захват видеопотока с камеры и выделение лица
Выделение особых точек лица (Facial Landmark Detection)
Выбор признаков для фильтрации изображений и распознавания лиц
Алгоритм распознавания лиц по 2D-каркасу точек 
3D-реконструкция наиболее характерных точек лица (раздел темы на стадии разработки)
Полезные ссылки

Введение

Как может работать базовый процесс распознавания лиц:

  1. Обнаружение лица на изображении
  2. Выделение особенностей на лице
  3. Преобразования для сравнения с лицами в базе данных
  4. Заключение (определение соответствия между лицами)

Основная идея в том, что выделяются специфические точки (метки) лица и по их взаимному расположению осуществляется сравнение лиц.

Для сравнения лиц можно использовать точечный 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\…

Выделение особых точек лица

Приложение создано на основе 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 с добавлением новых модулей и установил ее в  корень диска 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.

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

Определяем признак для сравнения лиц:

Пока признак только один — расстояние между точками 27 и 8 (см. рисунок во Введении). Признак определяется в ПСК разницей  Y1 — Y2 .

А вот и первый результат:

Программа распознает и по фото, на котором я на 15 лет моложе, да и при том, еще с усами. Различие на фото существенное, не каждый человек уловит. Но компьютерную программу не обманешь.

 

3D-реконструкция наиболее характерных точек лица

Прежде всего точки лица необходимо соотнести с удобной для выделения признаков пользовательской системе координат (ПСК):

Ось X — прямая, которая соединяет центры глаз (также как и в ПСК для распознавания лиц по 2D-каркасу точек).  Точка 31  (см. рисунок во Введении) вместе с осью X определяет положение плоскости XY. Ось Y  — это прямая, которая лежит в плоскости XY, перпендикулярна оси X и проходит через точку, которая находится посредине между глаз. Ось Z — это прямая, перпендикулярная плоскости XY.

Теперь ставится задача математически описать  3-D реконструкцию точек каркаса лица по 2-м изображениям. Решение подобных задач описано в темах  Алгоритм 3D-реконструкции под Android device, а также 3D реконструкция по одному изображению. Все эти задачи базируются на механизме аффинных преобразований,  изложенных в теме Геометрические преобразования в графических приложениях.

Сначала перейдем от оконной СК (ОСК) к  логической системе координат (ЛСК).

Плоскость XY ЛСК совпадает с плоскостью XY ОСК. Центр ЛСК совпадает с средней точкой между глазами, которая определяется по координатам угловых точек левого и правого глаз

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;

Направление оси X совпадает с направлением оси X в ОСК, направление оси Y противоположно направлению оси Y в ОСК, ось Z направлена от окна.

X = X_Window — X0;

Y = — (Y_Window — Y0 );

Нормализацию пока не проводим, поскольку натуральная величина параметра (расстояние между глазами), относительно которого будет проводится нормализация, определяется после 3D-реконструкции.

На рисунке выше показано положение ЛСК, которое соответствует виду лица в анфас. Определим положение лица относительно камеры. Для этого перейдем от СК XYZ к  СК xyz последовательным вращением СК xyz вокруг осей Z, X и Y  на углы alpha, bета  и gamma.

В матричном представлении эти преобразования совместно с преобразованием ортогонального проецирования могут быть представлены в виде:

Значения углов углов alpha, bета  и gamma положительное при вращении против часовой стрелки — если смотреть сверху оси вращения

В итоге, уравнения преобразования точек пространственного объекта в  точки текущего изображения запишутся в виде:

В этих уравнениях:

  • X,Y — координаты точки лица на изображении, они заданы (определяются в OpenCV приложении через массив landmarks).
  • alpha, bета, gamma — углы, которые определяют положение СК xyz относительно СК XYZ (см. рисунок выше). Их значение пока еще неизвестно.
  • x,y,z — координаты точки лица в ПСК, их то и нужно определить для решения задачи 3D-реконструкции каркаса точек лица.

Итак, что мы имеем? Систему из 2-х уравнений с 6-ю неизвестными: x,y,z, alpha, bета, gamma.

Для решения системы не хватает 4-х уравнений. Дополнительные зависимости можно получить, используя метод, описанный в теме 3D реконструкция по одному изображению. Суть метода заключается в том, что коэффициенты матрицы преобразований могут быть определены графически через искажения единичных отрезков на осях:

L — размер для нормализации, определяется расстоянием от внешней угловой  точки правого (Right)  глаза из выражения:

L = sqrt (xR ** 2 + yR **2 + zR **2)

Координаты точки правого  глаза подставляем в уравнениях для пересчета из СК xyz в СК XYZ, а также в уравнения для определения величин dxx и dyx.

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

Все равно  не хватает 2-х зависимостей. Для того, чтобы их получить можно использовать еще 2 изображения. При этом, для каждого изображения вместе с 4-я уравнениями с 3-я новыми переменными — углы вращения относительно осей координат (координаты точек в ПСК остаются теми же). Т.е., 2-е и 3-е изображения добавляют по одной лишней зависимости (4-3=1). В итоге получаем 12 уравнений с 12 неизвестными.

Возможно альтернативное решение задачи. Предположим, что точка 31  (см. рисунок во Введении) лежит на оси y. Практически так оно и есть, поскольку эта точка вместе с осью x определяют плоскость xy, к тому же она находится на линии симметрии лица, как и ось y. Тогда можно записать еще 2 уравнения (дополнительно к 4-м) для одного и того же изображения.

Вместе с 2-я уравнениями добавилась переменная Ly — натуральная величина расстояния от начала координат до точки 31. При таком варианте решения задачи получаем 6 уравнений и 7 неизвестных. Т.е., по одному изображению выполнить 3D реконструкцию не удается.  Необходимы зависимости еще, по крайней мере для одного изображения.

Итак, можно восстановить положение головы в пространстве (углы alpha, bета, gamma) по 2-м или 3-м изображениям. При этом реализуется 3D- реконструкция 2-х наиболее характерных точек лица, которые находятся на осях x и y в ПСК. Но решения задачи по 3D- реконструкции всех точек лица пока нет. Для общего случая точек есть только 2 уравнения X= f 1(x,y,z) и  Y= f2 (x,y,z) с 3-я неизвестными — x, y и z.

 

 

 

 

 

раздел темы на стадии разработки

 

 

Полезные ссылки

 

Автор: Николай Свирневский

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *