Поиск лиц с помощью Python

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

Для поиска лица в папке с изображениями используется библиотека deepface и opencv. Для распознавания лиц используется общедоступная библиотека “Facenet512”, а для определения лиц – модель retinaface.

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

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

Найденные изображения снова используются для поиска совпадений в папке с данными. Это повышает точность работы программы.

Код программы приведен ниже:

from deepface import DeepFace
import os
import shutil
import cv2 
import numpy as np
from deepface.detectors import FaceDetector
import tensorflow as tf
import traceback
tf_version = tf.__version__
tf_major_version = int(tf_version.split(".")[0])
tf_minor_version = int(tf_version.split(".")[1])
if tf_major_version == 1:
	import keras
	from keras.preprocessing.image import load_img, save_img, img_to_array
	from keras.applications.imagenet_utils import preprocess_input
	from keras.preprocessing import image
elif tf_major_version == 2:
	from tensorflow import keras
	from tensorflow.keras.preprocessing.image import load_img, save_img, img_to_array
	from tensorflow.keras.applications.imagenet_utils import preprocess_input
	from tensorflow.keras.preprocessing import image


def detect_face(result,img):

    img_region = [0, 0, img.shape[1], img.shape[0]]
  
    try:
        detected_face, img_region = result
    except: #if detected face shape is (0, 0) and alignment cannot be performed, this block will be run
        detected_face = None

    if (isinstance(detected_face, np.ndarray)):
        return detected_face, img_region
    else:
        if detected_face == None:
            enforce_detection = False
            if enforce_detection != True:
                return img, img_region
            else:
                raise ValueError("Face could not be detected. Please confirm that the picture is a face photo or consider to set enforce_detection param to False.")



