Mastering OpenCV with Practical Computer Vision Projects / Опановуюємо OpenCV через практичні проекти комп'ютерного зору: Розділ 8. Розпізнавання обличчя за методами Eigenfaces та Fisherfaces

← →
Английский оригинал Перевод на украинский

Сожалеем, но текст оригинала доступен только зарегистрированным пользователям.

Ми входимо в режим збирання даних, коли користувач натискає кнопку "Додати особу", щоб просигналізувати бажання почати збирання облич для нової людини. Як зазначено раніше, ми обмежили кількість знімків до одного в секунду, причому їхній вигляд має суттєво відрізнятися від попереднього. І пам'ятайте, ми бажаємо збирати не лише попередньо оброблені обличчя, а також їх віддзеркалення.

Atronax 22.03.21 в 15:38

0

У режимі збирання даних ми також бажаємо показати останнє обличчя кожної відомої особи та дозволити користувачу натискати на одну з наявних осіб чи доєднати більше примірників облич або взагалі натиснути кнопку "Додати людину" і розширити колекцію зображенням нової особи. Користувач має здійснити клік в межах вікна, щоб перейти в наступний режим, тренування.

Atronax 22.03.21 в 15:38

0

Спершу маємо зберегти посилання на останнє зібране обличчя для кожної особи. Це здійснюємо шляхом оновлення масиву цілих чисел m_latestFaces, який зберігає лише індекси для людини, з великого масиву preprocessedFaces (тобто колекції всіх облич всіх людей). Оскільки ми також зберігаємо віддзеркалене зображення, маємо посилатися на другий з кінця елемент, а не на останній. Тому потрібно додати відповідний код до фрагменту, що додає нове обличчя (та його віддзеркалений варіант) до масиву preprocessedFaces таким чином:

Atronax 22.03.21 в 15:39

0

Збережемо посилання на останнє обличчя кожної людини.
m_latestFaces[m_selectedPerson] = preprocessedFaces.size() - 2;
Варто лише пам'ятати про необхідність завжди збільшувати чи зменшувати масив m_latestFaces, коли додаються чи видаляються нові зображення облич (наприклад, у результаті натискання кнопки "Додати особу"). Виведемо останні зображення для кожної наявної людини у правому боці вікна (у режимах збирання даних та розпізнавання) так:

Atronax 22.03.21 в 15:39

0

m_gui_faces_left = displayedFrame.cols - BORDER - faceWidth;
m_gui_faces_top = BORDER;
for (int i=0; i<m_numPersons; i++) {
int index = m_latestFaces[i];
if (index >= 0 && index < (int)preprocessedFaces.size()) {
Mat srcGray = preprocessedFaces[index];
if (srcGray.data) {
// Збираємо обличчя BGR, оскільки результат також має цей формат.
Mat srcBGR = Mat(srcGray.size(), CV_8UC3);
cvtColor(srcGray, srcBGR, CV_GRAY2BGR);
// Отримуємо вихідний регіон інтересу.
int y = min(m_gui_faces_top + i * faceHeight,
displayedFrame.rows - faceHeight);
Rect dstRC = Rect(m_gui_faces_left, y, faceWidth,
faceHeight);
Mat dstROI = displayedFrame(dstRC);
// Копіюємо пікселі з вихідної матриці в цільову.
srcBGR.copyTo(dstROI);
}
}
}

Atronax 22.03.21 в 15:39

0

Ми також бажаємо виділити поточну особу, для якої збираємо фотографії, за допомгою товстої червоної границі навколо обличчя.
Це робиться таким чином:
if (m_mode == MODE_COLLECT_FACES) {
if (m_selectedPerson >= 0 &&
m_selectedPerson < m_numPersons) {
int y = min(m_gui_faces_top + m_selectedPerson *
faceHeight, displayedFrame.rows –
faceHeight);
Rect rc = Rect(m_gui_faces_left, y, faceWidth,
faceHeight);
rectangle(displayedFrame, rc, CV_RGB(255,0,0), 3,
CV_AA);
}
}

Atronax 22.03.21 в 15:40

0

Наступний частковий скріншот показує типовий результат виводу, коли зібрані обличчя для декількох людей. Користувач може натиснути на будь-яку з осіб у верхній правій частині, щоб зібрати більше даних для неї.

Atronax 22.03.21 в 15:40

0

Режим тренування

Atronax 22.03.21 в 15:40

0

