mirror of
https://github.com/serengil/deepface.git
synced 2025-06-05 19:15:23 +00:00
open issues
This commit is contained in:
parent
64d33717a9
commit
8497682171
41
CITATION.md
Normal file
41
CITATION.md
Normal file
@ -0,0 +1,41 @@
|
||||
## Cite DeepFace Papers
|
||||
|
||||
Please cite deepface in your publications if it helps your research. Here are its BibTex entries:
|
||||
|
||||
### Facial Recognition
|
||||
|
||||
If you use deepface in your research for facial recogntion purposes, please cite the this publication.
|
||||
|
||||
```BibTeX
|
||||
@inproceedings{serengil2020lightface,
|
||||
title = {LightFace: A Hybrid Deep Face Recognition Framework},
|
||||
author = {Serengil, Sefik Ilkin and Ozpinar, Alper},
|
||||
booktitle = {2020 Innovations in Intelligent Systems and Applications Conference (ASYU)},
|
||||
pages = {23-27},
|
||||
year = {2020},
|
||||
doi = {10.1109/ASYU50717.2020.9259802},
|
||||
url = {https://doi.org/10.1109/ASYU50717.2020.9259802},
|
||||
organization = {IEEE}
|
||||
}
|
||||
```
|
||||
|
||||
### Facial Attribute Analysis
|
||||
|
||||
If you use deepface in your research for facial attribute analysis purposes such as age, gender, emotion or ethnicity prediction or face detection purposes, please cite the this publication.
|
||||
|
||||
```BibTeX
|
||||
@inproceedings{serengil2021lightface,
|
||||
title = {HyperExtended LightFace: A Facial Attribute Analysis Framework},
|
||||
author = {Serengil, Sefik Ilkin and Ozpinar, Alper},
|
||||
booktitle = {2021 International Conference on Engineering and Emerging Technologies (ICEET)},
|
||||
pages = {1-4},
|
||||
year = {2021},
|
||||
doi = {10.1109/ICEET53442.2021.9659697},
|
||||
url = {https://doi.org/10.1109/ICEET53442.2021.9659697},
|
||||
organization = {IEEE}
|
||||
}
|
||||
```
|
||||
|
||||
### Repositories
|
||||
|
||||
Also, if you use deepface in your GitHub projects, please add `deepface` in the `requirements.txt`. Thereafter, your project will be listed in its [dependency graph](https://github.com/serengil/deepface/network/dependents).
|
@ -19,10 +19,10 @@ RUN apt-get install ffmpeg libsm6 libxext6 -y
|
||||
# -----------------------------------
|
||||
# Copy required files from repo into image
|
||||
COPY ./deepface /app/deepface
|
||||
COPY ./api/app.py /app/
|
||||
COPY ./api/api.py /app/
|
||||
COPY ./api/routes.py /app/
|
||||
COPY ./api/service.py /app/
|
||||
COPY ./api/src/app.py /app/
|
||||
COPY ./api/src/api.py /app/
|
||||
COPY ./api/src/routes.py /app/
|
||||
COPY ./api/src/service.py /app/
|
||||
COPY ./requirements.txt /app/
|
||||
COPY ./setup.py /app/
|
||||
COPY ./README.md /app/
|
||||
|
@ -289,7 +289,7 @@ cd scripts
|
||||
|
||||
<p align="center"><img src="https://raw.githubusercontent.com/serengil/deepface/master/icon/deepface-api.jpg" width="90%" height="90%"></p>
|
||||
|
||||
Face recognition, facial attribute analysis and vector representation functions are covered in the API. You are expected to call these functions as http post methods. Default service endpoints will be `http://localhost:5000/verify` for face recognition, `http://localhost:5000/analyze` for facial attribute analysis, and `http://localhost:5000/represent` for vector representation. You can pass input images as exact image paths on your environment, base64 encoded strings or images on web. [Here](https://github.com/serengil/deepface/tree/master/api), you can find a postman project to find out how these methods should be called.
|
||||
Face recognition, facial attribute analysis and vector representation functions are covered in the API. You are expected to call these functions as http post methods. Default service endpoints will be `http://localhost:5000/verify` for face recognition, `http://localhost:5000/analyze` for facial attribute analysis, and `http://localhost:5000/represent` for vector representation. You can pass input images as exact image paths on your environment, base64 encoded strings or images on web. [Here](https://github.com/serengil/deepface/tree/master/api/postman), you can find a postman project to find out how these methods should be called.
|
||||
|
||||
**Dockerized Service**
|
||||
|
||||
@ -332,9 +332,9 @@ You can also support this work on [Patreon](https://www.patreon.com/serengil?rep
|
||||
|
||||
## Citation
|
||||
|
||||
Please cite deepface in your publications if it helps your research. Here are its BibTex entries:
|
||||
Please cite deepface in your publications if it helps your research - see [`CITATIONS`](https://github.com/serengil/deepface/blob/master/CITATIONS.md) for more details. Here are its BibTex entries:
|
||||
|
||||
If you use deepface for facial recogntion purposes, please cite the this publication.
|
||||
If you use deepface in your research for facial recogntion purposes, please cite this publication.
|
||||
|
||||
```BibTeX
|
||||
@inproceedings{serengil2020lightface,
|
||||
@ -349,7 +349,7 @@ If you use deepface for facial recogntion purposes, please cite the this publica
|
||||
}
|
||||
```
|
||||
|
||||
If you use deepface for facial attribute analysis purposes such as age, gender, emotion or ethnicity prediction or face detection purposes, please cite the this publication.
|
||||
If you use deepface in your research for facial attribute analysis purposes such as age, gender, emotion or ethnicity prediction or face detection purposes, please cite this publication.
|
||||
|
||||
```BibTeX
|
||||
@inproceedings{serengil2021lightface,
|
||||
|
@ -10,7 +10,7 @@ import pandas as pd
|
||||
import tensorflow as tf
|
||||
|
||||
# package dependencies
|
||||
from deepface.commons import functions
|
||||
from deepface.commons import package_utils, folder_utils
|
||||
from deepface.commons.logger import Logger
|
||||
from deepface.modules import (
|
||||
modeling,
|
||||
@ -24,17 +24,21 @@ from deepface.modules import (
|
||||
|
||||
logger = Logger(module="DeepFace")
|
||||
|
||||
# current package version of deepface
|
||||
__version__ = package_utils.find_package_version()
|
||||
|
||||
# -----------------------------------
|
||||
# configurations for dependencies
|
||||
|
||||
warnings.filterwarnings("ignore")
|
||||
os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3"
|
||||
tf_version = functions.get_tf_major_version()
|
||||
tf_version = package_utils.get_tf_major_version()
|
||||
if tf_version == 2:
|
||||
tf.get_logger().setLevel(logging.ERROR)
|
||||
# -----------------------------------
|
||||
|
||||
functions.initialize_folder()
|
||||
# create required folders if necessary to store model weights
|
||||
folder_utils.initialize_folder()
|
||||
|
||||
|
||||
def build_model(model_name: str) -> Any:
|
||||
@ -511,7 +515,7 @@ def detectFace(
|
||||
align (bool): Flag to enable face alignment (default is True).
|
||||
|
||||
Returns:
|
||||
img (np.ndarray): detected (and aligned) facial area image as numpy array
|
||||
img (np.ndarray): detected (and aligned) facial area image as numpy array
|
||||
"""
|
||||
logger.warn("Function detectFace is deprecated. Use extract_faces instead.")
|
||||
face_objs = extract_faces(
|
||||
|
@ -2,7 +2,7 @@ from typing import List
|
||||
import os
|
||||
import gdown
|
||||
import numpy as np
|
||||
from deepface.commons import functions
|
||||
from deepface.commons import package_utils, folder_utils
|
||||
from deepface.commons.logger import Logger
|
||||
from deepface.models.FacialRecognition import FacialRecognition
|
||||
|
||||
@ -13,7 +13,7 @@ logger = Logger(module="basemodels.ArcFace")
|
||||
# --------------------------------
|
||||
# dependency configuration
|
||||
|
||||
tf_version = functions.get_tf_major_version()
|
||||
tf_version = package_utils.get_tf_major_version()
|
||||
|
||||
if tf_version == 1:
|
||||
from keras.models import Model
|
||||
@ -94,7 +94,7 @@ def load_model(
|
||||
# ---------------------------------------
|
||||
# check the availability of pre-trained weights
|
||||
|
||||
home = functions.get_deepface_home()
|
||||
home = folder_utils.get_deepface_home()
|
||||
|
||||
file_name = "arcface_weights.h5"
|
||||
output = home + "/.deepface/weights/" + file_name
|
||||
|
@ -2,13 +2,13 @@ from typing import List
|
||||
import os
|
||||
import gdown
|
||||
import numpy as np
|
||||
from deepface.commons import functions
|
||||
from deepface.commons import package_utils, folder_utils
|
||||
from deepface.commons.logger import Logger
|
||||
from deepface.models.FacialRecognition import FacialRecognition
|
||||
|
||||
logger = Logger(module="basemodels.DeepID")
|
||||
|
||||
tf_version = functions.get_tf_major_version()
|
||||
tf_version = package_utils.get_tf_major_version()
|
||||
|
||||
if tf_version == 1:
|
||||
from keras.models import Model
|
||||
@ -100,7 +100,7 @@ def load_model(
|
||||
|
||||
# ---------------------------------
|
||||
|
||||
home = functions.get_deepface_home()
|
||||
home = folder_utils.get_deepface_home()
|
||||
|
||||
if os.path.isfile(home + "/.deepface/weights/deepid_keras_weights.h5") != True:
|
||||
logger.info("deepid_keras_weights.h5 will be downloaded...")
|
||||
|
@ -3,7 +3,7 @@ import os
|
||||
import bz2
|
||||
import gdown
|
||||
import numpy as np
|
||||
from deepface.commons import functions
|
||||
from deepface.commons import folder_utils
|
||||
from deepface.commons.logger import Logger
|
||||
from deepface.models.FacialRecognition import FacialRecognition
|
||||
|
||||
@ -68,7 +68,7 @@ class DlibResNet:
|
||||
|
||||
# ---------------------
|
||||
|
||||
home = functions.get_deepface_home()
|
||||
home = folder_utils.get_deepface_home()
|
||||
weight_file = home + "/.deepface/weights/dlib_face_recognition_resnet_model_v1.dat"
|
||||
|
||||
# ---------------------
|
||||
|
@ -2,7 +2,7 @@ from typing import List
|
||||
import os
|
||||
import gdown
|
||||
import numpy as np
|
||||
from deepface.commons import functions
|
||||
from deepface.commons import package_utils, folder_utils
|
||||
from deepface.commons.logger import Logger
|
||||
from deepface.models.FacialRecognition import FacialRecognition
|
||||
|
||||
@ -11,7 +11,7 @@ logger = Logger(module="basemodels.Facenet")
|
||||
# --------------------------------
|
||||
# dependency configuration
|
||||
|
||||
tf_version = functions.get_tf_major_version()
|
||||
tf_version = package_utils.get_tf_major_version()
|
||||
|
||||
if tf_version == 1:
|
||||
from keras.models import Model
|
||||
@ -1689,7 +1689,7 @@ def load_facenet128d_model(
|
||||
|
||||
# -----------------------------------
|
||||
|
||||
home = functions.get_deepface_home()
|
||||
home = folder_utils.get_deepface_home()
|
||||
|
||||
if os.path.isfile(home + "/.deepface/weights/facenet_weights.h5") != True:
|
||||
logger.info("facenet_weights.h5 will be downloaded...")
|
||||
@ -1719,7 +1719,7 @@ def load_facenet512d_model(
|
||||
|
||||
# -------------------------
|
||||
|
||||
home = functions.get_deepface_home()
|
||||
home = folder_utils.get_deepface_home()
|
||||
|
||||
if os.path.isfile(home + "/.deepface/weights/facenet512_weights.h5") != True:
|
||||
logger.info("facenet512_weights.h5 will be downloaded...")
|
||||
|
@ -3,7 +3,7 @@ import os
|
||||
import zipfile
|
||||
import gdown
|
||||
import numpy as np
|
||||
from deepface.commons import functions
|
||||
from deepface.commons import package_utils, folder_utils
|
||||
from deepface.commons.logger import Logger
|
||||
from deepface.models.FacialRecognition import FacialRecognition
|
||||
|
||||
@ -12,7 +12,7 @@ logger = Logger(module="basemodels.FbDeepFace")
|
||||
# --------------------------------
|
||||
# dependency configuration
|
||||
|
||||
tf_version = functions.get_tf_major_version()
|
||||
tf_version = package_utils.get_tf_major_version()
|
||||
|
||||
if tf_version == 1:
|
||||
from keras.models import Model, Sequential
|
||||
@ -84,7 +84,7 @@ def load_model(
|
||||
|
||||
# ---------------------------------
|
||||
|
||||
home = functions.get_deepface_home()
|
||||
home = folder_utils.get_deepface_home()
|
||||
|
||||
if os.path.isfile(home + "/.deepface/weights/VGGFace2_DeepFace_weights_val-0.9034.h5") != True:
|
||||
logger.info("VGGFace2_DeepFace_weights_val-0.9034.h5 will be downloaded...")
|
||||
|
@ -3,13 +3,13 @@ import os
|
||||
import gdown
|
||||
import tensorflow as tf
|
||||
import numpy as np
|
||||
from deepface.commons import functions
|
||||
from deepface.commons import package_utils, folder_utils
|
||||
from deepface.commons.logger import Logger
|
||||
from deepface.models.FacialRecognition import FacialRecognition
|
||||
|
||||
logger = Logger(module="basemodels.OpenFace")
|
||||
|
||||
tf_version = functions.get_tf_major_version()
|
||||
tf_version = package_utils.get_tf_major_version()
|
||||
if tf_version == 1:
|
||||
from keras.models import Model
|
||||
from keras.layers import Conv2D, ZeroPadding2D, Input, concatenate
|
||||
@ -394,7 +394,7 @@ def load_model(
|
||||
|
||||
# -----------------------------------
|
||||
|
||||
home = functions.get_deepface_home()
|
||||
home = folder_utils.get_deepface_home()
|
||||
|
||||
if os.path.isfile(home + "/.deepface/weights/openface_weights.h5") != True:
|
||||
logger.info("openface_weights.h5 will be downloaded...")
|
||||
|
@ -5,7 +5,7 @@ import numpy as np
|
||||
import cv2 as cv
|
||||
import gdown
|
||||
|
||||
from deepface.commons import functions
|
||||
from deepface.commons import folder_utils
|
||||
from deepface.commons.logger import Logger
|
||||
from deepface.models.FacialRecognition import FacialRecognition
|
||||
|
||||
@ -50,7 +50,7 @@ def load_model(
|
||||
Construct SFace model, download its weights and load
|
||||
"""
|
||||
|
||||
home = functions.get_deepface_home()
|
||||
home = folder_utils.get_deepface_home()
|
||||
|
||||
file_name = home + "/.deepface/weights/face_recognition_sface_2021dec.onnx"
|
||||
|
||||
|
@ -2,7 +2,8 @@ from typing import List
|
||||
import os
|
||||
import gdown
|
||||
import numpy as np
|
||||
from deepface.commons import functions, distance
|
||||
from deepface.commons import package_utils, folder_utils
|
||||
from deepface.modules import verification
|
||||
from deepface.models.FacialRecognition import FacialRecognition
|
||||
from deepface.commons.logger import Logger
|
||||
|
||||
@ -10,7 +11,7 @@ logger = Logger(module="basemodels.VGGFace")
|
||||
|
||||
# ---------------------------------------
|
||||
|
||||
tf_version = functions.get_tf_major_version()
|
||||
tf_version = package_utils.get_tf_major_version()
|
||||
if tf_version == 1:
|
||||
from keras.models import Model, Sequential
|
||||
from keras.layers import (
|
||||
@ -59,7 +60,7 @@ class VggFaceClient(FacialRecognition):
|
||||
# having normalization layer in descriptor troubles for some gpu users (e.g. issue 957, 966)
|
||||
# instead we are now calculating it with traditional way not with keras backend
|
||||
embedding = self.model(img, training=False).numpy()[0].tolist()
|
||||
embedding = distance.l2_normalize(embedding)
|
||||
embedding = verification.l2_normalize(embedding)
|
||||
return embedding.tolist()
|
||||
|
||||
|
||||
@ -128,7 +129,7 @@ def load_model(
|
||||
|
||||
model = base_model()
|
||||
|
||||
home = functions.get_deepface_home()
|
||||
home = folder_utils.get_deepface_home()
|
||||
output = home + "/.deepface/weights/vgg_face_weights.h5"
|
||||
|
||||
if os.path.isfile(output) != True:
|
||||
|
4
deepface/commons/constant.py
Normal file
4
deepface/commons/constant.py
Normal file
@ -0,0 +1,4 @@
|
||||
import os
|
||||
|
||||
SRC_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
ROOT_DIR = os.path.dirname(SRC_DIR)
|
@ -1,64 +0,0 @@
|
||||
from typing import Union
|
||||
import numpy as np
|
||||
|
||||
|
||||
def find_cosine_distance(
|
||||
source_representation: Union[np.ndarray, list], test_representation: Union[np.ndarray, list]
|
||||
) -> np.float64:
|
||||
if isinstance(source_representation, list):
|
||||
source_representation = np.array(source_representation)
|
||||
|
||||
if isinstance(test_representation, list):
|
||||
test_representation = np.array(test_representation)
|
||||
|
||||
a = np.matmul(np.transpose(source_representation), test_representation)
|
||||
b = np.sum(np.multiply(source_representation, source_representation))
|
||||
c = np.sum(np.multiply(test_representation, test_representation))
|
||||
return 1 - (a / (np.sqrt(b) * np.sqrt(c)))
|
||||
|
||||
|
||||
def find_euclidean_distance(
|
||||
source_representation: Union[np.ndarray, list], test_representation: Union[np.ndarray, list]
|
||||
) -> np.float64:
|
||||
if isinstance(source_representation, list):
|
||||
source_representation = np.array(source_representation)
|
||||
|
||||
if isinstance(test_representation, list):
|
||||
test_representation = np.array(test_representation)
|
||||
|
||||
euclidean_distance = source_representation - test_representation
|
||||
euclidean_distance = np.sum(np.multiply(euclidean_distance, euclidean_distance))
|
||||
euclidean_distance = np.sqrt(euclidean_distance)
|
||||
return euclidean_distance
|
||||
|
||||
|
||||
def l2_normalize(x: Union[np.ndarray, list]) -> np.ndarray:
|
||||
if isinstance(x, list):
|
||||
x = np.array(x)
|
||||
return x / np.sqrt(np.sum(np.multiply(x, x)))
|
||||
|
||||
|
||||
def find_threshold(model_name: str, distance_metric: str) -> float:
|
||||
|
||||
base_threshold = {"cosine": 0.40, "euclidean": 0.55, "euclidean_l2": 0.75}
|
||||
|
||||
thresholds = {
|
||||
# "VGG-Face": {"cosine": 0.40, "euclidean": 0.60, "euclidean_l2": 0.86}, # 2622d
|
||||
"VGG-Face": {
|
||||
"cosine": 0.68,
|
||||
"euclidean": 1.17,
|
||||
"euclidean_l2": 1.17,
|
||||
}, # 4096d - tuned with LFW
|
||||
"Facenet": {"cosine": 0.40, "euclidean": 10, "euclidean_l2": 0.80},
|
||||
"Facenet512": {"cosine": 0.30, "euclidean": 23.56, "euclidean_l2": 1.04},
|
||||
"ArcFace": {"cosine": 0.68, "euclidean": 4.15, "euclidean_l2": 1.13},
|
||||
"Dlib": {"cosine": 0.07, "euclidean": 0.6, "euclidean_l2": 0.4},
|
||||
"SFace": {"cosine": 0.593, "euclidean": 10.734, "euclidean_l2": 1.055},
|
||||
"OpenFace": {"cosine": 0.10, "euclidean": 0.55, "euclidean_l2": 0.55},
|
||||
"DeepFace": {"cosine": 0.23, "euclidean": 64, "euclidean_l2": 0.64},
|
||||
"DeepID": {"cosine": 0.015, "euclidean": 45, "euclidean_l2": 0.17},
|
||||
}
|
||||
|
||||
threshold = thresholds.get(model_name, base_threshold).get(distance_metric, 0.4)
|
||||
|
||||
return threshold
|
35
deepface/commons/folder_utils.py
Normal file
35
deepface/commons/folder_utils.py
Normal file
@ -0,0 +1,35 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
from deepface.commons.logger import Logger
|
||||
|
||||
logger = Logger(module="deepface/commons/folder_utils.py")
|
||||
|
||||
|
||||
def initialize_folder() -> None:
|
||||
"""
|
||||
Initialize the folder for storing model weights.
|
||||
|
||||
Raises:
|
||||
OSError: if the folder cannot be created.
|
||||
"""
|
||||
home = get_deepface_home()
|
||||
deepface_home_path = home + "/.deepface"
|
||||
weights_path = deepface_home_path + "/weights"
|
||||
|
||||
if not os.path.exists(deepface_home_path):
|
||||
os.makedirs(deepface_home_path, exist_ok=True)
|
||||
logger.info(f"Directory {home}/.deepface created")
|
||||
|
||||
if not os.path.exists(weights_path):
|
||||
os.makedirs(weights_path, exist_ok=True)
|
||||
logger.info(f"Directory {home}/.deepface/weights created")
|
||||
|
||||
|
||||
def get_deepface_home() -> str:
|
||||
"""
|
||||
Get the home directory for storing model weights
|
||||
|
||||
Returns:
|
||||
str: the home directory.
|
||||
"""
|
||||
return str(os.getenv("DEEPFACE_HOME", default=str(Path.home())))
|
@ -1,42 +0,0 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
# 3rd party dependencies
|
||||
import tensorflow as tf
|
||||
|
||||
# package dependencies
|
||||
from deepface.commons.logger import Logger
|
||||
|
||||
logger = Logger(module="commons.functions")
|
||||
|
||||
|
||||
def get_tf_major_version() -> int:
|
||||
return int(tf.__version__.split(".", maxsplit=1)[0])
|
||||
|
||||
|
||||
def initialize_folder() -> None:
|
||||
"""Initialize the folder for storing weights and models.
|
||||
|
||||
Raises:
|
||||
OSError: if the folder cannot be created.
|
||||
"""
|
||||
home = get_deepface_home()
|
||||
deepFaceHomePath = home + "/.deepface"
|
||||
weightsPath = deepFaceHomePath + "/weights"
|
||||
|
||||
if not os.path.exists(deepFaceHomePath):
|
||||
os.makedirs(deepFaceHomePath, exist_ok=True)
|
||||
logger.info(f"Directory {home}/.deepface created")
|
||||
|
||||
if not os.path.exists(weightsPath):
|
||||
os.makedirs(weightsPath, exist_ok=True)
|
||||
logger.info(f"Directory {home}/.deepface/weights created")
|
||||
|
||||
|
||||
def get_deepface_home() -> str:
|
||||
"""Get the home directory for storing weights and models.
|
||||
|
||||
Returns:
|
||||
str: the home directory.
|
||||
"""
|
||||
return str(os.getenv("DEEPFACE_HOME", default=str(Path.home())))
|
36
deepface/commons/package_utils.py
Normal file
36
deepface/commons/package_utils.py
Normal file
@ -0,0 +1,36 @@
|
||||
import json
|
||||
|
||||
# 3rd party dependencies
|
||||
import tensorflow as tf
|
||||
|
||||
# package dependencies
|
||||
from deepface.commons.logger import Logger
|
||||
from deepface.commons import constant
|
||||
|
||||
logger = Logger(module="commons.package_utils")
|
||||
|
||||
|
||||
def get_tf_major_version() -> int:
|
||||
"""
|
||||
Find tensorflow's major version
|
||||
Returns
|
||||
major_version (int)
|
||||
"""
|
||||
return int(tf.__version__.split(".", maxsplit=1)[0])
|
||||
|
||||
|
||||
def find_package_version() -> str:
|
||||
"""
|
||||
Find the currenct package version
|
||||
Returns:
|
||||
version (str)
|
||||
"""
|
||||
version_info = "N/A"
|
||||
try:
|
||||
with open(f"{constant.ROOT_DIR}/package_info.json", "r", encoding="utf-8") as f:
|
||||
package_info = json.load(f)
|
||||
version_info = package_info["version"]
|
||||
except Exception as err: # pylint: disable=broad-except
|
||||
logger.error(f"Exception while getting version info: {str(err)}")
|
||||
|
||||
return version_info
|
@ -3,7 +3,7 @@ import os
|
||||
import bz2
|
||||
import gdown
|
||||
import numpy as np
|
||||
from deepface.commons import functions
|
||||
from deepface.commons import folder_utils
|
||||
from deepface.models.Detector import Detector, DetectedFace, FacialAreaRegion
|
||||
from deepface.commons.logger import Logger
|
||||
|
||||
@ -20,7 +20,7 @@ class DlibClient(Detector):
|
||||
Returns:
|
||||
model (Any)
|
||||
"""
|
||||
home = functions.get_deepface_home()
|
||||
home = folder_utils.get_deepface_home()
|
||||
|
||||
# this is not a must dependency. do not import it in the global level.
|
||||
try:
|
||||
|
@ -36,45 +36,47 @@ class RetinaFaceClient(Detector):
|
||||
|
||||
obj = rf.detect_faces(img, model=self.model, threshold=0.9)
|
||||
|
||||
if isinstance(obj, dict):
|
||||
for face_idx in obj.keys():
|
||||
identity = obj[face_idx]
|
||||
facial_area = identity["facial_area"]
|
||||
if not isinstance(obj, dict):
|
||||
return resp
|
||||
|
||||
y = facial_area[1]
|
||||
h = facial_area[3] - y
|
||||
x = facial_area[0]
|
||||
w = facial_area[2] - x
|
||||
img_region = FacialAreaRegion(x=x, y=y, w=w, h=h)
|
||||
confidence = identity["score"]
|
||||
for face_idx in obj.keys():
|
||||
identity = obj[face_idx]
|
||||
facial_area = identity["facial_area"]
|
||||
|
||||
# expand the facial area to be extracted and stay within img.shape limits
|
||||
x2 = max(0, x - int((w * expand_percentage) / 100)) # expand left
|
||||
y2 = max(0, y - int((h * expand_percentage) / 100)) # expand top
|
||||
w2 = min(img.shape[1], w + int((w * expand_percentage) / 100)) # expand right
|
||||
h2 = min(img.shape[0], h + int((h * expand_percentage) / 100)) # expand bottom
|
||||
y = facial_area[1]
|
||||
h = facial_area[3] - y
|
||||
x = facial_area[0]
|
||||
w = facial_area[2] - x
|
||||
img_region = FacialAreaRegion(x=x, y=y, w=w, h=h)
|
||||
confidence = identity["score"]
|
||||
|
||||
# detected_face = img[int(y) : int(y + h), int(x) : int(x + w)]
|
||||
detected_face = img[int(y2) : int(y2 + h2), int(x2) : int(x2 + w2)]
|
||||
# expand the facial area to be extracted and stay within img.shape limits
|
||||
x2 = max(0, x - int((w * expand_percentage) / 100)) # expand left
|
||||
y2 = max(0, y - int((h * expand_percentage) / 100)) # expand top
|
||||
w2 = min(img.shape[1], w + int((w * expand_percentage) / 100)) # expand right
|
||||
h2 = min(img.shape[0], h + int((h * expand_percentage) / 100)) # expand bottom
|
||||
|
||||
if align:
|
||||
landmarks = identity["landmarks"]
|
||||
left_eye = landmarks["left_eye"]
|
||||
right_eye = landmarks["right_eye"]
|
||||
nose = landmarks["nose"]
|
||||
# mouth_right = landmarks["mouth_right"]
|
||||
# mouth_left = landmarks["mouth_left"]
|
||||
# detected_face = img[int(y) : int(y + h), int(x) : int(x + w)]
|
||||
detected_face = img[int(y2) : int(y2 + h2), int(x2) : int(x2 + w2)]
|
||||
|
||||
detected_face = postprocess.alignment_procedure(
|
||||
detected_face, right_eye, left_eye, nose
|
||||
)
|
||||
if align:
|
||||
landmarks = identity["landmarks"]
|
||||
left_eye = landmarks["left_eye"]
|
||||
right_eye = landmarks["right_eye"]
|
||||
nose = landmarks["nose"]
|
||||
# mouth_right = landmarks["mouth_right"]
|
||||
# mouth_left = landmarks["mouth_left"]
|
||||
|
||||
detected_face_obj = DetectedFace(
|
||||
img=detected_face,
|
||||
facial_area=img_region,
|
||||
confidence=confidence,
|
||||
detected_face = postprocess.alignment_procedure(
|
||||
detected_face, right_eye, left_eye, nose
|
||||
)
|
||||
|
||||
resp.append(detected_face_obj)
|
||||
detected_face_obj = DetectedFace(
|
||||
img=detected_face,
|
||||
facial_area=img_region,
|
||||
confidence=confidence,
|
||||
)
|
||||
|
||||
resp.append(detected_face_obj)
|
||||
|
||||
return resp
|
||||
|
@ -5,7 +5,7 @@ import cv2
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
from deepface.detectors import OpenCv
|
||||
from deepface.commons import functions
|
||||
from deepface.commons import folder_utils
|
||||
from deepface.models.Detector import Detector, DetectedFace, FacialAreaRegion
|
||||
from deepface.modules import detection
|
||||
from deepface.commons.logger import Logger
|
||||
@ -26,7 +26,7 @@ class SsdClient(Detector):
|
||||
model (dict)
|
||||
"""
|
||||
|
||||
home = functions.get_deepface_home()
|
||||
home = folder_utils.get_deepface_home()
|
||||
|
||||
# model structure
|
||||
if os.path.isfile(home + "/.deepface/weights/deploy.prototxt") != True:
|
||||
|
@ -4,6 +4,7 @@ import numpy as np
|
||||
import gdown
|
||||
from deepface.models.Detector import Detector, DetectedFace, FacialAreaRegion
|
||||
from deepface.modules import detection
|
||||
from deepface.commons import folder_utils
|
||||
from deepface.commons.logger import Logger
|
||||
|
||||
logger = Logger()
|
||||
@ -39,9 +40,7 @@ class YoloClient(Detector):
|
||||
Please install using 'pip install ultralytics' "
|
||||
) from e
|
||||
|
||||
from deepface.commons.functions import get_deepface_home
|
||||
|
||||
weight_path = f"{get_deepface_home()}{PATH}"
|
||||
weight_path = f"{folder_utils.get_deepface_home()}{PATH}"
|
||||
|
||||
# Download the model's weights if they don't exist
|
||||
if not os.path.isfile(weight_path):
|
||||
|
@ -3,7 +3,7 @@ from typing import Any, List
|
||||
import cv2
|
||||
import numpy as np
|
||||
import gdown
|
||||
from deepface.commons import functions
|
||||
from deepface.commons import folder_utils
|
||||
from deepface.models.Detector import Detector, DetectedFace, FacialAreaRegion
|
||||
from deepface.modules import detection
|
||||
from deepface.commons.logger import Logger
|
||||
@ -31,7 +31,7 @@ class YuNetClient(Detector):
|
||||
# pylint: disable=C0301
|
||||
url = "https://github.com/opencv/opencv_zoo/raw/main/models/face_detection_yunet/face_detection_yunet_2023mar.onnx"
|
||||
file_name = "face_detection_yunet_2023mar.onnx"
|
||||
home = functions.get_deepface_home()
|
||||
home = folder_utils.get_deepface_home()
|
||||
if os.path.isfile(home + f"/.deepface/weights/{file_name}") is False:
|
||||
logger.info(f"{file_name} will be downloaded...")
|
||||
output = home + f"/.deepface/weights/{file_name}"
|
||||
|
@ -2,7 +2,7 @@ import os
|
||||
import gdown
|
||||
import numpy as np
|
||||
from deepface.basemodels import VGGFace
|
||||
from deepface.commons import functions
|
||||
from deepface.commons import package_utils, folder_utils
|
||||
from deepface.commons.logger import Logger
|
||||
from deepface.models.Demography import Demography
|
||||
|
||||
@ -11,7 +11,7 @@ logger = Logger(module="extendedmodels.Age")
|
||||
# ----------------------------------------
|
||||
# dependency configurations
|
||||
|
||||
tf_version = functions.get_tf_major_version()
|
||||
tf_version = package_utils.get_tf_major_version()
|
||||
|
||||
if tf_version == 1:
|
||||
from keras.models import Model, Sequential
|
||||
@ -64,7 +64,7 @@ def load_model(
|
||||
|
||||
# load weights
|
||||
|
||||
home = functions.get_deepface_home()
|
||||
home = folder_utils.get_deepface_home()
|
||||
|
||||
if os.path.isfile(home + "/.deepface/weights/age_model_weights.h5") != True:
|
||||
logger.info("age_model_weights.h5 will be downloaded...")
|
||||
|
@ -2,7 +2,7 @@ import os
|
||||
import gdown
|
||||
import numpy as np
|
||||
import cv2
|
||||
from deepface.commons import functions
|
||||
from deepface.commons import package_utils, folder_utils
|
||||
from deepface.commons.logger import Logger
|
||||
from deepface.models.Demography import Demography
|
||||
|
||||
@ -12,7 +12,7 @@ logger = Logger(module="extendedmodels.Emotion")
|
||||
# pylint: disable=line-too-long
|
||||
# -------------------------------------------
|
||||
# dependency configuration
|
||||
tf_version = functions.get_tf_major_version()
|
||||
tf_version = package_utils.get_tf_major_version()
|
||||
|
||||
if tf_version == 1:
|
||||
from keras.models import Sequential
|
||||
@ -88,7 +88,7 @@ def load_model(
|
||||
|
||||
# ----------------------------
|
||||
|
||||
home = functions.get_deepface_home()
|
||||
home = folder_utils.get_deepface_home()
|
||||
|
||||
if os.path.isfile(home + "/.deepface/weights/facial_expression_model_weights.h5") != True:
|
||||
logger.info("facial_expression_model_weights.h5 will be downloaded...")
|
||||
|
@ -2,7 +2,7 @@ import os
|
||||
import gdown
|
||||
import numpy as np
|
||||
from deepface.basemodels import VGGFace
|
||||
from deepface.commons import functions
|
||||
from deepface.commons import package_utils, folder_utils
|
||||
from deepface.commons.logger import Logger
|
||||
from deepface.models.Demography import Demography
|
||||
|
||||
@ -13,7 +13,7 @@ logger = Logger(module="extendedmodels.Gender")
|
||||
# -------------------------------------
|
||||
# dependency configurations
|
||||
|
||||
tf_version = functions.get_tf_major_version()
|
||||
tf_version = package_utils.get_tf_major_version()
|
||||
if tf_version == 1:
|
||||
from keras.models import Model, Sequential
|
||||
from keras.layers import Convolution2D, Flatten, Activation
|
||||
@ -66,7 +66,7 @@ def load_model(
|
||||
|
||||
# load weights
|
||||
|
||||
home = functions.get_deepface_home()
|
||||
home = folder_utils.get_deepface_home()
|
||||
|
||||
if os.path.isfile(home + "/.deepface/weights/gender_model_weights.h5") != True:
|
||||
logger.info("gender_model_weights.h5 will be downloaded...")
|
||||
|
@ -2,7 +2,7 @@ import os
|
||||
import gdown
|
||||
import numpy as np
|
||||
from deepface.basemodels import VGGFace
|
||||
from deepface.commons import functions
|
||||
from deepface.commons import package_utils, folder_utils
|
||||
from deepface.commons.logger import Logger
|
||||
from deepface.models.Demography import Demography
|
||||
|
||||
@ -12,7 +12,7 @@ logger = Logger(module="extendedmodels.Race")
|
||||
# pylint: disable=line-too-long
|
||||
# --------------------------
|
||||
# dependency configurations
|
||||
tf_version = functions.get_tf_major_version()
|
||||
tf_version = package_utils.get_tf_major_version()
|
||||
|
||||
if tf_version == 1:
|
||||
from keras.models import Model, Sequential
|
||||
@ -63,7 +63,7 @@ def load_model(
|
||||
|
||||
# load weights
|
||||
|
||||
home = functions.get_deepface_home()
|
||||
home = folder_utils.get_deepface_home()
|
||||
|
||||
if os.path.isfile(home + "/.deepface/weights/race_model_single_batch.h5") != True:
|
||||
logger.info("race_model_single_batch.h5 will be downloaded...")
|
||||
|
@ -1,9 +1,9 @@
|
||||
from typing import Union
|
||||
from abc import ABC, abstractmethod
|
||||
import numpy as np
|
||||
from deepface.commons import functions
|
||||
from deepface.commons import package_utils
|
||||
|
||||
tf_version = functions.get_tf_major_version()
|
||||
tf_version = package_utils.get_tf_major_version()
|
||||
if tf_version == 1:
|
||||
from keras.models import Model
|
||||
else:
|
||||
|
@ -1,9 +1,9 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Any, Union, List, Tuple
|
||||
import numpy as np
|
||||
from deepface.commons import functions
|
||||
from deepface.commons import package_utils
|
||||
|
||||
tf_version = functions.get_tf_major_version()
|
||||
tf_version = package_utils.get_tf_major_version()
|
||||
if tf_version == 2:
|
||||
from tensorflow.keras.models import Model
|
||||
else:
|
||||
|
@ -10,7 +10,7 @@ from PIL import Image
|
||||
from deepface.modules import preprocessing
|
||||
from deepface.models.Detector import DetectedFace, FacialAreaRegion
|
||||
from deepface.detectors import DetectorWrapper
|
||||
from deepface.commons import functions
|
||||
from deepface.commons import package_utils
|
||||
from deepface.commons.logger import Logger
|
||||
|
||||
logger = Logger(module="deepface/modules/detection.py")
|
||||
@ -18,7 +18,7 @@ logger = Logger(module="deepface/modules/detection.py")
|
||||
# pylint: disable=no-else-raise
|
||||
|
||||
|
||||
tf_major_version = functions.get_tf_major_version()
|
||||
tf_major_version = package_utils.get_tf_major_version()
|
||||
if tf_major_version == 1:
|
||||
from keras.preprocessing import image
|
||||
elif tf_major_version == 2:
|
||||
@ -63,8 +63,11 @@ def extract_faces(
|
||||
|
||||
Returns:
|
||||
results (List[Dict[str, Any]]): A list of dictionaries, where each dictionary contains:
|
||||
|
||||
- "face" (np.ndarray): The detected face as a NumPy array.
|
||||
|
||||
- "facial_area" (List[float]): The detected face's regions represented as a list of floats.
|
||||
|
||||
- "confidence" (float): The confidence score associated with the detected face.
|
||||
"""
|
||||
|
||||
|
@ -10,9 +10,8 @@ import pandas as pd
|
||||
from tqdm import tqdm
|
||||
|
||||
# project dependencies
|
||||
from deepface.commons import distance as dst
|
||||
from deepface.commons.logger import Logger
|
||||
from deepface.modules import representation, detection, modeling
|
||||
from deepface.modules import representation, detection, modeling, verification
|
||||
from deepface.models.FacialRecognition import FacialRecognition
|
||||
|
||||
logger = Logger(module="deepface/modules/recognition.py")
|
||||
@ -253,13 +252,17 @@ def find(
|
||||
)
|
||||
|
||||
if distance_metric == "cosine":
|
||||
distance = dst.find_cosine_distance(source_representation, target_representation)
|
||||
distance = verification.find_cosine_distance(
|
||||
source_representation, target_representation
|
||||
)
|
||||
elif distance_metric == "euclidean":
|
||||
distance = dst.find_euclidean_distance(source_representation, target_representation)
|
||||
distance = verification.find_euclidean_distance(
|
||||
source_representation, target_representation
|
||||
)
|
||||
elif distance_metric == "euclidean_l2":
|
||||
distance = dst.find_euclidean_distance(
|
||||
dst.l2_normalize(source_representation),
|
||||
dst.l2_normalize(target_representation),
|
||||
distance = verification.find_euclidean_distance(
|
||||
verification.l2_normalize(source_representation),
|
||||
verification.l2_normalize(target_representation),
|
||||
)
|
||||
else:
|
||||
raise ValueError(f"invalid distance metric passes - {distance_metric}")
|
||||
@ -267,7 +270,7 @@ def find(
|
||||
distances.append(distance)
|
||||
|
||||
# ---------------------------
|
||||
target_threshold = threshold or dst.find_threshold(model_name, distance_metric)
|
||||
target_threshold = threshold or verification.find_threshold(model_name, distance_metric)
|
||||
|
||||
result_df["threshold"] = target_threshold
|
||||
result_df["distance"] = distances
|
||||
|
@ -6,7 +6,6 @@ from typing import Any, Dict, Union
|
||||
import numpy as np
|
||||
|
||||
# project dependencies
|
||||
from deepface.commons import distance as dst
|
||||
from deepface.modules import representation, detection, modeling
|
||||
from deepface.models.FacialRecognition import FacialRecognition
|
||||
|
||||
@ -138,12 +137,12 @@ def verify(
|
||||
img2_representation = img2_embedding_obj[0]["embedding"]
|
||||
|
||||
if distance_metric == "cosine":
|
||||
distance = dst.find_cosine_distance(img1_representation, img2_representation)
|
||||
distance = find_cosine_distance(img1_representation, img2_representation)
|
||||
elif distance_metric == "euclidean":
|
||||
distance = dst.find_euclidean_distance(img1_representation, img2_representation)
|
||||
distance = find_euclidean_distance(img1_representation, img2_representation)
|
||||
elif distance_metric == "euclidean_l2":
|
||||
distance = dst.find_euclidean_distance(
|
||||
dst.l2_normalize(img1_representation), dst.l2_normalize(img2_representation)
|
||||
distance = find_euclidean_distance(
|
||||
l2_normalize(img1_representation), l2_normalize(img2_representation)
|
||||
)
|
||||
else:
|
||||
raise ValueError("Invalid distance_metric passed - ", distance_metric)
|
||||
@ -152,7 +151,7 @@ def verify(
|
||||
regions.append((img1_region, img2_region))
|
||||
|
||||
# -------------------------------
|
||||
threshold = dst.find_threshold(model_name, distance_metric)
|
||||
threshold = find_threshold(model_name, distance_metric)
|
||||
distance = min(distances) # best distance
|
||||
facial_areas = regions[np.argmin(distances)]
|
||||
|
||||
@ -171,3 +170,65 @@ def verify(
|
||||
}
|
||||
|
||||
return resp_obj
|
||||
|
||||
|
||||
def find_cosine_distance(
|
||||
source_representation: Union[np.ndarray, list], test_representation: Union[np.ndarray, list]
|
||||
) -> np.float64:
|
||||
if isinstance(source_representation, list):
|
||||
source_representation = np.array(source_representation)
|
||||
|
||||
if isinstance(test_representation, list):
|
||||
test_representation = np.array(test_representation)
|
||||
|
||||
a = np.matmul(np.transpose(source_representation), test_representation)
|
||||
b = np.sum(np.multiply(source_representation, source_representation))
|
||||
c = np.sum(np.multiply(test_representation, test_representation))
|
||||
return 1 - (a / (np.sqrt(b) * np.sqrt(c)))
|
||||
|
||||
|
||||
def find_euclidean_distance(
|
||||
source_representation: Union[np.ndarray, list], test_representation: Union[np.ndarray, list]
|
||||
) -> np.float64:
|
||||
if isinstance(source_representation, list):
|
||||
source_representation = np.array(source_representation)
|
||||
|
||||
if isinstance(test_representation, list):
|
||||
test_representation = np.array(test_representation)
|
||||
|
||||
euclidean_distance = source_representation - test_representation
|
||||
euclidean_distance = np.sum(np.multiply(euclidean_distance, euclidean_distance))
|
||||
euclidean_distance = np.sqrt(euclidean_distance)
|
||||
return euclidean_distance
|
||||
|
||||
|
||||
def l2_normalize(x: Union[np.ndarray, list]) -> np.ndarray:
|
||||
if isinstance(x, list):
|
||||
x = np.array(x)
|
||||
return x / np.sqrt(np.sum(np.multiply(x, x)))
|
||||
|
||||
|
||||
def find_threshold(model_name: str, distance_metric: str) -> float:
|
||||
|
||||
base_threshold = {"cosine": 0.40, "euclidean": 0.55, "euclidean_l2": 0.75}
|
||||
|
||||
thresholds = {
|
||||
# "VGG-Face": {"cosine": 0.40, "euclidean": 0.60, "euclidean_l2": 0.86}, # 2622d
|
||||
"VGG-Face": {
|
||||
"cosine": 0.68,
|
||||
"euclidean": 1.17,
|
||||
"euclidean_l2": 1.17,
|
||||
}, # 4096d - tuned with LFW
|
||||
"Facenet": {"cosine": 0.40, "euclidean": 10, "euclidean_l2": 0.80},
|
||||
"Facenet512": {"cosine": 0.30, "euclidean": 23.56, "euclidean_l2": 1.04},
|
||||
"ArcFace": {"cosine": 0.68, "euclidean": 4.15, "euclidean_l2": 1.13},
|
||||
"Dlib": {"cosine": 0.07, "euclidean": 0.6, "euclidean_l2": 0.4},
|
||||
"SFace": {"cosine": 0.593, "euclidean": 10.734, "euclidean_l2": 1.055},
|
||||
"OpenFace": {"cosine": 0.10, "euclidean": 0.55, "euclidean_l2": 0.55},
|
||||
"DeepFace": {"cosine": 0.23, "euclidean": 64, "euclidean_l2": 0.64},
|
||||
"DeepID": {"cosine": 0.015, "euclidean": 45, "euclidean_l2": 0.17},
|
||||
}
|
||||
|
||||
threshold = thresholds.get(model_name, base_threshold).get(distance_metric, 0.4)
|
||||
|
||||
return threshold
|
||||
|
3
package_info.json
Normal file
3
package_info.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"version": "0.0.84"
|
||||
}
|
2
scripts/service.sh
Normal file → Executable file
2
scripts/service.sh
Normal file → Executable file
@ -1,3 +1,3 @@
|
||||
#!/usr/bin/env bash
|
||||
cd ../api
|
||||
cd ../api/src
|
||||
gunicorn --workers=1 --timeout=3600 --bind=0.0.0.0:5000 "app:create_app()"
|
13
setup.py
13
setup.py
@ -1,3 +1,4 @@
|
||||
import json
|
||||
import setuptools
|
||||
|
||||
with open("README.md", "r", encoding="utf-8") as fh:
|
||||
@ -6,13 +7,19 @@ with open("README.md", "r", encoding="utf-8") as fh:
|
||||
with open("requirements.txt", "r", encoding="utf-8") as f:
|
||||
requirements = f.read().split("\n")
|
||||
|
||||
with open("package_info.json", "r", encoding="utf-8") as f:
|
||||
package_info = json.load(f)
|
||||
|
||||
setuptools.setup(
|
||||
name="deepface",
|
||||
version="0.0.84",
|
||||
version=package_info["version"],
|
||||
author="Sefik Ilkin Serengil",
|
||||
author_email="serengil@gmail.com",
|
||||
description="A Lightweight Face Recognition and Facial Attribute Analysis Framework (Age, Gender, Emotion, Race) for Python",
|
||||
data_files=[("", ["README.md", "requirements.txt"])],
|
||||
description=(
|
||||
"A Lightweight Face Recognition and Facial Attribute Analysis Framework"
|
||||
" (Age, Gender, Emotion, Race) for Python"
|
||||
),
|
||||
data_files=[("", ["README.md", "requirements.txt", "package_info.json"])],
|
||||
long_description=long_description,
|
||||
long_description_content_type="text/markdown",
|
||||
url="https://github.com/serengil/deepface",
|
||||
|
@ -1,7 +1,7 @@
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
from deepface import DeepFace
|
||||
from deepface.commons import distance
|
||||
from deepface.modules import verification
|
||||
from deepface.models.FacialRecognition import FacialRecognition
|
||||
from deepface.commons.logger import Logger
|
||||
|
||||
@ -38,7 +38,7 @@ distance_vector = np.square(img1_representation - img2_representation)
|
||||
current_distance = np.sqrt(distance_vector.sum())
|
||||
logger.info(f"Euclidean distance: {current_distance}")
|
||||
|
||||
threshold = distance.find_threshold(model_name=model_name, distance_metric="euclidean")
|
||||
threshold = verification.find_threshold(model_name=model_name, distance_metric="euclidean")
|
||||
logger.info(f"Threshold for {model_name}-euclidean pair is {threshold}")
|
||||
|
||||
if current_distance < threshold:
|
||||
|
@ -1,12 +1,12 @@
|
||||
import cv2
|
||||
import pandas as pd
|
||||
from deepface import DeepFace
|
||||
from deepface.commons import distance
|
||||
from deepface.modules import verification
|
||||
from deepface.commons.logger import Logger
|
||||
|
||||
logger = Logger("tests/test_find.py")
|
||||
|
||||
threshold = distance.find_threshold(model_name="VGG-Face", distance_metric="cosine")
|
||||
threshold = verification.find_threshold(model_name="VGG-Face", distance_metric="cosine")
|
||||
|
||||
|
||||
def test_find_with_exact_path():
|
||||
|
@ -20,7 +20,16 @@ model_names = [
|
||||
"SFace",
|
||||
]
|
||||
|
||||
detector_backends = ["opencv", "ssd", "dlib", "mtcnn", "retinaface", "yunet", "yolov8"]
|
||||
detector_backends = [
|
||||
"opencv",
|
||||
"ssd",
|
||||
"dlib",
|
||||
"mtcnn",
|
||||
# "mediapipe", # crashed in mac
|
||||
"retinaface",
|
||||
"yunet",
|
||||
"yolov8",
|
||||
]
|
||||
|
||||
# verification
|
||||
for model_name in model_names:
|
||||
|
Loading…
x
Reference in New Issue
Block a user