ITСooky

IT-рецепты съедобные и не очень!

Ищем человека на фото с OpenCV, dlib, face_recognition на Ubuntu 20.4

дата 07.09.2021

Собственно буду искать испанского актера Альваро Морте, не почему-то, а просто так! Есть испанский сериал на 2k серий есть 2k скриншотов — хочу найти с ним и надо это это как-то оптимизировать!

Пытался использовать вот этот мануал Face recognition with OpenCV, Python, and deep learning но он оказался непонятным и чето там надо было регистрироваться — он помог только с установкой нужного. А вот мануал Hussain Mujtaba реально помог Face Recognition with Python and OpenCV.

Установка OpenCV
Ставить буду через pip он у меня уже остановлен
pip --version

pip 20.0.2 from /usr/lib/python3/dist-packages/pip (python 3.8)

Python тоже уже установлен
python --version

Python 2.7.18

python3 --version

Python 3.8.10

К нему понадобиться
sudo apt-get install python-setuptools
sudo apt-get install python-dev

Ставим сам OpenCV
sudo pip install opencv-contrib-python

Установка dlib с поддержкой CUDA ядер
Я точно знаю что у меня на GeForce RTX 2070 есть CUDA ядра — в любой не старой видеокарте Nvidia они должны быть

для сборки понадобиться cmake ставлю его сначала
sudo apt-get install cmake

далее по инструкции
git clone https://github.com/davisking/dlib.git
cd dlib
mkdir build
cd build
cmake .. -DDLIB_USE_CUDA=1 -DUSE_AVX_INSTRUCTIONS=1
cmake --build .

Команда из инструкции 2018 года уже не работает запускаем дальше так
sudo python setup.py install

Установка face_recognition
pip install face_recognition

Установка imutils
Говорят нам еще нужен он
pip install imutils

Учим модель
Создаем папку app в ней создаем папку Images в ней создаем папку alvaro_morte
В неё сохраняем кучу(около 60) фоток Альваро Морте с разных ракурсов

Идем в парку app и создаем py файл
vi learn.py
вставляем в него code тут привязка к путям где лежат фотки

from imutils import paths
import face_recognition
import pickle
import cv2
import os
 
#get paths of each file in folder named Images
#Images here contains my data(folders of various persons)
imagePaths = list(paths.list_images('Images'))
knownEncodings = []
knownNames = []
# loop over the image paths
for (i, imagePath) in enumerate(imagePaths):
    # extract the person name from the image path
    name = imagePath.split(os.path.sep)[-2]
    # load the input image and convert it from BGR (OpenCV ordering)
    # to dlib ordering (RGB)
    image = cv2.imread(imagePath)
    rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    #Use Face_recognition to locate faces
    boxes = face_recognition.face_locations(rgb,model='hog')
    # compute the facial embedding for the face
    encodings = face_recognition.face_encodings(rgb, boxes)
    # loop over the encodings
    for encoding in encodings:
        knownEncodings.append(encoding)
        knownNames.append(name)
#save emcodings along with their names in dictionary data
data = {"encodings": knownEncodings, "names": knownNames}
#use pickle to save data into a file for later use
f = open("face_enc", "wb")
f.write(pickle.dumps(data))

Запускам его
python3 learn.py

он думает и создает в этой же папки файл face_enc тут оцифрованное лицо Альваро под именем папки в которой были его фотки

Теперь создаем файл
vi recog.py

вставляем код

import face_recognition
import imutils
import pickle
import time
import cv2
import os
 
#find path of xml file containing haarcascade file
cascPathface = os.path.dirname(
 cv2.__file__) + "/data/haarcascade_frontalface_alt2.xml"