Коли користувач нарешті натискає кнопку миші у вікні, алгоритм розпізнавання здійснить процедуру тренування на основі зібраних облич. При цьому варто впевнитися, що зібрано достатню кількість даних, інакше програма матиме збій у роботі. В загальному випадку, потрібне як мінімум одне обличчя в тренувальному наборі (наяна принаймні одна особа). Але алгоритм Fisherfaces, наприклад, порівнює між собою декількох людей, без відповідних даних збоєм завершиться й він. Тому ми мусимо перевірити, чи обрано цей метод для розпізнавання облич. Якщо це так, потрібні зображення як мінімум двох людей з обличчями, інакше лише однієї. За недостатності даних програма повернеться у режим збирання, щоб користувач міг додати більше облич для тренування.

Atronax 22.03.21 в 15:40

0

Щоб перевірити наявність як мінімум двох людей із зібраними обличчями, коли користувач натискає на кнопку "Додати особу", новий об'єкт додається лише тоді, коли немає іншого незаповненого (тобто особу додано, але зібраних облич для неї немає). Ми також можемо впевнитися, що якщо наявні лише дві людини і ми використовуємо алгоритм Fisherfaces, потрібно встановити посилання m_latestFaces на останню людину в режимі збирання даних. m_latestFaces[i] отримує значення -1, якщо зображень облич для неї ще не маємо, та 0 чи вище, якщо обличчя для цієї людини додано. Це робиться таким чином:

Atronax 22.03.21 в 15:40

0

// Перевіряємо, чи достатньо даних для тренування.
bool haveEnoughData = true;
if (!strcmp(facerecAlgorithm, "FaceRecognizer.Fisherfaces")) {
if ((m_numPersons < 2) ||
(m_numPersons == 2 && m_latestFaces[1] < 0) ) {
cout << "Для алгоритму Fisherfaces потрібно не менше двох осіб!" << endl;
haveEnoughData = false;
}
}
if (m_numPersons < 1 || preprocessedFaces.size() <= 0 ||
preprocessedFaces.size() != faceLabels.size()) {
cout << "Перед початком тренування треба зібрати дані!" << endl;
haveEnoughData = false;
}
if (haveEnoughData) {
// Вивчаємо зібрані обличчя за допомогою методів Eigenfaces та Fisherfaces.
model = learnCollectedFaces(preprocessedFaces, faceLabels,
facerecAlgorithm);
// Завершивши процес тренування, можемо почати розпізнавання!
m_mode = MODE_RECOGNITION;
}
else {
// Недостатньо тренувальних даних, повернемося до режиму збирання!
m_mode = MODE_COLLECT_FACES;
}

Atronax 22.03.21 в 15:41

0

Тренування може зайняти долі секунди, декілька секунд чи навіть хвилин, залежно від кількості зібраних даних. Коли процедура завершиться, система автоматично увійде в режим розпізнавання.

Atronax 22.03.21 в 15:41

0

Режим розпізнавання

Atronax 22.03.21 в 15:41

0

У цьому режимі поряд з попередьно обробленим обличчя показана метрика впевненості, аби користувач міг упевнитися, наскільки надійним є розпізнавання. Якщо значення більше за певний поріг, навколо людини намалюється зелений прямокутник. Користувач може доєднати нові обличчя для подальшого тренування, натиснувши кнопку "Додати особу" або обравши одну з наявних, що змусить програму повернутися на етап збирання даних.

Atronax 22.03.21 в 15:42

0

Ми вже здобули розпізнані показники ідентичності та схожості з відновленим обличчям як зазначено раніше. Щоб вивести метрику впевненості на екрані, значення схожості вкажемо в межах від 0 до 0.5 для високого рівня та від 0.5 до 1.0 - для низького, у такому разі зможемо відняти її від одиниці, щоб отримати відповідне значення впевненості від 0.0 до 1.0. Потім просто намалюємо заповнений прямокутник на основі отриманого відношення:

Atronax 22.03.21 в 15:42

0

int cx = (displayedFrame.cols - faceWidth) / 2;
Point ptBottomRight = Point(cx - 5, BORDER + faceHeight);
Point ptTopLeft = Point(cx - 15, BORDER);
// Намалюємо сіру лінію, що показує поріг для "невідомої" людини.
Point ptThreshold = Point(ptTopLeft.x, ptBottomRight.y -
(1.0 - UNKNOWN_PERSON_THRESHOLD) * faceHeight);
rectangle(displayedFrame, ptThreshold, Point(ptBottomRight.x,
ptThreshold.y), CV_RGB(200,200,200), 1, CV_AA);
// Обмежимо рівень впевненості у проміжок від 0 до 1, щоб вмістити результат.
double confidenceRatio = 1.0 - min(max(similarity, 0.0), 1.0);
Point ptConfidence = Point(ptTopLeft.x, ptBottomRight.y -
confidenceRatio * faceHeight);

