mirror of
https://github.com/serengil/deepface.git
synced 2025-06-06 19:45:21 +00:00
124 lines
3.8 KiB
Python
124 lines
3.8 KiB
Python
import os
|
|
import cv2
|
|
from deepface.detectors import FaceDetector
|
|
|
|
|
|
def build_model():
|
|
detector = {}
|
|
detector["face_detector"] = build_cascade("haarcascade")
|
|
detector["eye_detector"] = build_cascade("haarcascade_eye")
|
|
return detector
|
|
|
|
|
|
def build_cascade(model_name="haarcascade"):
|
|
opencv_path = get_opencv_path()
|
|
if model_name == "haarcascade":
|
|
face_detector_path = opencv_path + "haarcascade_frontalface_default.xml"
|
|
if os.path.isfile(face_detector_path) != True:
|
|
raise ValueError(
|
|
"Confirm that opencv is installed on your environment! Expected path ",
|
|
face_detector_path,
|
|
" violated.",
|
|
)
|
|
detector = cv2.CascadeClassifier(face_detector_path)
|
|
|
|
elif model_name == "haarcascade_eye":
|
|
eye_detector_path = opencv_path + "haarcascade_eye.xml"
|
|
if os.path.isfile(eye_detector_path) != True:
|
|
raise ValueError(
|
|
"Confirm that opencv is installed on your environment! Expected path ",
|
|
eye_detector_path,
|
|
" violated.",
|
|
)
|
|
detector = cv2.CascadeClassifier(eye_detector_path)
|
|
|
|
else:
|
|
raise ValueError(f"unimplemented model_name for build_cascade - {model_name}")
|
|
|
|
return detector
|
|
|
|
|
|
def detect_face(detector, img, align=True):
|
|
resp = []
|
|
|
|
detected_face = None
|
|
img_region = [0, 0, img.shape[1], img.shape[0]]
|
|
|
|
faces = []
|
|
try:
|
|
# faces = detector["face_detector"].detectMultiScale(img, 1.3, 5)
|
|
|
|
# note that, by design, opencv's haarcascade scores are >0 but not capped at 1
|
|
faces, _, scores = detector["face_detector"].detectMultiScale3(
|
|
img, 1.1, 10, outputRejectLevels=True
|
|
)
|
|
except:
|
|
pass
|
|
|
|
if len(faces) > 0:
|
|
|
|
for (x, y, w, h), confidence in zip(faces, scores):
|
|
detected_face = img[int(y) : int(y + h), int(x) : int(x + w)]
|
|
|
|
if align:
|
|
detected_face = align_face(detector["eye_detector"], detected_face)
|
|
|
|
img_region = [x, y, w, h]
|
|
|
|
resp.append((detected_face, img_region, confidence))
|
|
|
|
return resp
|
|
|
|
|
|
def align_face(eye_detector, img):
|
|
|
|
detected_face_gray = cv2.cvtColor(
|
|
img, cv2.COLOR_BGR2GRAY
|
|
) # eye detector expects gray scale image
|
|
|
|
# eyes = eye_detector.detectMultiScale(detected_face_gray, 1.3, 5)
|
|
eyes = eye_detector.detectMultiScale(detected_face_gray, 1.1, 10)
|
|
|
|
# ----------------------------------------------------------------
|
|
|
|
# opencv eye detectin module is not strong. it might find more than 2 eyes!
|
|
# besides, it returns eyes with different order in each call (issue 435)
|
|
# this is an important issue because opencv is the default detector and ssd also uses this
|
|
# find the largest 2 eye. Thanks to @thelostpeace
|
|
|
|
eyes = sorted(eyes, key=lambda v: abs((v[0] - v[2]) * (v[1] - v[3])), reverse=True)
|
|
|
|
# ----------------------------------------------------------------
|
|
|
|
if len(eyes) >= 2:
|
|
|
|
# decide left and right eye
|
|
|
|
eye_1 = eyes[0]
|
|
eye_2 = eyes[1]
|
|
|
|
if eye_1[0] < eye_2[0]:
|
|
left_eye = eye_1
|
|
right_eye = eye_2
|
|
else:
|
|
left_eye = eye_2
|
|
right_eye = eye_1
|
|
|
|
# -----------------------
|
|
# find center of eyes
|
|
left_eye = (int(left_eye[0] + (left_eye[2] / 2)), int(left_eye[1] + (left_eye[3] / 2)))
|
|
right_eye = (int(right_eye[0] + (right_eye[2] / 2)), int(right_eye[1] + (right_eye[3] / 2)))
|
|
img = FaceDetector.alignment_procedure(img, left_eye, right_eye)
|
|
return img # return img anyway
|
|
|
|
|
|
def get_opencv_path():
|
|
opencv_home = cv2.__file__
|
|
folders = opencv_home.split(os.path.sep)[0:-1]
|
|
|
|
path = folders[0]
|
|
for folder in folders[1:]:
|
|
path = path + "/" + folder
|
|
|
|
return path + "/data/"
|