# load the harcaascade in the cascade classifier
faceCascade = cv2.CascadeClassifier(cascPathface)
# load the known faces and embeddings saved in last file
data = pickle.loads(open('face_enc', "rb").read())
#Find path to the image you want to detect face and pass it here
image = cv2.imread('./001.jpg')
rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
#convert image to Greyscale for haarcascade
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
faces = faceCascade.detectMultiScale(gray,
                                     scaleFactor=1.1,
                                     minNeighbors=5,
                                     minSize=(60, 60),
                                     flags=cv2.CASCADE_SCALE_IMAGE)
 
# the facial embeddings for face in input
encodings = face_recognition.face_encodings(rgb)
names = []
# loop over the facial embeddings incase
# we have multiple embeddings for multiple fcaes
for encoding in encodings:
    #Compare encodings with encodings in data["encodings"]
    #Matches contain array with boolean values and True for the embeddings it matches closely
    #and False for rest
    matches = face_recognition.compare_faces(data["encodings"],
    encoding)
    #set name =inknown if no encoding matches
    name = "Unknown"
    # check to see if we have found a match
    if True in matches:
        #Find positions at which we get True and store them
        matchedIdxs = [i for (i, b) in enumerate(matches) if b]
        counts = {}
        # loop over the matched indexes and maintain a count for
        # each recognized face face
        for i in matchedIdxs:
            #Check the names at respective indexes we stored in matchedIdxs
            name = data["names"][i]
            #increase count for the name we got
            counts[name] = counts.get(name, 0) + 1
            #set name which has highest count
            name = max(counts, key=counts.get)
 
 
        # update the list of names
        names.append(name)
        # loop over the recognized faces
        for ((x, y, w, h), name) in zip(faces, names):
            # rescale the face coordinates
            # draw the predicted face name on the image
            cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)
            cv2.putText(image, name, (x, y), cv2.FONT_HERSHEY_SIMPLEX,
             0.75, (0, 255, 0), 2)
    cv2.imshow("Frame", image)
    cv2.waitKey(0)

кладем файл 001.jpg в папку app в которой лежит скрипт и файл face_enc — это прописано в этой строчке

image = cv2.imread('./001.jpg')

Запускаем
python3 recog.py

Скрипт показывает фотку(без её названия что плохо) и обводит лицо если узнает — чтобы его закрыть корркетно надо нажать 0 когда фотка показалсь

На фотке из набора для обучения сработало

На фотке не из набора тоже

Если на фотке несколько лиц странно срабатывает, но срабатывает

И так это штукофина работает таки!!! Теперь надо её адаптировать для поиска по многим фоткам и лицам, и чтобы она эти фотки копировала вдругую папку, а для этого надо погрузиться в python, а я его уже не взлюбил…поэтому часть того что нужно сделаю скриптами bash

Итак будет два файла первый pyhon вот такой
vi nrecog.py

вствляем код

import sys
import face_recognition
import imutils
import pickle
import time
import cv2
import os

#find path of xml file containing haarcascade file
cascPathface = os.path.dirname(
 cv2.__file__) + "/data/haarcascade_frontalface_alt2.xml"
# load the harcaascade in the cascade classifier
faceCascade = cv2.CascadeClassifier(cascPathface) 
# load the known faces and embeddings saved in last file
data = pickle.loads(open('face_enc', "rb").read())
#Find path to the image you want to detect face and pass it here
image = cv2.imread(sys.argv[1])
rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
#convert image to Greyscale for haarcascade
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
faces = faceCascade.detectMultiScale(gray,
                                     scaleFactor=1.1,
                                     minNeighbors=5,
                                     minSize=(60, 60),
                                     flags=cv2.CASCADE_SCALE_IMAGE)
 
# the facial embeddings for face in input
encodings = face_recognition.face_encodings(rgb)
names = []
# loop over the facial embeddings incase
# we have multiple embeddings for multiple fcaes
for encoding in encodings:
    #Compare encodings with encodings in data["encodings"]
    #Matches contain array with boolean values and True for the embeddings it matches closely
    #and False for rest
    matches = face_recognition.compare_faces(data["encodings"],
    encoding, tolerance=0.5)
    #set name =inknown if no encoding matches
    name = "Unknown"
    # check to see if we have found a match
    if True in matches:
        f = open("result.txt", "a")
        f.write(sys.argv[1] + '\n')
        f.close()
        sys.exit() 
      

