Mastering OpenCV with Practical Computer Vision Projects / Опановуюємо OpenCV через практичні проекти комп'ютерного зору: Розділ 8. Розпізнавання обличчя за методами Eigenfaces та Fisherfaces
| Английский оригинал | Перевод на украинский | |
|---|---|---|
Сожалеем, но текст оригинала доступен только зарегистрированным пользователям. |
Збільшений малюнок показує приклад результату виконання усіх етапів попередньої обробки обличчя. Ця процедура більш стійка до зміни яскравості, повороту, напрямку камери, фону, позицій світла і так далі. Попередньо оброблене обличчя використаємо як вхідні дані для подальших етапів, збору облич для тренування та власне розпізнавання: Atronax 22.03.21 в 15:03 |
|
|
Етап 3: Збір облич та тренування Atronax 22.03.21 в 15:04 |
||
|
Збирати обличчя настільки ж просто, як і розміщувати кожне новооброблене обличчя в масив попередньо опрацьованих кадрів камери, а також зберігати відмітку в масиві (щоб мати можливість визначати, кому саме належить обличчя). Наприклад, можна використати 10 заздалегідь оброблених облич першої особи та 10 другої, щоб вхідні дані алгоритму розпізнавання обличчя включали масив 20 попередньо опрацьованих облич та масив 20 цілих чисел (серед яких перші десять - нулі, а наступні - одиниці). Atronax 22.03.21 в 15:04 |
||
|
Далі алгоритм розпізнавання навчатиметься розрізняти обличчя різних людей. Цей етап називають тренуванням, а зібрані дані - тренувальним набором. Після його завершення, можна зберегти здобуті знання у пам'яті або файлі для пізнішого використання, щоб упізнати, хто саме зображений на знімку. Цей етап називають тестуванням. Якщо вхідні дані подано напряму з камери, то заздалегідь оброблене обличчя називатимемо тестовим зображенням, а якщо тестування відбувається за допомогою багатьох кадрів (наприклад, цілої теки), такі дані називатимемо тестовим набором. Atronax 22.03.21 в 15:04 |
||
|
Важливо забезпечити якісний тренувальний набір, який покриє всі типи очікуваних змін у тестовому наборі. Наприклад, якщо тестуватимемо лише обличчя осіб, погляд яких спрямований чітко на камеру (фотографії паспортів), знадобляться тренувальні зображення саме таких облич. Але якщо особа дивиться вліво чи вгору, набір має включати і такі кадри, інакше алгоритм розпізнавання обличчя навряд чи поверне результати, оскільки у цьому випадку вони матимуть дещо інший вигляд. Atronax 22.03.21 в 15:04 |
||
|
Це також стосується інших факторів, наприклад виразу обличчя (якщо людина завжди посміхається на кадрах тренувального набору, але не посміхається на тестових зображеннях) чи напряму освітлення (сильне світло з лівого боку на тренувальних фрагментах і з правого боку на тестових), у такому разі алгоритму складніше здійснити розпізнавання. Розглянутий раніше етап попередньої обробки зображення зменшить подібні проблеми, але навряд чи анулює вплив цих факторів, особливо в напрямі погляду, оскільки він має значний вплив на розміщення усіх елементів обличчя. Atronax 22.03.21 в 15:04 |
||
|
Примітка Atronax 22.03.21 в 15:04 |
||
|
Щоб отримати якісний тренувальний набір, що покриє різні реальні умови для кожної особи, можна скористатися знімками обличчя з поглядом, чітко спрямованим вліво, вверх, вправо та вниз. Потім людина нахиляє голову в боки, вгору та вниз, а також дещо змінює вираз обличчя, наприклад посміхається, виглядає розлюченою чи спокійною. Якщо кожна особа здійснить таку ж процедуру під час збору даних, вірогідність розпізнати усіх в реальних умовах значно підвищиться. Atronax 22.03.21 в 15:05 |
||
|
Для навіть кращих результатів процес варто здійснити ще для одного чи двох положень чи напрямків, наприклад здійснивши поворот камери на 180 градусів та повторивши процедуру зі зворотнього боку камери, щоб тренувальний набір включав знімки з різними умовами освітлення. Atronax 22.03.21 в 15:05 |
||
|
У загальному випадку, 100 тренувальних знімків облич для кожної людини дасть кращі результати, аніж 10, але якщо всі 100 облич виглядають практично однаковими, результат все ще буде поганим, адже більш важливим є те, щоб тренувальний набір мав достатню варіативність, щоб мати змогу покрити потрібні тестові умови, а не просто велику кількість різних облич. Щоб впевнитися, що не всі обличчя у тренувальному наборі схожі, маємо додати помітну затримку між кожним знімком. Наприклад, якщо камера діє зі швидкість 30 кадрів у секунду, вона здатна зібрати 100 облич за декілька секунд, а людина не матиме можливості повернутися за цей час, тому краще зберігати лише один знімок в секунду, даючи особі час для руху. Ще одним простим методом покращити варіативність тренувального набору - збирати обличчя, які не схожі на попередні. Atronax 22.03.21 в 15:05 |
||
|
Збираємо попередньо оброблені обличчя для тренування Atronax 22.03.21 в 15:05 |
||
|
Щоб впевнитися, що між знімками нових облич існує проміжок принаймні в одну секунду, потрібно вимірювати час. Це робиться таким чином: Atronax 22.03.21 в 15:05 |
||
|
Щоб порівняти попіксельну подібність двох кадрів, можна обчислити відносну похибку L2, тобто відняти одне зображення від іншого, просумувати квадрати значень та знайти корінь квадратний від отриманого результату. Якщо людина не здійснила жодних рухів, результат віднімання поточного та попереднього облич має досить низькі значення в кожному пікселі, яле якщо відбувся рух у будь-якому напряму, результат віднімає сформує досить великі числа, тобто похибка L2 буде високою. Оскільки результат сумується по всім пікселям, значення сильно залежить від роздільної здатності зображення. Тому, щоб знайти середню похибку, поділимо це значення на загальну кількість пікселів зображення. Для цього скористаємось зручною функцією getSimilarity(): Atronax 22.03.21 в 15:06 |
||
|
double getSimilarity(const Mat A, const Mat B) { Atronax 22.03.21 в 15:06 |
||
|
Значення схожості становитиме менше 0.2, якщо зображення не дуже змістилося, та вище 0.4, якщо відбувся значний рух, тому скористуємось значенням 0.3 в якості порогу для збору нового обличчя. Існує багато трюків, які можна застосувати для того, щоб отримати більше тренувальних даних, наприклад віддзеркалення, випадковий шум, зміщення обличчя на декілька пікселів, масштабування на певний відсоток чи поворот на декілька градусів (навіть якщо ми намагалися видалити ці ефекти на етапі попередньої обробки). Додамо віддзеркалені обличчя до тренувального набору, щоб збільшити розміри і знизити похибки асиметричних облич чи постійної орієнтації користувача в лівий чи правий бік під час тренування, але не тестування. Це можна зробити таким чином: Atronax 22.03.21 в 15:06 |
||
|
// Оброблювати обличчя, якщо ті помітно відрізняються Atronax 22.03.21 в 15:07 |
||
|
Цей фрагмент коду наповнить вектори preprocessedFaces та faceLabels попередньо обробленими обличчями, а також відмітками чи номером паспорта цієї особи (припускаючи, що він зберігається у змінній m_selectedPerson). Atronax 22.03.21 в 15:07 |
||
|
Щоб оповістити користувача про те, що його обличчя додано до колекції, достатньо вивести великий білий прямокутник на поверхні зображення або просто показати кадр на долі секунди. Завдяки С++ інтерфейсу бібліотеки OpenCV можна скористатися перевантаженим оператором + об'єкта cv::Mat, щоб додати значення кожного пікселя до зображення та обмежити його на рівні 255 (за допомогою функції saturate_cost, щоб білий колір не перетворився в чорний!). Припустимо, що displayedFrame є копією кольорового кадру камери та додамо такий фрагмент коду до процедури збору облич: Atronax 22.03.21 в 15:07 |
||
|
// Отримаємо доступ до регіону інтересу обличчя. Atronax 22.03.21 в 15:08 |
||
|
Тренування системи розпізнавання на основі колекції облич Atronax 22.03.21 в 15:08 |
||
|
Отримавши достатню колекцію облич кожної особи, потрібно натренувати систему за допомогою алгоритму машинного навчання, що підходить для розпізнавання. В літературі описано багато різних алгоритмів, найпростішими серед яких є методи Eigenfaces та штучні нейромережі. Перший спосіб працює краще і, не зважаючи на простоту, діє настільки ж добре, як і більш складні алгоритми розпізнавання обличчя, тому його часто використовують як фундамент для початківців та побудови нових процедур. Atronax 22.03.21 в 15:08 |
||
|
Якщо ви бажаєте й надалі вивчати питання розпізнавання обличчя, перегляньте теоретичні відомості, що стосуються таких тем: Atronax 22.03.21 в 15:08 |
||
|
Більш нові алгоритми з нещодавно викладених у публічний доступ дослідницьних праць (CVPR чи ICCV в http://www.cvpapers.com/), оскільки кожного року публікуються сотні подібних статей. Atronax 22.03.21 в 15:08 |
||
|
Але вам не обов'язково знати теоретичні викладки алгоритмів, щоб користуватися ними для поставлених у книзі завдань. Дякуючи команді OpenCV та вкладу Філіпа Вагнера в libfacerec, версія 2.4.1 постачає простий та загальний метод cv::Algorithm для здійснення розпізнавання обличчя за допомогою одного з декількох різних алгоритмів (які навіть можна обирати в режимі реального часу) без розуміння деталей їх реалізації. Щоб переглянути доступні алгоритми для вашої версії бібліотеки OpenCV, досить викликати функцію Algorithm::getList() Atronax 22.03.21 в 15:08 |
||
|
vector<string> algorithms; Atronax 22.03.21 в 15:09 |
||
|
У бібліотеці OpenCV v2.4.1 доступні три алгоритми: Atronax 22.03.21 в 15:09 |
||
|
Примітка Atronax 22.03.21 в 15:09 |
||
|
Ці алгоритми розпізнавання обличчя доступні в класі FaceRecognizer модуля contrib бібліотеки OpenCV. Зважаючи на динамічне лінкування, можлива ситуація, за якої програму поєднано з модулем, але він не завантажений (якщо відповідний файл не знайдено). Тому рекомендовано викликати функцію cv::initModule_contrib() до спроб отримати доступ до алгоритмів FaceRecognizer. Така функція доступна в бібліотеці OpenCV, починаючи з версії 2.4.1, вона дозволяє впевнитися, що алгоритми розпізнавання доступні на етапі компіляції. Atronax 22.03.21 в 15:09 |
||
|
// Завантажимо модуль contrib динамічно Atronax 22.03.21 в 15:09 |
||
|
Щоб скористатися одним з алгоритмів розпізнавання обличчя, потрібно створити об'єкт FaceRecognizer за допомогою функції cv::Algorithm::create<FaceRecognizer>(). В якості параметра передаємо назву бажаного алгоритму у вигляді стрічки. Це дасть змогу застосовувати його, якщо він доступний у нашій версії. Також можна використати цей факт для перевірки, має користувач бібліотеку OpenCV v2.4.1 і вище чи ні. Наприклад: Atronax 22.03.21 в 15:10 |
||
|
string facerecAlgorithm = "FaceRecognizer.Fisherfaces"; Atronax 22.03.21 в 15:10 |
||
|
Завантаживши алгоритм FaceRecognizer, можна просто викликати функцію FaceRecognizer::train() із зібраними даними таким чином: Atronax 22.03.21 в 15:11 |
||
|
Ця стрічка коду розпочинає процес тренування обраного алгоритму (наприклад, Eigenfaces, Fisherfaces або будь-який інший). Якщо є лише декілька людей і менше за 20 облич, тренування займе незначний проміжок часу, але для багатьох людей з великою кількістю знімків, для обробки даних може знадобитися декілька секунд чи навіть хвилин. Atronax 22.03.21 в 15:11 |
||
|
Огляд отриманих знань Atronax 22.03.21 в 15:11 |
||
|
Хоч це й не обов'язково, згенеровані алгоритмом розпізнавання обличчя внутрішні структури даних корисно переглядати, особливо якщо ви розумієте теорію та бажаєте перевірити коректність результати чи знайти причини похибок. Внутрішні структури даних можуть відрізнятися від алгоритму до алгоритму, але, на щастя, вони однакові для Eigenfaces та Fisherfaces, тому розглянемо саме їх. Обидві представлені у вигляду одновимірних матриць власних векторів, схожих на обличчя, якщо переглядати їх як двовимірні зображення, тому для алгоритму Eigenfaces їх ще називають власними обличчями, а для Fisherfaces - обличчями Фішера. Atronax 22.03.21 в 15:11 |
||
|
Простими словами, суть методу Eigenfaces полягає в пошуку набору особливих зображень (власних облич) та відношень змішування (власних значень), які можна комбінувати різними способами для створення зображень тренувального набору та формування відмінностей. Наприклад, якщо деякі обличчя мають вуса, а деякі ні, матимемо як мінімум одне власне обличчя з вусами, тому такі тренувальні зображення матимуть високі показники змішування з власним вектором, а кадри без вус - низькі. Atronax 22.03.21 в 15:12 |
||
|
Якщо набір сформовано для 5 осіб з 20-ма фрагментами облич для кожної, для розпізнавання 100 облич знадобляться 100 власних облич та 100 власних значень, причому вони відсортовані таким чином, щоб декілька перших елементів вказували на найбільш значимі відмінності, а останні - всього лише випадкові шуми, які ніяк не допомагають розрізнити дані. Прийнято відкидати останні власні обличчя і залишати приблизно 50 елементів. Atronax 22.03.21 в 15:14 |
||
|
На противагу цьому, головний принцип методу Fisherfaces замість обчислення особливого власного вектора та власного значення для кожного зображення тренувального набору вимагає пошуку одного вектора та одного значення для особи. У попередньому прикладі 5 людей та 20 знімків облич для кожної, алгоритм Eigenfaces скористається сотнею власних облич та власних значень, у той час як метод Fisherfaces - лише п'ятьма. Atronax 22.03.21 в 15:17 |
||
|
Щоб отримати доступ до внутрішніх структур даних алгоритмів Eigenfaces та Fisherfaces, ми повинні скористатися функцією cv::Algorithm::get() у процесі роботи програми, оскільки вона не діє на етапі компіляції. Ці структури використовуються для математичних обчислень, а не обробки зображень, тому зберігаються у вигляді плаваючих чисел з типовим діапазоном від 0.0 до 1.0, а не 8-бітних пікселів uchar від 0 до 255, подібно до звичайних зображень. Atronax 22.03.21 в 15:17 |
||
|
Крім цього, це або одновимірний вектор чи один з багатьох рядів чи колонок більшої матриці. Перед тим як показати внутрішні структури даних, потрібно надати їм коректної прямокутної форми та конвертувати у 8-бітні пікселів uchar, що мають значення від 0 до 255. Оскільки дані матриці можуть належати діапазону від 0.0 до 1.0 чи від -1.0 до 1.0, можна скористатися функцією cv::normalize() з опцією cv::NORM_MINMAX, щоб упевнитися, що вихідні дані знаходяться у межах від 0 до 255, неважливо, яким є вхідний діапазон. Створимо функцію для виконання перетворення у прямокутну функцію та сконвертуємо у 8-бітні пікселі таким чином: Atronax 22.03.21 в 15:17 |
||
|
// Конвертуємо ряд чи колонку матриці плаваючих чисел у Atronax 22.03.21 в 15:18 |
||
|
Щоб легше налагоджувати код OpenCV та перевіряти структуру даних cv::Algorithm, можна скористатися файлами ImageUtils.cpp та ImageUtils.h для виводу інформації про сv::Mat: Atronax 22.03.21 в 15:18 |
||
|
Ви побачите дещо подібне у консолі: Atronax 22.03.21 в 15:18 |
||
|
Примітка Atronax 22.03.21 в 15:19 |
||
|
Код класу ImageUtils практично повністю заснований на С інтерфейсі бібліотеки OpenCV, але з часом включатиме все більше методів С++. Остання верcія доступна за адресою http://shervinemami.info/openCV.html. Atronax 22.03.21 в 15:19 |
||
|
Середнє обличчя Atronax 22.03.21 в 15:19 |
||
|
Алгоритми Eigenfaces та Fisherfaces спочатку обраховують середнє обличчя математично для усіх тренувальних зображень, тому від кожного можна відняти його та отримати кращі результати розпізнавання. Розглянемо, яким саме воно є. Іншою назвою цієї характеристики в реалізаціях Eigenfaces та Fisherfaces є "mean", описаний таким чином: Atronax 22.03.21 в 15:19 |
||
|
Mat averageFace = model->get<Mat>("mean"); Atronax 22.03.21 в 15:20 |
||
|
Ви маєте побачити на екрані зображення середнього обличчя, подібного до такого збільшеного фрагмента, що є комбінацією чоловіка, жінки та дитини. Також у консолі надруковано схожий текст: Atronax 22.03.21 в 15:20 |
||
|
averageFace (ряд): 4900w1h 1ch 64bpp, range[5.21,251.47] Atronax 22.03.21 в 15:21 |