def preprocess_face(img, output, target_size=(224, 224), grayscale = False, enforce_detection = False, detector_backend = 'opencv', return_region = False, align = True):

	#img might be path, base64 or numpy array. Convert it to numpy whatever it is.
	img = DeepFace.functions.load_image(img)
	base_img = img.copy()

	img, region = output

	#--------------------------

	if img.shape[0] == 0 or img.shape[1] == 0:
		if enforce_detection == True:
			raise ValueError("Detected face shape is ", img.shape,". Consider to set enforce_detection argument to False.")
		else: #restore base image
			img = base_img.copy()

	#--------------------------

	#post-processing
	if grayscale == True:
		img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

	#---------------------------------------------------
	#resize image to expected shape

	# img = cv2.resize(img, target_size) #resize causes transformation on base image, adding black pixels to resize will not deform the base image

	if img.shape[0] > 0 and img.shape[1] > 0:
		factor_0 = target_size[0] / img.shape[0]
		factor_1 = target_size[1] / img.shape[1]
		factor = min(factor_0, factor_1)

		dsize = (int(img.shape[1] * factor), int(img.shape[0] * factor))
		img = cv2.resize(img, dsize)

		# Then pad the other side to the target size by adding black pixels
		diff_0 = target_size[0] - img.shape[0]
		diff_1 = target_size[1] - img.shape[1]
		if grayscale == False:
			# Put the base image in the middle of the padded image
			img = np.pad(img, ((diff_0 // 2, diff_0 - diff_0 // 2), (diff_1 // 2, diff_1 - diff_1 // 2), (0, 0)), 'constant')
		else:
			img = np.pad(img, ((diff_0 // 2, diff_0 - diff_0 // 2), (diff_1 // 2, diff_1 - diff_1 // 2)), 'constant')

	#------------------------------------------

	#double check: if target image is not still the same size with target.
	if img.shape[0:2] != target_size:
		img = cv2.resize(img, target_size)

	#---------------------------------------------------

	#normalizing the image pixels

	img_pixels = image.img_to_array(img) #what this line doing? must?
	img_pixels = np.expand_dims(img_pixels, axis = 0)
	img_pixels /= 255 #normalize input in [0, 1]

	#---------------------------------------------------

	if return_region == True:
		return img_pixels, region
	else:
		return img_pixels


def checkresult(result):
    try:
        detected_face, img_region = result
    except: #if detected face shape is (0, 0) and alignment cannot be performed, this block will be run
        detected_face = None
    if detected_face is None:
        return False
    if detected_face.shape[0] == 0 or detected_face.shape[1] == 0:
        return False
    return True




testfolder = r'./data'
inputfolder = r'./input'
outputfolder = r'./output'


def verify(sourceembedding,path,face_detector, detector,file):
    embeddings = []
    img = cv2.imread(path)
    results = FaceDetector.detect_faces(face_detector, detector, img, True)
    input_shape_x, input_shape_y = DeepFace.functions.find_input_shape(model)
    ids = []
    resultok = []
    for result in results:
        resultok.append(checkresult(result))
    if any(resultok) == False:
        print('using other detector')
        if detector == 'retinaface':
            detector = 'mtcnn'
        else:
            detector = 'retinaface'
        face_detector = FaceDetector.build_model(detector)
        results = FaceDetector.detect_faces(face_detector, detector, img, True)

    for result in results:
        output = detect_face(result,img)
        output2 = preprocess_face(img,output, target_size=(input_shape_y, input_shape_x))
        output3 = DeepFace.functions.normalize_input(img = output2, normalization = 'base')
        if "keras" in str(type(model)):
            #new tf versions show progress bar and it is annoying
            targetembedding = model.predict(output3, verbose=0)[0].tolist()
        else:
            #SFace is not a keras model and it has no verbose argument
            targetembedding = model.predict(output3)[0].tolist()
        distance = DeepFace.dst.findCosineDistance(sourceembedding, targetembedding)
        distance = np.float64(distance)
        threshold = DeepFace.dst.findThreshold(model_name, 'cosine')
        if distance <= threshold:
            identified = True
            foundembeddings.append(targetembedding)
        else:
            identified = False
        print({"identified":identified})
        ids.append(identified)
        embeddings.append({'path':path,'file':file,'embedding':targetembedding})
    return {"verified":any(ids),'embeddings':embeddings}

def checkfolder():
    for file in os.listdir(testfolder):
        test = testfolder + "\\" + file
        try:
            check = cv2.imread(test)
        except:
            continue
        if check is None:
            continue
        
        
        for sourceembedding in sourceembeddings:
            result = verify(sourceembedding,test,face_detector, detector, file)
            testembeddings.extend(result['embeddings'])
            # result = DeepFace.verify(img1_path = img , img2_path = test ,enforce_detection =False, model = builtmodel,  detector_backend = 'opencv')
            # result2 = DeepFace.verify(img1_path = img , img2_path = test ,enforce_detection =False, model = builtmodel,  detector_backend = 'mtcnn')
            if result['verified'] == True : #or result2['verified'] == True 
                outputpath = outputfolder + "\\" + file
                shutil.copyfile(test, outputpath)
                print (result['verified'])

def checkembeddings():
    for sourceembedding in sourceembeddings:
        for a in testembeddings:
            path = a['path']
            file = a['file']
            targetembedding = a['embedding']
            distance = DeepFace.dst.findCosineDistance(sourceembedding, targetembedding)
            distance = np.float64(distance)
            threshold = DeepFace.dst.findThreshold(model_name, 'cosine')
            if distance <= threshold:
                outputpath = outputfolder + "\\" + file
                if file not in os.listdir(outputfolder):
                    shutil.copyfile(path, outputpath)
                    foundembeddings.append(targetembedding)

model_name = "Facenet512"
model = DeepFace.build_model(model_name)
sourceembeddings = []
foundembeddings = []
testembeddings = []
detector = 'retinaface'
face_detector = FaceDetector.build_model(detector)


def facecheck():
    try:
        global foundembeddings, sourceembeddings, testembeddings
        for input in os.listdir(inputfolder):
            srcimg = inputfolder + "\\" + input
            try:
                check = cv2.imread(srcimg)
            except:
                continue
            if check is None:
                continue
            try:
                embedding = DeepFace.represent(srcimg, model_name, model = model, enforce_detection = True, detector_backend = 'retinaface')
            except:
                embedding = DeepFace.represent(srcimg, model_name, model = model, enforce_detection = False, detector_backend = 'mtcnn')
                print('used mtcnn')
            sourceembeddings.append(embedding)
        checkfolder()
        
        sourceembeddings.extend(foundembeddings)
        foundembeddings =[]
        print('length of source embeddings', len(sourceembeddings))
        checkembeddings()
        sourceembeddings.extend(foundembeddings)
        foundembeddings =[]
        print('length of source embeddings', len(sourceembeddings))
        checkembeddings()


    except:
        print(srcimg,test)
        print(traceback.format_exc())


if __name__ == "__main__":
    try:
        window = tk.Tk()
        window.title('Face Search ')
        window.geometry("500x500")
        frame = tk.Frame(window)
        frame.grid(row=0, column=0)
        button3 = tk.Button(frame, text='Search Face', command=facecheck)
        button3.grid(row=0, column=1)
  

        window.mainloop()
    except:
        window.destroy()
+1
5
+1
3
+1
1
+1
2
+1
0

Ответить

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