mirror of
https://github.com/serengil/deepface.git
synced 2025-06-07 20:15:21 +00:00
Update master branch. Merge branch 'master' into feat/make-Race-and-Emotion-batch
This commit is contained in:
commit
9f3875e6a3
@ -121,7 +121,7 @@ models = [
|
|||||||
"ArcFace",
|
"ArcFace",
|
||||||
"Dlib",
|
"Dlib",
|
||||||
"SFace",
|
"SFace",
|
||||||
"GhostFaceNet",
|
"GhostFaceNet"
|
||||||
]
|
]
|
||||||
|
|
||||||
#face verification
|
#face verification
|
||||||
@ -223,6 +223,9 @@ backends = [
|
|||||||
'retinaface',
|
'retinaface',
|
||||||
'mediapipe',
|
'mediapipe',
|
||||||
'yolov8',
|
'yolov8',
|
||||||
|
'yolov11s',
|
||||||
|
'yolov11n',
|
||||||
|
'yolov11m',
|
||||||
'yunet',
|
'yunet',
|
||||||
'centerface',
|
'centerface',
|
||||||
]
|
]
|
||||||
|
@ -54,10 +54,10 @@ def build_model(model_name: str, task: str = "facial_recognition") -> Any:
|
|||||||
Args:
|
Args:
|
||||||
model_name (str): model identifier
|
model_name (str): model identifier
|
||||||
- VGG-Face, Facenet, Facenet512, OpenFace, DeepFace, DeepID, Dlib,
|
- VGG-Face, Facenet, Facenet512, OpenFace, DeepFace, DeepID, Dlib,
|
||||||
ArcFace, SFace, GhostFaceNet for face recognition
|
ArcFace, SFace and GhostFaceNet for face recognition
|
||||||
- Age, Gender, Emotion, Race for facial attributes
|
- Age, Gender, Emotion, Race for facial attributes
|
||||||
- opencv, mtcnn, ssd, dlib, retinaface, mediapipe, yolov8, yunet,
|
- opencv, mtcnn, ssd, dlib, retinaface, mediapipe, yolov8, yolov11n,
|
||||||
fastmtcnn or centerface for face detectors
|
yolov11s, yolov11m, yunet, fastmtcnn or centerface for face detectors
|
||||||
- Fasnet for spoofing
|
- Fasnet for spoofing
|
||||||
task (str): facial_recognition, facial_attribute, face_detector, spoofing
|
task (str): facial_recognition, facial_attribute, face_detector, spoofing
|
||||||
default is facial_recognition
|
default is facial_recognition
|
||||||
@ -68,18 +68,18 @@ def build_model(model_name: str, task: str = "facial_recognition") -> Any:
|
|||||||
|
|
||||||
|
|
||||||
def verify(
|
def verify(
|
||||||
img1_path: Union[str, np.ndarray, List[float]],
|
img1_path: Union[str, np.ndarray, List[float]],
|
||||||
img2_path: Union[str, np.ndarray, List[float]],
|
img2_path: Union[str, np.ndarray, List[float]],
|
||||||
model_name: str = "VGG-Face",
|
model_name: str = "VGG-Face",
|
||||||
detector_backend: str = "opencv",
|
detector_backend: str = "opencv",
|
||||||
distance_metric: str = "cosine",
|
distance_metric: str = "cosine",
|
||||||
enforce_detection: bool = True,
|
enforce_detection: bool = True,
|
||||||
align: bool = True,
|
align: bool = True,
|
||||||
expand_percentage: int = 0,
|
expand_percentage: int = 0,
|
||||||
normalization: str = "base",
|
normalization: str = "base",
|
||||||
silent: bool = False,
|
silent: bool = False,
|
||||||
threshold: Optional[float] = None,
|
threshold: Optional[float] = None,
|
||||||
anti_spoofing: bool = False,
|
anti_spoofing: bool = False,
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
Verify if an image pair represents the same person or different persons.
|
Verify if an image pair represents the same person or different persons.
|
||||||
@ -96,8 +96,8 @@ def verify(
|
|||||||
OpenFace, DeepFace, DeepID, Dlib, ArcFace, SFace and GhostFaceNet (default is VGG-Face).
|
OpenFace, DeepFace, DeepID, Dlib, ArcFace, SFace and GhostFaceNet (default is VGG-Face).
|
||||||
|
|
||||||
detector_backend (string): face detector backend. Options: 'opencv', 'retinaface',
|
detector_backend (string): face detector backend. Options: 'opencv', 'retinaface',
|
||||||
'mtcnn', 'ssd', 'dlib', 'mediapipe', 'yolov8', 'centerface' or 'skip'
|
'mtcnn', 'ssd', 'dlib', 'mediapipe', 'yolov8', 'yolov11n', 'yolov11s', 'yolov11m',
|
||||||
(default is opencv).
|
'centerface' or 'skip' (default is opencv).
|
||||||
|
|
||||||
distance_metric (string): Metric for measuring similarity. Options: 'cosine',
|
distance_metric (string): Metric for measuring similarity. Options: 'cosine',
|
||||||
'euclidean', 'euclidean_l2' (default is cosine).
|
'euclidean', 'euclidean_l2' (default is cosine).
|
||||||
@ -164,14 +164,14 @@ def verify(
|
|||||||
|
|
||||||
|
|
||||||
def analyze(
|
def analyze(
|
||||||
img_path: Union[str, np.ndarray],
|
img_path: Union[str, np.ndarray],
|
||||||
actions: Union[tuple, list] = ("emotion", "age", "gender", "race"),
|
actions: Union[tuple, list] = ("emotion", "age", "gender", "race"),
|
||||||
enforce_detection: bool = True,
|
enforce_detection: bool = True,
|
||||||
detector_backend: str = "opencv",
|
detector_backend: str = "opencv",
|
||||||
align: bool = True,
|
align: bool = True,
|
||||||
expand_percentage: int = 0,
|
expand_percentage: int = 0,
|
||||||
silent: bool = False,
|
silent: bool = False,
|
||||||
anti_spoofing: bool = False,
|
anti_spoofing: bool = False,
|
||||||
) -> List[Dict[str, Any]]:
|
) -> List[Dict[str, Any]]:
|
||||||
"""
|
"""
|
||||||
Analyze facial attributes such as age, gender, emotion, and race in the provided image.
|
Analyze facial attributes such as age, gender, emotion, and race in the provided image.
|
||||||
@ -187,8 +187,8 @@ def analyze(
|
|||||||
Set to False to avoid the exception for low-resolution images (default is True).
|
Set to False to avoid the exception for low-resolution images (default is True).
|
||||||
|
|
||||||
detector_backend (string): face detector backend. Options: 'opencv', 'retinaface',
|
detector_backend (string): face detector backend. Options: 'opencv', 'retinaface',
|
||||||
'mtcnn', 'ssd', 'dlib', 'mediapipe', 'yolov8', 'centerface' or 'skip'
|
'mtcnn', 'ssd', 'dlib', 'mediapipe', 'yolov8', 'yolov11n', 'yolov11s', 'yolov11m',
|
||||||
(default is opencv).
|
'centerface' or 'skip' (default is opencv).
|
||||||
|
|
||||||
distance_metric (string): Metric for measuring similarity. Options: 'cosine',
|
distance_metric (string): Metric for measuring similarity. Options: 'cosine',
|
||||||
'euclidean', 'euclidean_l2' (default is cosine).
|
'euclidean', 'euclidean_l2' (default is cosine).
|
||||||
@ -263,20 +263,20 @@ def analyze(
|
|||||||
|
|
||||||
|
|
||||||
def find(
|
def find(
|
||||||
img_path: Union[str, np.ndarray],
|
img_path: Union[str, np.ndarray],
|
||||||
db_path: str,
|
db_path: str,
|
||||||
model_name: str = "VGG-Face",
|
model_name: str = "VGG-Face",
|
||||||
distance_metric: str = "cosine",
|
distance_metric: str = "cosine",
|
||||||
enforce_detection: bool = True,
|
enforce_detection: bool = True,
|
||||||
detector_backend: str = "opencv",
|
detector_backend: str = "opencv",
|
||||||
align: bool = True,
|
align: bool = True,
|
||||||
expand_percentage: int = 0,
|
expand_percentage: int = 0,
|
||||||
threshold: Optional[float] = None,
|
threshold: Optional[float] = None,
|
||||||
normalization: str = "base",
|
normalization: str = "base",
|
||||||
silent: bool = False,
|
silent: bool = False,
|
||||||
refresh_database: bool = True,
|
refresh_database: bool = True,
|
||||||
anti_spoofing: bool = False,
|
anti_spoofing: bool = False,
|
||||||
batched: bool = False,
|
batched: bool = False,
|
||||||
) -> Union[List[pd.DataFrame], List[List[Dict[str, Any]]]]:
|
) -> Union[List[pd.DataFrame], List[List[Dict[str, Any]]]]:
|
||||||
"""
|
"""
|
||||||
Identify individuals in a database
|
Identify individuals in a database
|
||||||
@ -298,8 +298,8 @@ def find(
|
|||||||
Set to False to avoid the exception for low-resolution images (default is True).
|
Set to False to avoid the exception for low-resolution images (default is True).
|
||||||
|
|
||||||
detector_backend (string): face detector backend. Options: 'opencv', 'retinaface',
|
detector_backend (string): face detector backend. Options: 'opencv', 'retinaface',
|
||||||
'mtcnn', 'ssd', 'dlib', 'mediapipe', 'yolov8', 'centerface' or 'skip'
|
'mtcnn', 'ssd', 'dlib', 'mediapipe', 'yolov8', 'yolov11n', 'yolov11s', 'yolov11m',
|
||||||
(default is opencv).
|
'centerface' or 'skip' (default is opencv).
|
||||||
|
|
||||||
align (boolean): Perform alignment based on the eye positions (default is True).
|
align (boolean): Perform alignment based on the eye positions (default is True).
|
||||||
|
|
||||||
@ -369,15 +369,15 @@ def find(
|
|||||||
|
|
||||||
|
|
||||||
def represent(
|
def represent(
|
||||||
img_path: Union[str, np.ndarray],
|
img_path: Union[str, np.ndarray],
|
||||||
model_name: str = "VGG-Face",
|
model_name: str = "VGG-Face",
|
||||||
enforce_detection: bool = True,
|
enforce_detection: bool = True,
|
||||||
detector_backend: str = "opencv",
|
detector_backend: str = "opencv",
|
||||||
align: bool = True,
|
align: bool = True,
|
||||||
expand_percentage: int = 0,
|
expand_percentage: int = 0,
|
||||||
normalization: str = "base",
|
normalization: str = "base",
|
||||||
anti_spoofing: bool = False,
|
anti_spoofing: bool = False,
|
||||||
max_faces: Optional[int] = None,
|
max_faces: Optional[int] = None,
|
||||||
) -> List[Dict[str, Any]]:
|
) -> List[Dict[str, Any]]:
|
||||||
"""
|
"""
|
||||||
Represent facial images as multi-dimensional vector embeddings.
|
Represent facial images as multi-dimensional vector embeddings.
|
||||||
@ -396,8 +396,8 @@ def represent(
|
|||||||
(default is True).
|
(default is True).
|
||||||
|
|
||||||
detector_backend (string): face detector backend. Options: 'opencv', 'retinaface',
|
detector_backend (string): face detector backend. Options: 'opencv', 'retinaface',
|
||||||
'mtcnn', 'ssd', 'dlib', 'mediapipe', 'yolov8', 'centerface' or 'skip'
|
'mtcnn', 'ssd', 'dlib', 'mediapipe', 'yolov8', 'yolov11n', 'yolov11s', 'yolov11m',
|
||||||
(default is opencv).
|
'centerface' or 'skip' (default is opencv).
|
||||||
|
|
||||||
align (boolean): Perform alignment based on the eye positions (default is True).
|
align (boolean): Perform alignment based on the eye positions (default is True).
|
||||||
|
|
||||||
@ -441,15 +441,15 @@ def represent(
|
|||||||
|
|
||||||
|
|
||||||
def stream(
|
def stream(
|
||||||
db_path: str = "",
|
db_path: str = "",
|
||||||
model_name: str = "VGG-Face",
|
model_name: str = "VGG-Face",
|
||||||
detector_backend: str = "opencv",
|
detector_backend: str = "opencv",
|
||||||
distance_metric: str = "cosine",
|
distance_metric: str = "cosine",
|
||||||
enable_face_analysis: bool = True,
|
enable_face_analysis: bool = True,
|
||||||
source: Any = 0,
|
source: Any = 0,
|
||||||
time_threshold: int = 5,
|
time_threshold: int = 5,
|
||||||
frame_threshold: int = 5,
|
frame_threshold: int = 5,
|
||||||
anti_spoofing: bool = False,
|
anti_spoofing: bool = False,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Run real time face recognition and facial attribute analysis
|
Run real time face recognition and facial attribute analysis
|
||||||
@ -462,8 +462,8 @@ def stream(
|
|||||||
OpenFace, DeepFace, DeepID, Dlib, ArcFace, SFace and GhostFaceNet (default is VGG-Face).
|
OpenFace, DeepFace, DeepID, Dlib, ArcFace, SFace and GhostFaceNet (default is VGG-Face).
|
||||||
|
|
||||||
detector_backend (string): face detector backend. Options: 'opencv', 'retinaface',
|
detector_backend (string): face detector backend. Options: 'opencv', 'retinaface',
|
||||||
'mtcnn', 'ssd', 'dlib', 'mediapipe', 'yolov8', 'centerface' or 'skip'
|
'mtcnn', 'ssd', 'dlib', 'mediapipe', 'yolov8', 'yolov11n', 'yolov11s', 'yolov11m',
|
||||||
(default is opencv).
|
'centerface' or 'skip' (default is opencv).
|
||||||
|
|
||||||
distance_metric (string): Metric for measuring similarity. Options: 'cosine',
|
distance_metric (string): Metric for measuring similarity. Options: 'cosine',
|
||||||
'euclidean', 'euclidean_l2' (default is cosine).
|
'euclidean', 'euclidean_l2' (default is cosine).
|
||||||
@ -499,15 +499,15 @@ def stream(
|
|||||||
|
|
||||||
|
|
||||||
def extract_faces(
|
def extract_faces(
|
||||||
img_path: Union[str, np.ndarray],
|
img_path: Union[str, np.ndarray],
|
||||||
detector_backend: str = "opencv",
|
detector_backend: str = "opencv",
|
||||||
enforce_detection: bool = True,
|
enforce_detection: bool = True,
|
||||||
align: bool = True,
|
align: bool = True,
|
||||||
expand_percentage: int = 0,
|
expand_percentage: int = 0,
|
||||||
grayscale: bool = False,
|
grayscale: bool = False,
|
||||||
color_face: str = "rgb",
|
color_face: str = "rgb",
|
||||||
normalize_face: bool = True,
|
normalize_face: bool = True,
|
||||||
anti_spoofing: bool = False,
|
anti_spoofing: bool = False,
|
||||||
) -> List[Dict[str, Any]]:
|
) -> List[Dict[str, Any]]:
|
||||||
"""
|
"""
|
||||||
Extract faces from a given image
|
Extract faces from a given image
|
||||||
@ -517,8 +517,8 @@ def extract_faces(
|
|||||||
as a string, numpy array (BGR), or base64 encoded images.
|
as a string, numpy array (BGR), or base64 encoded images.
|
||||||
|
|
||||||
detector_backend (string): face detector backend. Options: 'opencv', 'retinaface',
|
detector_backend (string): face detector backend. Options: 'opencv', 'retinaface',
|
||||||
'mtcnn', 'ssd', 'dlib', 'mediapipe', 'yolov8', 'centerface' or 'skip'
|
'mtcnn', 'ssd', 'dlib', 'mediapipe', 'yolov8', 'yolov11n', 'yolov11s', 'yolov11m',
|
||||||
(default is opencv).
|
'centerface' or 'skip' (default is opencv).
|
||||||
|
|
||||||
enforce_detection (boolean): If no face is detected in an image, raise an exception.
|
enforce_detection (boolean): If no face is detected in an image, raise an exception.
|
||||||
Set to False to avoid the exception for low-resolution images (default is True).
|
Set to False to avoid the exception for low-resolution images (default is True).
|
||||||
@ -584,11 +584,11 @@ def cli() -> None:
|
|||||||
|
|
||||||
|
|
||||||
def detectFace(
|
def detectFace(
|
||||||
img_path: Union[str, np.ndarray],
|
img_path: Union[str, np.ndarray],
|
||||||
target_size: tuple = (224, 224),
|
target_size: tuple = (224, 224),
|
||||||
detector_backend: str = "opencv",
|
detector_backend: str = "opencv",
|
||||||
enforce_detection: bool = True,
|
enforce_detection: bool = True,
|
||||||
align: bool = True,
|
align: bool = True,
|
||||||
) -> Union[np.ndarray, None]:
|
) -> Union[np.ndarray, None]:
|
||||||
"""
|
"""
|
||||||
Deprecated face detection function. Use extract_faces for same functionality.
|
Deprecated face detection function. Use extract_faces for same functionality.
|
||||||
@ -601,8 +601,8 @@ def detectFace(
|
|||||||
added to resize the image (default is (224, 224)).
|
added to resize the image (default is (224, 224)).
|
||||||
|
|
||||||
detector_backend (string): face detector backend. Options: 'opencv', 'retinaface',
|
detector_backend (string): face detector backend. Options: 'opencv', 'retinaface',
|
||||||
'mtcnn', 'ssd', 'dlib', 'mediapipe', 'yolov8', 'centerface' or 'skip'
|
'mtcnn', 'ssd', 'dlib', 'mediapipe', 'yolov8', 'yolov11n', 'yolov11s', 'yolov11m',
|
||||||
(default is opencv).
|
'centerface' or 'skip' (default is opencv).
|
||||||
|
|
||||||
enforce_detection (boolean): If no face is detected in an image, raise an exception.
|
enforce_detection (boolean): If no face is detected in an image, raise an exception.
|
||||||
Set to False to avoid the exception for low-resolution images (default is True).
|
Set to False to avoid the exception for low-resolution images (default is True).
|
||||||
|
@ -72,7 +72,9 @@ def extract_image_from_request(img_key: str) -> Union[str, np.ndarray]:
|
|||||||
|
|
||||||
@blueprint.route("/represent", methods=["POST"])
|
@blueprint.route("/represent", methods=["POST"])
|
||||||
def represent():
|
def represent():
|
||||||
input_args = request.get_json() or request.form.to_dict()
|
input_args = (request.is_json and request.get_json()) or (
|
||||||
|
request.form and request.form.to_dict()
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
img = extract_image_from_request("img")
|
img = extract_image_from_request("img")
|
||||||
@ -96,7 +98,9 @@ def represent():
|
|||||||
|
|
||||||
@blueprint.route("/verify", methods=["POST"])
|
@blueprint.route("/verify", methods=["POST"])
|
||||||
def verify():
|
def verify():
|
||||||
input_args = request.get_json() or request.form.to_dict()
|
input_args = (request.is_json and request.get_json()) or (
|
||||||
|
request.form and request.form.to_dict()
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
img1 = extract_image_from_request("img1")
|
img1 = extract_image_from_request("img1")
|
||||||
@ -126,7 +130,9 @@ def verify():
|
|||||||
|
|
||||||
@blueprint.route("/analyze", methods=["POST"])
|
@blueprint.route("/analyze", methods=["POST"])
|
||||||
def analyze():
|
def analyze():
|
||||||
input_args = request.get_json() or request.form.to_dict()
|
input_args = (request.is_json and request.get_json()) or (
|
||||||
|
request.form and request.form.to_dict()
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
img = extract_image_from_request("img")
|
img = extract_image_from_request("img")
|
||||||
|
@ -128,8 +128,9 @@ def download_all_models_in_one_shot() -> None:
|
|||||||
WEIGHTS_URL as SSD_WEIGHTS,
|
WEIGHTS_URL as SSD_WEIGHTS,
|
||||||
)
|
)
|
||||||
from deepface.models.face_detection.Yolo import (
|
from deepface.models.face_detection.Yolo import (
|
||||||
WEIGHT_URL as YOLOV8_WEIGHTS,
|
WEIGHT_URLS as YOLO_WEIGHTS,
|
||||||
WEIGHT_NAME as YOLOV8_WEIGHT_NAME,
|
WEIGHT_NAMES as YOLO_WEIGHT_NAMES,
|
||||||
|
YoloModel
|
||||||
)
|
)
|
||||||
from deepface.models.face_detection.YuNet import WEIGHTS_URL as YUNET_WEIGHTS
|
from deepface.models.face_detection.YuNet import WEIGHTS_URL as YUNET_WEIGHTS
|
||||||
from deepface.models.face_detection.Dlib import WEIGHTS_URL as DLIB_FD_WEIGHTS
|
from deepface.models.face_detection.Dlib import WEIGHTS_URL as DLIB_FD_WEIGHTS
|
||||||
@ -162,8 +163,20 @@ def download_all_models_in_one_shot() -> None:
|
|||||||
SSD_MODEL,
|
SSD_MODEL,
|
||||||
SSD_WEIGHTS,
|
SSD_WEIGHTS,
|
||||||
{
|
{
|
||||||
"filename": YOLOV8_WEIGHT_NAME,
|
"filename": YOLO_WEIGHT_NAMES[YoloModel.V8N.value],
|
||||||
"url": YOLOV8_WEIGHTS,
|
"url": YOLO_WEIGHTS[YoloModel.V8N.value],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": YOLO_WEIGHT_NAMES[YoloModel.V11N.value],
|
||||||
|
"url": YOLO_WEIGHTS[YoloModel.V11N.value],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": YOLO_WEIGHT_NAMES[YoloModel.V11S.value],
|
||||||
|
"url": YOLO_WEIGHTS[YoloModel.V11S.value],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": YOLO_WEIGHT_NAMES[YoloModel.V11M.value],
|
||||||
|
"url": YOLO_WEIGHTS[YoloModel.V11M.value],
|
||||||
},
|
},
|
||||||
YUNET_WEIGHTS,
|
YUNET_WEIGHTS,
|
||||||
DLIB_FD_WEIGHTS,
|
DLIB_FD_WEIGHTS,
|
||||||
|
@ -46,7 +46,7 @@ class CenterFaceClient(Detector):
|
|||||||
"""
|
"""
|
||||||
resp = []
|
resp = []
|
||||||
|
|
||||||
threshold = float(os.getenv("CENTERFACE_THRESHOLD", "0.80"))
|
threshold = float(os.getenv("CENTERFACE_THRESHOLD", "0.35"))
|
||||||
|
|
||||||
# BUG: model causes problematic results from 2nd call if it is not flushed
|
# BUG: model causes problematic results from 2nd call if it is not flushed
|
||||||
# detections, landmarks = self.model.forward(
|
# detections, landmarks = self.model.forward(
|
||||||
|
@ -92,4 +92,4 @@ def xyxy_to_xywh(regions: Union[list, tuple]) -> tuple:
|
|||||||
x, y, x_plus_w, y_plus_h = regions[0], regions[1], regions[2], regions[3]
|
x, y, x_plus_w, y_plus_h = regions[0], regions[1], regions[2], regions[3]
|
||||||
w = x_plus_w - x
|
w = x_plus_w - x
|
||||||
h = y_plus_h - y
|
h = y_plus_h - y
|
||||||
return (x, y, w, h)
|
return (int(x), int(y), int(w), int(h))
|
||||||
|
@ -1,29 +1,45 @@
|
|||||||
# built-in dependencies
|
# built-in dependencies
|
||||||
import os
|
import os
|
||||||
from typing import Any, List
|
from typing import List, Any
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
# 3rd party dependencies
|
# 3rd party dependencies
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
# project dependencies
|
# project dependencies
|
||||||
from deepface.models.Detector import Detector, FacialAreaRegion
|
from deepface.models.Detector import Detector, FacialAreaRegion
|
||||||
from deepface.commons import weight_utils
|
|
||||||
from deepface.commons.logger import Logger
|
from deepface.commons.logger import Logger
|
||||||
|
from deepface.commons import weight_utils
|
||||||
|
|
||||||
logger = Logger()
|
logger = Logger()
|
||||||
|
|
||||||
|
|
||||||
|
class YoloModel(Enum):
|
||||||
|
V8N = 0
|
||||||
|
V11N = 1
|
||||||
|
V11S = 2
|
||||||
|
V11M = 3
|
||||||
|
|
||||||
|
|
||||||
# Model's weights paths
|
# Model's weights paths
|
||||||
WEIGHT_NAME = "yolov8n-face.pt"
|
WEIGHT_NAMES = ["yolov8n-face.pt",
|
||||||
|
"yolov11n-face.pt",
|
||||||
|
"yolov11s-face.pt",
|
||||||
|
"yolov11m-face.pt"]
|
||||||
|
|
||||||
# Google Drive URL from repo (https://github.com/derronqi/yolov8-face) ~6MB
|
# Google Drive URL from repo (https://github.com/derronqi/yolov8-face) ~6MB
|
||||||
WEIGHT_URL = "https://drive.google.com/uc?id=1qcr9DbgsX3ryrz2uU8w4Xm3cOrRywXqb"
|
WEIGHT_URLS = ["https://drive.google.com/uc?id=1qcr9DbgsX3ryrz2uU8w4Xm3cOrRywXqb",
|
||||||
|
"https://github.com/akanametov/yolo-face/releases/download/v0.0.0/yolov11n-face.pt",
|
||||||
|
"https://github.com/akanametov/yolo-face/releases/download/v0.0.0/yolov11s-face.pt",
|
||||||
|
"https://github.com/akanametov/yolo-face/releases/download/v0.0.0/yolov11m-face.pt"]
|
||||||
|
|
||||||
|
|
||||||
class YoloClient(Detector):
|
class YoloDetectorClient(Detector):
|
||||||
def __init__(self):
|
def __init__(self, model: YoloModel):
|
||||||
self.model = self.build_model()
|
super().__init__()
|
||||||
|
self.model = self.build_model(model)
|
||||||
|
|
||||||
def build_model(self) -> Any:
|
def build_model(self, model: YoloModel) -> Any:
|
||||||
"""
|
"""
|
||||||
Build a yolo detector model
|
Build a yolo detector model
|
||||||
Returns:
|
Returns:
|
||||||
@ -40,7 +56,7 @@ class YoloClient(Detector):
|
|||||||
) from e
|
) from e
|
||||||
|
|
||||||
weight_file = weight_utils.download_weights_if_necessary(
|
weight_file = weight_utils.download_weights_if_necessary(
|
||||||
file_name=WEIGHT_NAME, source_url=WEIGHT_URL
|
file_name=WEIGHT_NAMES[model.value], source_url=WEIGHT_URLS[model.value]
|
||||||
)
|
)
|
||||||
|
|
||||||
# Return face_detector
|
# Return face_detector
|
||||||
@ -69,21 +85,27 @@ class YoloClient(Detector):
|
|||||||
# For each face, extract the bounding box, the landmarks and confidence
|
# For each face, extract the bounding box, the landmarks and confidence
|
||||||
for result in results:
|
for result in results:
|
||||||
|
|
||||||
if result.boxes is None or result.keypoints is None:
|
if result.boxes is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Extract the bounding box and the confidence
|
# Extract the bounding box and the confidence
|
||||||
x, y, w, h = result.boxes.xywh.tolist()[0]
|
x, y, w, h = result.boxes.xywh.tolist()[0]
|
||||||
confidence = result.boxes.conf.tolist()[0]
|
confidence = result.boxes.conf.tolist()[0]
|
||||||
|
|
||||||
# right_eye_conf = result.keypoints.conf[0][0]
|
right_eye = None
|
||||||
# left_eye_conf = result.keypoints.conf[0][1]
|
left_eye = None
|
||||||
right_eye = result.keypoints.xy[0][0].tolist()
|
|
||||||
left_eye = result.keypoints.xy[0][1].tolist()
|
|
||||||
|
|
||||||
# eyes are list of float, need to cast them tuple of int
|
# yolo-facev8 is detecting eyes through keypoints,
|
||||||
left_eye = tuple(int(i) for i in left_eye)
|
# while for v11 keypoints are always None
|
||||||
right_eye = tuple(int(i) for i in right_eye)
|
if result.keypoints is not None:
|
||||||
|
# right_eye_conf = result.keypoints.conf[0][0]
|
||||||
|
# left_eye_conf = result.keypoints.conf[0][1]
|
||||||
|
right_eye = result.keypoints.xy[0][0].tolist()
|
||||||
|
left_eye = result.keypoints.xy[0][1].tolist()
|
||||||
|
|
||||||
|
# eyes are list of float, need to cast them tuple of int
|
||||||
|
left_eye = tuple(int(i) for i in left_eye)
|
||||||
|
right_eye = tuple(int(i) for i in right_eye)
|
||||||
|
|
||||||
x, y, w, h = int(x - w / 2), int(y - h / 2), int(w), int(h)
|
x, y, w, h = int(x - w / 2), int(y - h / 2), int(w), int(h)
|
||||||
facial_area = FacialAreaRegion(
|
facial_area = FacialAreaRegion(
|
||||||
@ -98,3 +120,23 @@ class YoloClient(Detector):
|
|||||||
resp.append(facial_area)
|
resp.append(facial_area)
|
||||||
|
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
|
|
||||||
|
class YoloDetectorClientV8n(YoloDetectorClient):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__(YoloModel.V8N)
|
||||||
|
|
||||||
|
|
||||||
|
class YoloDetectorClientV11n(YoloDetectorClient):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__(YoloModel.V11N)
|
||||||
|
|
||||||
|
|
||||||
|
class YoloDetectorClientV11s(YoloDetectorClient):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__(YoloModel.V11S)
|
||||||
|
|
||||||
|
|
||||||
|
class YoloDetectorClientV11m(YoloDetectorClient):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__(YoloModel.V11M)
|
||||||
|
@ -64,7 +64,7 @@ class FaceNet128dClient(FacialRecognition):
|
|||||||
|
|
||||||
class FaceNet512dClient(FacialRecognition):
|
class FaceNet512dClient(FacialRecognition):
|
||||||
"""
|
"""
|
||||||
FaceNet-1512d model class
|
FaceNet-512d model class
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -35,8 +35,8 @@ def analyze(
|
|||||||
Set to False to avoid the exception for low-resolution images (default is True).
|
Set to False to avoid the exception for low-resolution images (default is True).
|
||||||
|
|
||||||
detector_backend (string): face detector backend. Options: 'opencv', 'retinaface',
|
detector_backend (string): face detector backend. Options: 'opencv', 'retinaface',
|
||||||
'mtcnn', 'ssd', 'dlib', 'mediapipe', 'yolov8', 'centerface' or 'skip'
|
'mtcnn', 'ssd', 'dlib', 'mediapipe', 'yolov8', 'yolov11n', 'yolov11s', 'yolov11m',
|
||||||
(default is opencv).
|
'centerface' or 'skip' (default is opencv).
|
||||||
|
|
||||||
distance_metric (string): Metric for measuring similarity. Options: 'cosine',
|
distance_metric (string): Metric for measuring similarity. Options: 'cosine',
|
||||||
'euclidean', 'euclidean_l2' (default is cosine).
|
'euclidean', 'euclidean_l2' (default is cosine).
|
||||||
|
@ -38,8 +38,8 @@ def extract_faces(
|
|||||||
as a string, numpy array (BGR), or base64 encoded images.
|
as a string, numpy array (BGR), or base64 encoded images.
|
||||||
|
|
||||||
detector_backend (string): face detector backend. Options: 'opencv', 'retinaface',
|
detector_backend (string): face detector backend. Options: 'opencv', 'retinaface',
|
||||||
'mtcnn', 'ssd', 'dlib', 'mediapipe', 'yolov8', 'centerface' or 'skip'
|
'mtcnn', 'ssd', 'dlib', 'mediapipe', 'yolov8', 'yolov11n', 'yolov11s', 'yolov11m',
|
||||||
(default is opencv)
|
'centerface' or 'skip' (default is opencv)
|
||||||
|
|
||||||
enforce_detection (boolean): If no face is detected in an image, raise an exception.
|
enforce_detection (boolean): If no face is detected in an image, raise an exception.
|
||||||
Default is True. Set to False to avoid the exception for low-resolution images.
|
Default is True. Set to False to avoid the exception for low-resolution images.
|
||||||
@ -255,7 +255,7 @@ def detect_faces(
|
|||||||
)
|
)
|
||||||
|
|
||||||
return [
|
return [
|
||||||
expand_and_align_face(
|
extract_face(
|
||||||
facial_area=facial_area,
|
facial_area=facial_area,
|
||||||
img=img,
|
img=img,
|
||||||
align=align,
|
align=align,
|
||||||
@ -267,7 +267,7 @@ def detect_faces(
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def expand_and_align_face(
|
def extract_face(
|
||||||
facial_area: FacialAreaRegion,
|
facial_area: FacialAreaRegion,
|
||||||
img: np.ndarray,
|
img: np.ndarray,
|
||||||
align: bool,
|
align: bool,
|
||||||
@ -301,15 +301,32 @@ def expand_and_align_face(
|
|||||||
detected_face = img[int(y) : int(y + h), int(x) : int(x + w)]
|
detected_face = img[int(y) : int(y + h), int(x) : int(x + w)]
|
||||||
# align original image, then find projection of detected face area after alignment
|
# align original image, then find projection of detected face area after alignment
|
||||||
if align is True: # and left_eye is not None and right_eye is not None:
|
if align is True: # and left_eye is not None and right_eye is not None:
|
||||||
aligned_img, angle = align_img_wrt_eyes(img=img, left_eye=left_eye, right_eye=right_eye)
|
# we were aligning the original image before, but this comes with an extra cost
|
||||||
|
# instead we now focus on the facial area with a margin
|
||||||
|
# and align it instead of original image to decrese the cost
|
||||||
|
sub_img, relative_x, relative_y = extract_sub_image(img=img, facial_area=(x, y, w, h))
|
||||||
|
|
||||||
|
aligned_sub_img, angle = align_img_wrt_eyes(
|
||||||
|
img=sub_img, left_eye=left_eye, right_eye=right_eye
|
||||||
|
)
|
||||||
|
|
||||||
rotated_x1, rotated_y1, rotated_x2, rotated_y2 = project_facial_area(
|
rotated_x1, rotated_y1, rotated_x2, rotated_y2 = project_facial_area(
|
||||||
facial_area=(x, y, x + w, y + h), angle=angle, size=(img.shape[0], img.shape[1])
|
facial_area=(
|
||||||
|
relative_x,
|
||||||
|
relative_y,
|
||||||
|
relative_x + w,
|
||||||
|
relative_y + h,
|
||||||
|
),
|
||||||
|
angle=angle,
|
||||||
|
size=(sub_img.shape[0], sub_img.shape[1]),
|
||||||
)
|
)
|
||||||
detected_face = aligned_img[
|
detected_face = aligned_sub_img[
|
||||||
int(rotated_y1) : int(rotated_y2), int(rotated_x1) : int(rotated_x2)
|
int(rotated_y1) : int(rotated_y2), int(rotated_x1) : int(rotated_x2)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# do not spend memory for these temporary variables anymore
|
||||||
|
del aligned_sub_img, sub_img
|
||||||
|
|
||||||
# restore x, y, le and re before border added
|
# restore x, y, le and re before border added
|
||||||
x = x - width_border
|
x = x - width_border
|
||||||
y = y - height_border
|
y = y - height_border
|
||||||
@ -339,14 +356,66 @@ def expand_and_align_face(
|
|||||||
mouth_left=mouth_left,
|
mouth_left=mouth_left,
|
||||||
mouth_right=mouth_right,
|
mouth_right=mouth_right,
|
||||||
),
|
),
|
||||||
confidence=confidence,
|
confidence=confidence or 0,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def extract_sub_image(
|
||||||
|
img: np.ndarray, facial_area: Tuple[int, int, int, int]
|
||||||
|
) -> Tuple[np.ndarray, int, int]:
|
||||||
|
"""
|
||||||
|
Get the sub image with given facial area while expanding the facial region
|
||||||
|
to ensure alignment does not shift the face outside the image.
|
||||||
|
|
||||||
|
This function doubles the height and width of the face region,
|
||||||
|
and adds black pixels if necessary.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
- img (np.ndarray): pre-loaded image with detected face
|
||||||
|
- facial_area (tuple of int): Representing the (x, y, w, h) of the facial area.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
- extracted_face (np.ndarray): expanded facial image
|
||||||
|
- relative_x (int): adjusted x-coordinates relative to the expanded region
|
||||||
|
- relative_y (int): adjusted y-coordinates relative to the expanded region
|
||||||
|
"""
|
||||||
|
x, y, w, h = facial_area
|
||||||
|
relative_x = int(0.5 * w)
|
||||||
|
relative_y = int(0.5 * h)
|
||||||
|
|
||||||
|
# calculate expanded coordinates
|
||||||
|
x1, y1 = x - relative_x, y - relative_y
|
||||||
|
x2, y2 = x + w + relative_x, y + h + relative_y
|
||||||
|
|
||||||
|
# most of the time, the expanded region fits inside the image
|
||||||
|
if x1 >= 0 and y1 >= 0 and x2 <= img.shape[1] and y2 <= img.shape[0]:
|
||||||
|
return img[y1:y2, x1:x2], relative_x, relative_y
|
||||||
|
|
||||||
|
# but sometimes, we need to add black pixels
|
||||||
|
# ensure the coordinates are within bounds
|
||||||
|
x1, y1 = max(0, x1), max(0, y1)
|
||||||
|
x2, y2 = min(img.shape[1], x2), min(img.shape[0], y2)
|
||||||
|
cropped_region = img[y1:y2, x1:x2]
|
||||||
|
|
||||||
|
# create a black image
|
||||||
|
extracted_face = np.zeros(
|
||||||
|
(h + 2 * relative_y, w + 2 * relative_x, img.shape[2]), dtype=img.dtype
|
||||||
|
)
|
||||||
|
|
||||||
|
# map the cropped region
|
||||||
|
start_x = max(0, relative_x - x)
|
||||||
|
start_y = max(0, relative_y - y)
|
||||||
|
extracted_face[
|
||||||
|
start_y : start_y + cropped_region.shape[0], start_x : start_x + cropped_region.shape[1]
|
||||||
|
] = cropped_region
|
||||||
|
|
||||||
|
return extracted_face, relative_x, relative_y
|
||||||
|
|
||||||
|
|
||||||
def align_img_wrt_eyes(
|
def align_img_wrt_eyes(
|
||||||
img: np.ndarray,
|
img: np.ndarray,
|
||||||
left_eye: Union[list, tuple],
|
left_eye: Optional[Union[list, tuple]],
|
||||||
right_eye: Union[list, tuple],
|
right_eye: Optional[Union[list, tuple]],
|
||||||
) -> Tuple[np.ndarray, float]:
|
) -> Tuple[np.ndarray, float]:
|
||||||
"""
|
"""
|
||||||
Align a given image horizantally with respect to their left and right eye locations
|
Align a given image horizantally with respect to their left and right eye locations
|
||||||
|
@ -11,7 +11,7 @@ from deepface.models.facial_recognition import (
|
|||||||
SFace,
|
SFace,
|
||||||
Dlib,
|
Dlib,
|
||||||
Facenet,
|
Facenet,
|
||||||
GhostFaceNet,
|
GhostFaceNet
|
||||||
)
|
)
|
||||||
from deepface.models.face_detection import (
|
from deepface.models.face_detection import (
|
||||||
FastMtCnn,
|
FastMtCnn,
|
||||||
@ -21,7 +21,7 @@ from deepface.models.face_detection import (
|
|||||||
Dlib as DlibDetector,
|
Dlib as DlibDetector,
|
||||||
RetinaFace,
|
RetinaFace,
|
||||||
Ssd,
|
Ssd,
|
||||||
Yolo,
|
Yolo as YoloFaceDetector,
|
||||||
YuNet,
|
YuNet,
|
||||||
CenterFace,
|
CenterFace,
|
||||||
)
|
)
|
||||||
@ -36,10 +36,10 @@ def build_model(task: str, model_name: str) -> Any:
|
|||||||
task (str): facial_recognition, facial_attribute, face_detector, spoofing
|
task (str): facial_recognition, facial_attribute, face_detector, spoofing
|
||||||
model_name (str): model identifier
|
model_name (str): model identifier
|
||||||
- VGG-Face, Facenet, Facenet512, OpenFace, DeepFace, DeepID, Dlib,
|
- VGG-Face, Facenet, Facenet512, OpenFace, DeepFace, DeepID, Dlib,
|
||||||
ArcFace, SFace, GhostFaceNet for face recognition
|
ArcFace, SFace and GhostFaceNet for face recognition
|
||||||
- Age, Gender, Emotion, Race for facial attributes
|
- Age, Gender, Emotion, Race for facial attributes
|
||||||
- opencv, mtcnn, ssd, dlib, retinaface, mediapipe, yolov8, yunet,
|
- opencv, mtcnn, ssd, dlib, retinaface, mediapipe, yolov8, 'yolov11n',
|
||||||
fastmtcnn or centerface for face detectors
|
'yolov11s', 'yolov11m', yunet, fastmtcnn or centerface for face detectors
|
||||||
- Fasnet for spoofing
|
- Fasnet for spoofing
|
||||||
Returns:
|
Returns:
|
||||||
built model class
|
built model class
|
||||||
@ -59,7 +59,7 @@ def build_model(task: str, model_name: str) -> Any:
|
|||||||
"Dlib": Dlib.DlibClient,
|
"Dlib": Dlib.DlibClient,
|
||||||
"ArcFace": ArcFace.ArcFaceClient,
|
"ArcFace": ArcFace.ArcFaceClient,
|
||||||
"SFace": SFace.SFaceClient,
|
"SFace": SFace.SFaceClient,
|
||||||
"GhostFaceNet": GhostFaceNet.GhostFaceNetClient,
|
"GhostFaceNet": GhostFaceNet.GhostFaceNetClient
|
||||||
},
|
},
|
||||||
"spoofing": {
|
"spoofing": {
|
||||||
"Fasnet": FasNet.Fasnet,
|
"Fasnet": FasNet.Fasnet,
|
||||||
@ -77,7 +77,10 @@ def build_model(task: str, model_name: str) -> Any:
|
|||||||
"dlib": DlibDetector.DlibClient,
|
"dlib": DlibDetector.DlibClient,
|
||||||
"retinaface": RetinaFace.RetinaFaceClient,
|
"retinaface": RetinaFace.RetinaFaceClient,
|
||||||
"mediapipe": MediaPipe.MediaPipeClient,
|
"mediapipe": MediaPipe.MediaPipeClient,
|
||||||
"yolov8": Yolo.YoloClient,
|
"yolov8": YoloFaceDetector.YoloDetectorClientV8n,
|
||||||
|
"yolov11n": YoloFaceDetector.YoloDetectorClientV11n,
|
||||||
|
"yolov11s": YoloFaceDetector.YoloDetectorClientV11s,
|
||||||
|
"yolov11m": YoloFaceDetector.YoloDetectorClientV11m,
|
||||||
"yunet": YuNet.YuNetClient,
|
"yunet": YuNet.YuNetClient,
|
||||||
"fastmtcnn": FastMtCnn.FastMtCnnClient,
|
"fastmtcnn": FastMtCnn.FastMtCnnClient,
|
||||||
"centerface": CenterFace.CenterFaceClient,
|
"centerface": CenterFace.CenterFaceClient,
|
||||||
|
@ -54,7 +54,8 @@ def find(
|
|||||||
Default is True. Set to False to avoid the exception for low-resolution images.
|
Default is True. Set to False to avoid the exception for low-resolution images.
|
||||||
|
|
||||||
detector_backend (string): face detector backend. Options: 'opencv', 'retinaface',
|
detector_backend (string): face detector backend. Options: 'opencv', 'retinaface',
|
||||||
'mtcnn', 'ssd', 'dlib', 'mediapipe', 'yolov8', 'centerface' or 'skip'.
|
'mtcnn', 'ssd', 'dlib', 'mediapipe', 'yolov8','yolov11n', 'yolov11s',
|
||||||
|
'yolov11m', 'centerface' or 'skip'.
|
||||||
|
|
||||||
align (boolean): Perform alignment based on the eye positions.
|
align (boolean): Perform alignment based on the eye positions.
|
||||||
|
|
||||||
@ -483,7 +484,8 @@ def find_batched(
|
|||||||
Default is True. Set to False to avoid the exception for low-resolution images.
|
Default is True. Set to False to avoid the exception for low-resolution images.
|
||||||
|
|
||||||
detector_backend (string): face detector backend. Options: 'opencv', 'retinaface',
|
detector_backend (string): face detector backend. Options: 'opencv', 'retinaface',
|
||||||
'mtcnn', 'ssd', 'dlib', 'mediapipe', 'yolov8', 'centerface' or 'skip'.
|
'mtcnn', 'ssd', 'dlib', 'mediapipe', 'yolov8', 'yolov11n', 'yolov11s',
|
||||||
|
'yolov11m', 'centerface' or 'skip'.
|
||||||
|
|
||||||
align (boolean): Perform alignment based on the eye positions.
|
align (boolean): Perform alignment based on the eye positions.
|
||||||
|
|
||||||
|
@ -36,7 +36,8 @@ def represent(
|
|||||||
Default is True. Set to False to avoid the exception for low-resolution images.
|
Default is True. Set to False to avoid the exception for low-resolution images.
|
||||||
|
|
||||||
detector_backend (string): face detector backend. Options: 'opencv', 'retinaface',
|
detector_backend (string): face detector backend. Options: 'opencv', 'retinaface',
|
||||||
'mtcnn', 'ssd', 'dlib', 'mediapipe', 'yolov8', 'centerface' or 'skip'.
|
'mtcnn', 'ssd', 'dlib', 'mediapipe', 'yolov8', 'yolov11n', 'yolov11s',
|
||||||
|
'yolov11m', 'centerface' or 'skip'.
|
||||||
|
|
||||||
align (boolean): Perform alignment based on the eye positions.
|
align (boolean): Perform alignment based on the eye positions.
|
||||||
|
|
||||||
@ -115,7 +116,7 @@ def represent(
|
|||||||
raise ValueError("Spoof detected in the given image.")
|
raise ValueError("Spoof detected in the given image.")
|
||||||
img = img_obj["face"]
|
img = img_obj["face"]
|
||||||
|
|
||||||
# rgb to bgr
|
# bgr to rgb
|
||||||
img = img[:, :, ::-1]
|
img = img[:, :, ::-1]
|
||||||
|
|
||||||
region = img_obj["facial_area"]
|
region = img_obj["facial_area"]
|
||||||
|
@ -42,11 +42,11 @@ def analysis(
|
|||||||
in the database will be considered in the decision-making process.
|
in the database will be considered in the decision-making process.
|
||||||
|
|
||||||
model_name (str): Model for face recognition. Options: VGG-Face, Facenet, Facenet512,
|
model_name (str): Model for face recognition. Options: VGG-Face, Facenet, Facenet512,
|
||||||
OpenFace, DeepFace, DeepID, Dlib, ArcFace, SFace and GhostFaceNet (default is VGG-Face).
|
OpenFace, DeepFace, DeepID, Dlib, ArcFace, SFace and GhostFaceNet (default is VGG-Face)
|
||||||
|
|
||||||
detector_backend (string): face detector backend. Options: 'opencv', 'retinaface',
|
detector_backend (string): face detector backend. Options: 'opencv', 'retinaface',
|
||||||
'mtcnn', 'ssd', 'dlib', 'mediapipe', 'yolov8', 'centerface' or 'skip'
|
'mtcnn', 'ssd', 'dlib', 'mediapipe', 'yolov8', 'yolov11n', 'yolov11s', 'yolov11m',
|
||||||
(default is opencv).
|
'centerface' or 'skip' (default is opencv).
|
||||||
|
|
||||||
distance_metric (string): Metric for measuring similarity. Options: 'cosine',
|
distance_metric (string): Metric for measuring similarity. Options: 'cosine',
|
||||||
'euclidean', 'euclidean_l2' (default is cosine).
|
'euclidean', 'euclidean_l2' (default is cosine).
|
||||||
@ -192,8 +192,8 @@ def search_identity(
|
|||||||
model_name (str): Model for face recognition. Options: VGG-Face, Facenet, Facenet512,
|
model_name (str): Model for face recognition. Options: VGG-Face, Facenet, Facenet512,
|
||||||
OpenFace, DeepFace, DeepID, Dlib, ArcFace, SFace and GhostFaceNet (default is VGG-Face).
|
OpenFace, DeepFace, DeepID, Dlib, ArcFace, SFace and GhostFaceNet (default is VGG-Face).
|
||||||
detector_backend (string): face detector backend. Options: 'opencv', 'retinaface',
|
detector_backend (string): face detector backend. Options: 'opencv', 'retinaface',
|
||||||
'mtcnn', 'ssd', 'dlib', 'mediapipe', 'yolov8', 'centerface' or 'skip'
|
'mtcnn', 'ssd', 'dlib', 'mediapipe', 'yolov8', 'yolov11n', 'yolov11s', 'yolov11m',
|
||||||
(default is opencv).
|
'centerface' or 'skip' (default is opencv).
|
||||||
distance_metric (string): Metric for measuring similarity. Options: 'cosine',
|
distance_metric (string): Metric for measuring similarity. Options: 'cosine',
|
||||||
'euclidean', 'euclidean_l2' (default is cosine).
|
'euclidean', 'euclidean_l2' (default is cosine).
|
||||||
Returns:
|
Returns:
|
||||||
@ -374,8 +374,8 @@ def grab_facial_areas(
|
|||||||
Args:
|
Args:
|
||||||
img (np.ndarray): image itself
|
img (np.ndarray): image itself
|
||||||
detector_backend (string): face detector backend. Options: 'opencv', 'retinaface',
|
detector_backend (string): face detector backend. Options: 'opencv', 'retinaface',
|
||||||
'mtcnn', 'ssd', 'dlib', 'mediapipe', 'yolov8', 'centerface' or 'skip'
|
'mtcnn', 'ssd', 'dlib', 'mediapipe', 'yolov8', 'yolov11n', 'yolov11s', 'yolov11m',
|
||||||
(default is opencv).
|
'centerface' or 'skip' (default is opencv).
|
||||||
threshold (int): threshold for facial area, discard smaller ones
|
threshold (int): threshold for facial area, discard smaller ones
|
||||||
Returns
|
Returns
|
||||||
result (list): list of tuple with x, y, w and h coordinates
|
result (list): list of tuple with x, y, w and h coordinates
|
||||||
@ -443,8 +443,8 @@ def perform_facial_recognition(
|
|||||||
db_path (string): Path to the folder containing image files. All detected faces
|
db_path (string): Path to the folder containing image files. All detected faces
|
||||||
in the database will be considered in the decision-making process.
|
in the database will be considered in the decision-making process.
|
||||||
detector_backend (string): face detector backend. Options: 'opencv', 'retinaface',
|
detector_backend (string): face detector backend. Options: 'opencv', 'retinaface',
|
||||||
'mtcnn', 'ssd', 'dlib', 'mediapipe', 'yolov8', 'centerface' or 'skip'
|
'mtcnn', 'ssd', 'dlib', 'mediapipe', 'yolov8', 'yolov11n', 'yolov11s',
|
||||||
(default is opencv).
|
'yolov11m', 'centerface' or 'skip' (default is opencv).
|
||||||
distance_metric (string): Metric for measuring similarity. Options: 'cosine',
|
distance_metric (string): Metric for measuring similarity. Options: 'cosine',
|
||||||
'euclidean', 'euclidean_l2' (default is cosine).
|
'euclidean', 'euclidean_l2' (default is cosine).
|
||||||
model_name (str): Model for face recognition. Options: VGG-Face, Facenet, Facenet512,
|
model_name (str): Model for face recognition. Options: VGG-Face, Facenet, Facenet512,
|
||||||
|
@ -47,8 +47,8 @@ def verify(
|
|||||||
OpenFace, DeepFace, DeepID, Dlib, ArcFace, SFace and GhostFaceNet (default is VGG-Face).
|
OpenFace, DeepFace, DeepID, Dlib, ArcFace, SFace and GhostFaceNet (default is VGG-Face).
|
||||||
|
|
||||||
detector_backend (string): face detector backend. Options: 'opencv', 'retinaface',
|
detector_backend (string): face detector backend. Options: 'opencv', 'retinaface',
|
||||||
'mtcnn', 'ssd', 'dlib', 'mediapipe', 'yolov8', 'centerface' or 'skip'
|
'mtcnn', 'ssd', 'dlib', 'mediapipe', 'yolov8', 'yolov11n', 'yolov11s', 'yolov11m',
|
||||||
(default is opencv)
|
'centerface' or 'skip' (default is opencv)
|
||||||
|
|
||||||
distance_metric (string): Metric for measuring similarity. Options: 'cosine',
|
distance_metric (string): Metric for measuring similarity. Options: 'cosine',
|
||||||
'euclidean', 'euclidean_l2' (default is cosine).
|
'euclidean', 'euclidean_l2' (default is cosine).
|
||||||
|
@ -119,25 +119,31 @@ def image_to_base64(image_path):
|
|||||||
|
|
||||||
|
|
||||||
def test_facial_coordinates_are_in_borders():
|
def test_facial_coordinates_are_in_borders():
|
||||||
|
detectors = ["retinaface", "mtcnn"]
|
||||||
|
expected_faces = [7, 6]
|
||||||
|
|
||||||
img_path = "dataset/selfie-many-people.jpg"
|
img_path = "dataset/selfie-many-people.jpg"
|
||||||
img = cv2.imread(img_path)
|
img = cv2.imread(img_path)
|
||||||
height, width, _ = img.shape
|
height, width, _ = img.shape
|
||||||
|
|
||||||
results = DeepFace.extract_faces(img_path=img_path)
|
for i, detector_backend in enumerate(detectors):
|
||||||
|
results = DeepFace.extract_faces(img_path=img_path, detector_backend=detector_backend)
|
||||||
|
|
||||||
assert len(results) > 0
|
# this is a hard example, mtcnn can detect 6 and retinaface can detect 7 faces
|
||||||
|
# be sure all those faces detected. any change in detection module can break this.
|
||||||
|
assert len(results) == expected_faces[i]
|
||||||
|
|
||||||
for result in results:
|
for result in results:
|
||||||
facial_area = result["facial_area"]
|
facial_area = result["facial_area"]
|
||||||
|
|
||||||
x = facial_area["x"]
|
x = facial_area["x"]
|
||||||
y = facial_area["y"]
|
y = facial_area["y"]
|
||||||
w = facial_area["w"]
|
w = facial_area["w"]
|
||||||
h = facial_area["h"]
|
h = facial_area["h"]
|
||||||
|
|
||||||
assert x >= 0
|
assert x >= 0
|
||||||
assert y >= 0
|
assert y >= 0
|
||||||
assert x + w < width
|
assert x + w < width
|
||||||
assert y + h < height
|
assert y + h < height
|
||||||
|
|
||||||
logger.info("✅ facial area coordinates are all in image borders")
|
logger.info(f"✅ facial area coordinates are all in image borders for {detector_backend}")
|
||||||
|
@ -21,7 +21,7 @@ model_names = [
|
|||||||
"Dlib",
|
"Dlib",
|
||||||
"ArcFace",
|
"ArcFace",
|
||||||
"SFace",
|
"SFace",
|
||||||
"GhostFaceNet",
|
"GhostFaceNet"
|
||||||
]
|
]
|
||||||
|
|
||||||
detector_backends = [
|
detector_backends = [
|
||||||
@ -34,6 +34,9 @@ detector_backends = [
|
|||||||
"retinaface",
|
"retinaface",
|
||||||
"yunet",
|
"yunet",
|
||||||
"yolov8",
|
"yolov8",
|
||||||
|
"yolov11n",
|
||||||
|
"yolov11s",
|
||||||
|
"yolov11m",
|
||||||
"centerface",
|
"centerface",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user