В этой статье я максимально коротко и просто объясню принцип распознавания, хранения и поиска лиц в базе данных. В качестве примера будет использована библиотека Insightface и база данных PostgreSQL.

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

Для начала кратко пройдемся по всей цепочке действий, чтобы понять общую схему:

  1. Прогоняем фото с лицами через библиотеку insightface и получаем для каждого лица вектор (embedding)

  2. Полученный вектор записываем в базу данных

  3. Чтобы осуществлять поиск по лицу, сравниваем исходный embedding с теми, что хранятся в базе данных

А теперь пройдемся по каждому пункту более подробно.

Преобразование фото лица в вектор

Для начала устанавливаем библиотеку для распознавания лиц:

pip install insightface

Существует много других библиотек для распознавания лиц (к примеру, DeepFace), можете использовать любую библиотеку, принцип работы не изменится.

Далее прогоняем изображение через нейросеть:

from insightface.app import FaceAnalysis
import cv2
app = FaceAnalysis(name="buffalo_sc",providers=['CPUExecutionProvider'])
app.prepare(ctx_id=0, det_size=(256, 256))  #подготовка нейросети
img = cv2.imread("G:/pic.jpg") #считываем изображение
faces = app.get(img) #ищем лица на изображении и получаем информацию о них
for face in faces:
    print(face)
Hidden text
  • если нужна более высокая точность, распознавание пола, возраста, то используйте модель "buffalo_l"

  • можно использовать GPU вместо CPU (providers="CUDAExecutionProvider"). Также придется установить библиотеку onnx и onnxruntime-gpu

На выходе в переменной face получаем:

  • face.bbox - это область на картинке, где находится лицо

  • face.det_score - уверенность нейросети в полученных результатах

  • face.embedding - точка, или же вектор в 512-мерном пространстве, по которому далее можно сравнивать схожесть лиц

Для того, чтобы видеть, какие лица были найдены, можно использовать данный код:

x, y, x2, y2 = face.bbox #получаем границы лица
cropped = img[int(y):int(y2), int(x):int(x2)] #вырезаем лицо из изображения
cv2.imshow('image', cropped) #показываем лицо
cv2.waitKey(0)
Исходное изображение
Полученные лица. insihtface находят лица, даже если их часть скрыта маской
Полученные лица. insihtface находят лица, даже если их часть скрыта маской

Хранение векторов в базе данных

Есть множество вариантов хранения векторов, но, если лиц десятки тысяч, или даже миллионы, то без хорошей базы данных не обойтись. В этой статье, в качестве примера, я покажу как устроено хранение векторов в моем проекте (django + postgresql)

Для более простого хранения и поиска по векторам потребуется установить расширение для базы данных "pgvector" https://github.com/pgvector/pgvector, а также, установить python библиотеку pip install pgvector

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

Как это выглядит django models.py:

from pgvector.django import VectorField
class Faces(models.Model):
    id = models.AutoField(primary_key=True)
    embedding = VectorField(dimensions = 512,null=True)

Как это выглядит в pgAdmin:

Как добавлять в базу данных новые лица в django:

Faces.objects.create(embedding=face.embedding)

После того, как у нас уже есть база данных с хранящимися в ней лицами, можно переходить к поиску.

Поиск по базе данных

Итак, лица у нас хранятся в виде векторов. Что же нам нужно сделать с этими векторами, чтобы найти лицо в базе данных? Самые распространенные варианты поиска - это нахождение расстояний между концами векторов (чем меньше расстояние, тем меньше отличаются лица), а также - нахождение косинуса между векторами.

Расстояние между концами векторов в 2-х мерном пространстве
Расстояние между концами векторов в 2-х мерном пространстве

В этой статье рассмотрим поиск через нахождение расстояний (евклидово расстояние). Выполняется оно так:

from pgvector.django import L2Distance
fbase = Faces.objects.alias(distance=L2Distance('embedding', face.embedding)).filter(distance__lt=22)

В этом куске кода мы ищем в базе данных векторы, расстояние до которых от исходного вектора не более 22. Если нужен более точный поиск, можно поставить число поменьше. Если точность не так важна, можно увеличить число. Также, расстояние зависит от размерности вектора, если у вас 128-мерные векторы, то расстояния там, скорее всего, будут поменьше. В общем, подбирайте точность поиска опытным путем исходя из ваших задач.

Если нам просто нужно посчитать расстояние между двумя векторами, то можно воспользоваться библиотекой numpy:

import numpy as np
distance = np.linalg.norm(embedding1 - embedding2)

В приведенном примере в таблице с лицами хранится только id. Можно хранить и любые другие данные, пол, возраст, можно связать id с данными из других таблиц. Тут все зависит от ваших задач.

Заключение

В данной статье мы разобрали общие принципы распознавания, хранения и поиска лиц в базе данных. Далее подбирайте базы данных, библиотеки, которые будут наиболее удобны и эффективны для работы в ваших фреймворках, для решения ваших задач.

Комментарии (5)


  1. sem-a
    26.04.2024 04:29
    +2

    Системы распознания лиц могут допускать ошибки. Какая ошибка у этого метода? Например, какая вероятность того, что прогоняя фото с лицами через библиотеку, она распознает всех людей как разных?


    1. demonuga1998 Автор
      26.04.2024 04:29
      +2

      Точность довольно высокая. К примеру, в моем проекте, если есть 100 разных фото одного лица и провести поиск с дистанцией 22, то система выдаст, примерно, 95 фото (5 фото не выдаст, у которых дистанция более 22). А если сделать поиск с дистанцией 24, то выдаст все фото, но, при этом, еще 5 фото с лицом другого человека подкинет (при общем количестве фото в базе данных - около 10 тысяч).


      1. septa
        26.04.2024 04:29
        +1

        Как эта "точность" соотносится с точностью результата?
        Исходя из вашего комментария точность 95% при дистанции 22 и 512 векторами и уклоном в " - ", в то же время она будет такой же, но с уклоном в " + " при 24. Есть ли способ посчитать это заранее?


  1. ORENYT
    26.04.2024 04:29

    Тоже в свое время этой библой работал. Сам не мог победить проблему разных масштабов картинки.


  1. osp2003
    26.04.2024 04:29

    Мне кажется в публикации опущено несколько важных моментов. Например предварительная обработка исходного изображения, чтобы повысить точность распознавания лиц. Ничего не описано про скорость поиска. И не совсем понятно почему расчет разности между векторами ведется на питоне. pgvector имеет свои функции расчета расстояния наверное с ними побыстрее будет чем гонять данные туда-сюда.