Atronax 22.03.21 в 15:43

0

// Зобразимо яскраво-блакитний прямокутник впевненості.
rectangle(displayedFrame, ptConfidence, ptBottomRight,
CV_RGB(0,255,255), CV_FILLED, CV_AA);
// Виведемо сірі границі прямокутника.
rectangle(displayedFrame, ptTopLeft, ptBottomRight,
CV_RGB(200,200,200), 1, CV_AA);
Щоб виділити розпізнану особу, намалюємо зелений прямокутник навколо обличчя:
if (identity >= 0 && identity < 1000) {
int y = min(m_gui_faces_top + identity * faceHeight,
displayedFrame.rows - faceHeight);
Rect rc = Rect(m_gui_faces_left, y, faceWidth, faceHeight);
rectangle(displayedFrame, rc, CV_RGB(0,255,0), 3, CV_AA);
}

Atronax 22.03.21 в 15:43

0

Далі проілюстровано типові результати виводу у режимі розпізнавання, що показують значення впевненості поряд з попередньо обробленим обличчям у верхній центральній частині та виділяє розпізнану людину у верхньому правому куті.

Atronax 22.03.21 в 15:43

0

Перевірка та обробка натискання кнопок миші

Atronax 22.03.21 в 15:44

0

Маючи всі потрібні елементи графічного інтерфейсу, перейдемо до обробки подій миші. Налаштувавши вікно, ми повідомили бібліотеці OpenCV про функцію зворотнього виклику onMouse(). Нас не хвилює рух миші, лише кліки, тому пропустимо події, які не стосуються лівої кнопки миші:

Atronax 22.03.21 в 15:44

0

void onMouse(int event, int x, int y, int, void*)
{
if (event != CV_EVENT_LBUTTONDOWN)
return;
Point pt = Point(x,y);
... (handle mouse clicks) ...
}

Atronax 22.03.21 в 15:44

0

Оскільки ми вже маємо прямокутні межі кнопок, потрібно лише перевірити, чи знаходиться позиція курсора у будь-якому відповідному регіоні за допомогою функції inside() бібліотеки OpenCV. Процедуру можна здійснити для усіх створених кнопок.

Atronax 22.03.21 в 15:44

0

Коли користувач натискає кнопку "Додати особу", ми додаємо одиницю до змінної m_numPersons, виділяємо простір у змінній m_latestFaces, обираємо нову людину для процедури та переходимо в режим збирання даних (не важливо, у якому були раніше).

Atronax 22.03.21 в 15:44

0

Але існує одна складність; щоб впевнитися, що ми маємо як мінімум одне обличчя для кожної особи на етапі тренування, виділимо простір для нової лише тоді, коли немає інших осіб без зображень. У такому разі ми матимемо можливість перевірити значення змінної m_latestFaces [m_numPersons-1] та побачити, чи додані обличчя для кожної особи. Здійснимо це так:

Atronax 22.03.21 в 15:44

0

if (pt.inside(m_btnAddPerson)) {
// Впевнимося, що не існує інших осіб без зібраних даних.
if ((m_numPersons==0) ||
(m_latestFaces[m_numPersons-1] >= 0)) {
// Додаємо нову особу.
m_numPersons++;
m_latestFaces.push_back(-1);
}
m_selectedPerson = m_numPersons - 1;
m_mode = MODE_COLLECT_FACES;
}

Atronax 22.03.21 в 15:44

0

Цей метод можна використати для тестування інших кнопок, наприклад за допомогою флагу налаштування:
else if (pt.inside(m_btnDebug)) {
m_debug = !m_debug;
}

Atronax 22.03.21 в 15:45

0

Щоб виконати обробку кнопки "Видалити все", потрібно звільнити різні структури даних, розміщені локально у головному циклі (недоступному функції зворотнього виклику для подій миші), тому перейдемо в режим видалення, щоб мати таку можливість. Ми також маємо обробити події натискання мишею в межах вікна (не кнопок). Якщо користувач вибере одне з облич праворуч, маємо обрати особу та перейти в режим збирання даних. А якщо він натисне у вікні у цьому режимі, потрібно перейти у стан тренування. Це можна зробити так:

