factory/apps/utils/face.py

90 lines
2.9 KiB
Python

from deepface import DeepFace
from deepface.commons import functions, distance as dst
import pandas as pd
import time
def face_find(
img_path,
global_df,
model_name="Facenet512",
distance_metric="cosine",
enforce_detection=True,
detector_backend="opencv",
align=True,
normalization="base",
silent=False,
):
tic = time.time()
target_size = functions.find_target_size(model_name=model_name)
# now, we got representations for facial database
df = global_df
# img path might have more than once face
target_objs = functions.extract_faces(
img=img_path,
target_size=target_size,
detector_backend=detector_backend,
grayscale=False,
enforce_detection=enforce_detection,
align=align,
)
resp_obj = []
for target_img, target_region, _ in target_objs:
target_embedding_obj = DeepFace.represent(
img_path=target_img,
model_name=model_name,
enforce_detection=enforce_detection,
detector_backend="skip",
align=align,
normalization=normalization,
)
target_representation = target_embedding_obj[0]["embedding"]
result_df = df.copy() # df will be filtered in each img
result_df["source_x"] = target_region["x"]
result_df["source_y"] = target_region["y"]
result_df["source_w"] = target_region["w"]
result_df["source_h"] = target_region["h"]
distances = []
for index, instance in df.iterrows():
source_representation = instance[f"{model_name}_representation"]
if distance_metric == "cosine":
distance = dst.findCosineDistance(source_representation, target_representation)
elif distance_metric == "euclidean":
distance = dst.findEuclideanDistance(source_representation, target_representation)
elif distance_metric == "euclidean_l2":
distance = dst.findEuclideanDistance(
dst.l2_normalize(source_representation),
dst.l2_normalize(target_representation),
)
else:
raise ValueError(f"invalid distance metric passes - {distance_metric}")
distances.append(distance)
# ---------------------------
result_df[f"{model_name}_{distance_metric}"] = distances
threshold = dst.findThreshold(model_name, distance_metric)
result_df = result_df.drop(columns=[f"{model_name}_representation"])
result_df = result_df[result_df[f"{model_name}_{distance_metric}"] <= threshold]
result_df = result_df.sort_values(
by=[f"{model_name}_{distance_metric}"], ascending=True
).reset_index(drop=True)
resp_obj.append(result_df)
# -----------------------------------
toc = time.time()
if not silent:
print("find function lasts ", toc - tic, " seconds")
return resp_obj