Распознавание Ворониных на фотографиях: от концепции к делу
Всем привет. В этом небольшом материале я расскажу как довольно быстро и малыми усилиями можно реализовать распознавание лиц на изображениях. Приподниму завесу тайны – получится довольно легко и безболезненно. Добро пожаловать под кат!
Откуда родилась задача
На данный момент я учусь в магистратуре. Этот семестр, помимо дистанционного образования, порадовал нас предметом, на котором мы учились проектировать интеллектуальные системы. В качестве практики было предложено выбрать какую-то группу объектов и научиться их распознавать на фотографиях при помощи нейронных сетей. Условие было лишь одно – нельзя выбирать тривиальные темы для распознавания, которые все делали уже сотню раз (кошечки, собачки, машины, автомобильные номера и т.п.). Мой выбор пал не героев сериала “Воронины”.
Сразу оговорюсь – информации о принципах работы и рекомендаций по реализации нейронных сетей, которые умеют что-то распознавать, мы, к сожалению, не получили. К моменту моего поступления в магистратуру довольно весомая часть теории вероятностей, математической статистики и прочих разделов математики была благополучно забыта. Поэтому пришлось импровизировать, что называется, на лету.
Что будем использовать
Первым шагом к решению проблемы стал выбор инструментария. После изучения нескольких популярных решений и подходов, выбор пал на библиотеку face-recognition. О других реализациях распознавания нестандартных объектов постараюсь рассказать в следующих статьях (дайте знать, если тема распознавания грибов на фото трогает вашу душу).
Выбранная библиотека имеет довольно широкий функционал по распознаванию лиц на фотографиях, а также довольно приятную документацию и ряд интересных примеров с фрагментами кода. Помимо фото, она позволяет распознавать лица и на видео (не без помощи openCV).
Устанавливается face-recognition довольно легко, единственная важная оговорка – пользователям Mac и Linux (в моем случае была Ubuntu 20.04) необходимо вручную установить dlib. Процесс тоже довольно подробно описан в документации.
Немного о том, как все работает
face-regontion использует внутри себя обозначенный выше dlib и OpenFace. Сначала на фотографии выделяется лицо, а после на лице выделяется 68 значимых точек.
После лицо кодируется особым образом и возвращается нам массивом, который мы можем использовать для наших нужд. Поскольку количество распознанных точек для нас критически важно, ведь по ним и будет строиться кодировка изображений, то алгоритм может давать ошибки на нестандартных ракурсах. К примеру, фотографии в профиль или смазанные фото распознавались довольно плохо.
Подробно о том, как все устроено, можно узнать в оригинальном посте автора библиотеки.
От слов к реализации
После того, как инструментарий выбран, осталось перейти к реализации системы, которая сейчас представляет из себя до боли простое веб-приложение (форма и кнопка), которое позволяет загрузить изображение с героем и увидеть результат в алерте.
На серверной стороне python с fast api. Эта давно зарекомендовавшая себя пара и тут продемонстрировала все свои красоту и удобство.
Первым делом, нам необходим набор из фото, который позволяет заранее построить кодировки лиц героев. И тут раскрывается очередной и довольно весомый плюс face-recognition – нам нужно всего одно фото, по которому мы можем построить математическую проекцию лица. Нам нет нужды собирать большой датасет из тысяч или даже десятков тысяч изображений.
Далее мы загружаем в систему все наши тестовые фотографии, чтобы выделить кодировки лиц:
kostik = face_recognition.load_image_file("samples/kostik.jpg")
kostik_encoding = face_recognition.face_encodings(kostik)[0]
vera = face_recognition.load_image_file("samples/vera.jpg")
vera_encoding = face_recognition.face_encodings(vera)[0]
После я реализовал набор функций, которые принимают на вход кодировку присланного изображения, сравнивают его с определенном персонажем, а после возвращают либо имя, либо вызов следующей функции. Выглядит все следующим образом:
def start_comparing(encoding):
compare_result = face_recognition.compare_faces([kostik_encoding], encoding)
if compare_result[0]:
return "Костик"
else:
return compare_vera(encoding)
def compare_vera(encoding):
compare_result = face_recognition.compare_faces([vera_encoding], encoding)
if compare_result[0]:
return "Вера"
else:
return compare_nikolay(encoding)
Тут есть один интересный момент: я расположил вызовы функции в порядке популярности персонажей. То есть, чем популярнее персонаж, тем быстрее мы будем получать результат (просто за счет того, что выполняем меньше проверок). Популярность, разумеется, определялась моим мнением, но если бы речь шла о создании не учебной системы, то подобный ход мог бы существенно повысить производительность.
Внимательный читатель наверняка уже заметил, что функция compare_faces возвращает массив. Связанно это с тем, что мы можем на одном фото определять сразу несколько лиц, а также сравнивать сразу несколько лиц. Покопавшись в api библиотеки можно найти еще ряд полезных функций, которые сильно увеличат потенциал системы.
Ну и в конце нужно реализовать обычный API-поинт, который умел бы принимать фото и возвращать результат:
@app.post("/recognize/")
def create_file(file: UploadFile = File(...)):
with open("samples/test.jpeg", "wb") as buffer:
shutil.copyfileobj(file.file, buffer)
unknown_image = face_recognition.load_image_file("samples/test.jpeg")
try:
unknown_encoding = face_recognition.face_encodings(unknown_image)[0]
result = start_comparing(unknown_encoding)
except Exception as e:
result = "Тут нет лица"
else:
pass
finally:
pass
return {"filename": file.filename, "result": result}
Получаем файл изображения, сохраняем его, кодируем и запускаем алгоритм сравнения. Если вы все сделали правильно, не забыли про CORS и написали веб-приложение (или использовали мое, с 2 формами), то теперь у вас готовая система, которая умеет отличать Галю от Лени. Итоговое решение можно найти тут. Если вдруг кто-то заинтересуется и будет скучать томными вечерами, то присылайте пулл-реквесты – буду рад!
Выводы
Теперь немного выводов:
-
Искусственный интеллект и распознавание изображений в частности – это очень сложный домен, который требует большого количество знаний и опыта. Однако существует ряд инструментов, которые помогут облегчить вам жизнь и внедрить необычные технологии “малой кровью”.
-
Библиотека замечательно показала себя в учебном проекте. Использование ее будет вполне оправдано в хакатонах или же стартапах, где нужно как можно быстрее реализовать MVP.
-
Не стоит бездумно использовать библиотеку в больших проектах, все же лучше изучить ограничения производительности.
-
Навык импорта библиотеки в python и последующее использование ее методов не делает из программиста Senior Data Sciene Engineer. Область искусственного интеллекта куда как сложнее и глубже.
-
Математику все же забывать не стоит 🙂