Atronax 22.03.21 в 15:45

0

else {
// Перевіряємо, чи користувач натиснув на обличчя списку.
int clickedPerson = -1;
for (int i=0; i<m_numPersons; i++) {
if (m_gui_faces_top >= 0) {
Rect rcFace = Rect(m_gui_faces_left,
m_gui_faces_top + i * faceHeight,
faceWidth, faceHeight);
if (pt.inside(rcFace)) {
clickedPerson = i;
break;
}
}
}
// Виділяємо іншу людину, якщо користувач натиснув на її обличчя.
if (clickedPerson >= 0) {
// Змінюємо поточну особу та збираємо фотографії.
m_selectedPerson = clickedPerson;
m_mode = MODE_COLLECT_FACES;
}
// Інакше користувач здійснив клік в центрі вікна.
else {
// Переходимо у стан тренування з режиму збирання даних.
if (m_mode == MODE_COLLECT_FACES) {
m_mode = MODE_TRAINING;
}
}
}

Atronax 22.03.21 в 15:45

0

Висновки

Atronax 22.03.21 в 15:45

0

У цьому розділі показано всі кроки, потрібні для створення застосунків розпізнавання облич, що діють у режимі реального часу, з достатньою попередньою обробкою, що дозволяє певні відмінності між умовами тренувального та тестувального наборів, за допомогою простих алгоритмів. Для знаходження позиції обличчя на кадрі камери ми скористалися процедурою пошуку, декількома видами попередньої обробки для зменшення ефектів різних умов освітлення, орієнтації камери та обличчя, виразів. Потім натренували системи машинного навчання алгоритмів Eigenfaces та Fisherfaces на основі зібраних даних та здійснили розпізнавання обличчя, аби вказати, ким є особа, на основі процедури верифікації, яка надає метрику впевненості у випадках, якщо та невідома.

Atronax 22.03.21 в 15:46

0

Замість створення інструменту командної стрічки, який обробляє файли зображень в режимі офлайн, ми об'єднали попередні кроки у цілісний графічний інтерфейс, який дозволяє негайно використовувати систему розпізнавання обличчя. Ви повинні мати можливість модифікувати поведінку системи заради власних цілей, наприклад дозволити автоматичний вхід до комп'ютера, або підвищити надійність розпізнавання на основі нещодавніх досліджень, щоб потенційно покращити кожен крок програми, поки вона не підходитиме специфічним потребам. Наприклад, можна вдосконалити попередню обробку облич, або застосувати кращий алгоритм машинного навчання чи верифікації обличчя за методами, що описані на ресурсах http://www.face-rec.org/algorithms/ та http://www.cvpapers.com

Atronax 22.03.21 в 15:46

0

Посилання

Atronax 22.03.21 в 15:46

0

Rapid Object Detection using a Boosted Cascade of Simple Features, P. Viola and M.J. Jones,
Proceedings of the IEEE Transactions on CVPR 2001, Vol. 1, pp. 511-518
An Extended Set of Haar-like Features for Rapid Object Detection, R. Lienhart and J. Maydt,
Proceedings of the IEEE Transactions on ICIP 2002, Vol. 1, pp. 900-903
Face Description with Local Binary Patterns: Application to Face Recognition, T. Ahonen, A.
Hadid and M. Pietikainen, Proceedings of the IEEE Transactions on PAMI 2006, Vol. 28,
Issue 12, pp. 2037-2041
Learning OpenCV: Computer Vision with the OpenCV Library, G. Bradski and A. Kaehler,
pp. 186-190, O'Reilly Media.

Atronax 22.03.21 в 15:46

0

Eigenfaces for recognition, M. Turk and A. Pentland, Journal of Cognitive Neuroscience 3, pp.
71-86
Eigenfaces vs. Fisherfaces: Recognition using class specific linear projection, P.N. Belhumeur,
J. Hespanha and D. Kriegman, Proceedings of the IEEE Transactions on PAMI 1997, Vol. 19,
Issue 7, pp. 711–720
Face Recognition with Local Binary Patterns, T. Ahonen, A. Hadid and M. Pietikainen,
Computer Vision - ECCV 2004, pp. 469–48

Atronax 22.03.21 в 15:46

0
Минутку...

← Предыдущая страница