Это обрезанный и чуть измененный код который был до этого. Он берет с наружи имя файла, которое будем накидывать bash и пишет в файле название если найдет

Создаем српит

vi facecheck.sh

вствляем код

#!/bin/bash
IFS=$'\n'
folder="test" 
rm result.txt
mkdir "./"$folder"_result" 
echo $folder
for a in $( ls ./$folder ); do
python3 nrecog.py $folder/$a
echo "./"$folder"/"$a
done
for a in $( cat ./result.txt | awk -F/ '{print $2}' ); do
cp "./"$folder"/"$a "./"$folder"_result/"$a
done

тут надо менять только переменнубю folder сейчас там написано папка test
и так в папке у нас три файла facecheck.sh nrecog.py face_enc и папка test с тестовыми фотками(не из обучения)

Запускм срипт
bash ./facecheck.sh

Как он отработаем смотрим файл который он создал result.txt, а так же он копирует все найденные фотки в папк test_result

там получается
28 — всего файлов
9 — сработали как осдержащие Альваро Морте
4 — из них действительно с Альваро
2 — так и не нашло, правда там трудности с лицом — он в профиль, а на втором после пытки

Предпологаю что улучшить этот результат можно лучше прокачавь модель. Беру еще около 2000 скриншотов из видео интервью с Альваро

Делаю сриншот каждой секунды командой
ffmpeg -i video.mp4 -vf fps=1 out%d.jpg

Возвращаюсь на пару шагов назад, кладу их в нужную папку и запускаю обучение — оно уже занимает больше времени!

Опять запускаю распознование
28 — всего файлов
16 — сработали как осдержащие Альваро Морте
6 — из них действительно с Альваро
0 — все Альвары найдены

Должна быть настройка для точности распознования… и она есть!

В файле nrecog.py находим строчку

matches = face_recognition.compare_faces(data["encodings"], encoding)

и меняем её на

matches = face_recognition.compare_faces(data["encodings"], encoding, tolerance=0.4)

Теперь все супер гуд

28 — всего файлов
6 — сработали как осдержащие Альваро Морте
6 — из них действительно с Альваро
0 — все Альвары найдены

Теперь хорошо бы проверить на больших масштабах так чтобы скриншотов 2000 и обычно это проблема, но вот испанский стримнг, надеюсь он не обидеться все же в научных целях — вот тут по ссылке можно безхитростным образом вытащить окло 2350 скринштов — по одному с серии. И я точно знаю что Альваро там был (уже заметил).

Запускаю

При толерантности 0.4 нашел 26 с Морой, при этом глазами я нашел 34, но не нашел 4 где Мора в дали.

Кстати: Процесс обработки 2300 картинок размером 1280×720 у меня занимает 59 минут на:
OS: Ubuntu 20.04.3 LTS
CPU: AMD® Ryzen 7 3700x 8-core processor × 16
Mem: 62,8 GiB
GPU: Nvidia GeForce RTX 2070
Disk: Samsung SSD 970 EVO Plus 500GB

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

Перезапускаю при толерантности 1.1 НЕТ стоп это слишком много, даже 0.7 много запускаю с 0.5
Найдено 56 из них с Альваро 28. При этом, ладно путает с бородатыми мужиками, но прям неборадатых женщин тоже помечает как Альваро!

Итого: Система помогает найти лица, но точность не очень, видимо это зависит от натренерованной модели. Глазами и своим мозгом у меня ищется быстрее пока — что радает… хотя у ПК возможности по совершенствованию безграничны, а вот мой мозг с каждым годом…


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

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