mirror of
https://github.com/serengil/deepface.git
synced 2025-06-07 03:55:21 +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 required files from repo into image
|
||||||
COPY ./deepface /app/deepface
|
COPY ./deepface /app/deepface
|
||||||
COPY ./api/app.py /app/
|
COPY ./api/src/app.py /app/
|
||||||
COPY ./api/api.py /app/
|
COPY ./api/src/api.py /app/
|
||||||
COPY ./api/routes.py /app/
|
COPY ./api/src/routes.py /app/
|
||||||
COPY ./api/service.py /app/
|
COPY ./api/src/service.py /app/
|
||||||
COPY ./requirements.txt /app/
|
COPY ./requirements.txt /app/
|
||||||
COPY ./setup.py /app/
|
COPY ./setup.py /app/
|
||||||
COPY ./README.md /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>
|
<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**
|
**Dockerized Service**
|
||||||
|
|
||||||
@ -332,9 +332,9 @@ You can also support this work on [Patreon](https://www.patreon.com/serengil?rep
|
|||||||
|
|
||||||
## Citation
|
## 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
|
```BibTeX
|
||||||
@inproceedings{serengil2020lightface,
|
@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
|
```BibTeX
|
||||||
@inproceedings{serengil2021lightface,
|
@inproceedings{serengil2021lightface,
|
||||||
|
@ -10,7 +10,7 @@ import pandas as pd
|
|||||||
import tensorflow as tf
|
import tensorflow as tf
|
||||||
|
|
||||||
# package dependencies
|
# package dependencies
|
||||||
from deepface.commons import functions
|
from deepface.commons import package_utils, folder_utils
|
||||||
from deepface.commons.logger import Logger
|
from deepface.commons.logger import Logger
|
||||||
from deepface.modules import (
|
from deepface.modules import (
|
||||||
modeling,
|
modeling,
|
||||||
@ -24,17 +24,21 @@ from deepface.modules import (
|
|||||||
|
|
||||||
logger = Logger(module="DeepFace")
|
logger = Logger(module="DeepFace")
|
||||||
|
|
||||||
|
# current package version of deepface
|
||||||
|
__version__ = package_utils.find_package_version()
|
||||||
|
|
||||||
# -----------------------------------
|
# -----------------------------------
|
||||||
# configurations for dependencies
|
# configurations for dependencies
|
||||||
|
|
||||||
warnings.filterwarnings("ignore")
|
warnings.filterwarnings("ignore")
|
||||||
os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3"
|
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:
|
if tf_version == 2:
|
||||||
tf.get_logger().setLevel(logging.ERROR)
|
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:
|
def build_model(model_name: str) -> Any:
|
||||||
|
@ -2,7 +2,7 @@ from typing import List
|
|||||||
import os
|
import os
|
||||||
import gdown
|
import gdown
|
||||||
import numpy as np
|
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.commons.logger import Logger
|
||||||
from deepface.models.FacialRecognition import FacialRecognition
|
from deepface.models.FacialRecognition import FacialRecognition
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ logger = Logger(module="basemodels.ArcFace")
|
|||||||
# --------------------------------
|
# --------------------------------
|
||||||
# dependency configuration
|
# dependency configuration
|
||||||
|
|
||||||
tf_version = functions.get_tf_major_version()
|
tf_version = package_utils.get_tf_major_version()
|
||||||
|
|
||||||
if tf_version == 1:
|
if tf_version == 1:
|
||||||
from keras.models import Model
|
from keras.models import Model
|
||||||
@ -94,7 +94,7 @@ def load_model(
|
|||||||
# ---------------------------------------
|
# ---------------------------------------
|
||||||
# check the availability of pre-trained weights
|
# check the availability of pre-trained weights
|
||||||
|
|
||||||
home = functions.get_deepface_home()
|
home = folder_utils.get_deepface_home()
|
||||||
|
|
||||||
file_name = "arcface_weights.h5"
|
file_name = "arcface_weights.h5"
|
||||||
output = home + "/.deepface/weights/" + file_name
|
output = home + "/.deepface/weights/" + file_name
|
||||||
|
@ -2,13 +2,13 @@ from typing import List
|
|||||||
import os
|
import os
|
||||||
import gdown
|
import gdown
|
||||||
import numpy as np
|
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.commons.logger import Logger
|
||||||
from deepface.models.FacialRecognition import FacialRecognition
|
from deepface.models.FacialRecognition import FacialRecognition
|
||||||
|
|
||||||
logger = Logger(module="basemodels.DeepID")
|
logger = Logger(module="basemodels.DeepID")
|
||||||
|
|
||||||
tf_version = functions.get_tf_major_version()
|
tf_version = package_utils.get_tf_major_version()
|
||||||
|
|
||||||
if tf_version == 1:
|
if tf_version == 1:
|
||||||
from keras.models import Model
|
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:
|
if os.path.isfile(home + "/.deepface/weights/deepid_keras_weights.h5") != True:
|
||||||
logger.info("deepid_keras_weights.h5 will be downloaded...")
|
logger.info("deepid_keras_weights.h5 will be downloaded...")
|
||||||
|
@ -3,7 +3,7 @@ import os
|
|||||||
import bz2
|
import bz2
|
||||||
import gdown
|
import gdown
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from deepface.commons import functions
|
from deepface.commons import folder_utils
|
||||||
from deepface.commons.logger import Logger
|
from deepface.commons.logger import Logger
|
||||||
from deepface.models.FacialRecognition import FacialRecognition
|
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"
|
weight_file = home + "/.deepface/weights/dlib_face_recognition_resnet_model_v1.dat"
|
||||||
|
|
||||||
# ---------------------
|
# ---------------------
|
||||||
|
@ -2,7 +2,7 @@ from typing import List
|
|||||||
import os
|
import os
|
||||||
import gdown
|
import gdown
|
||||||
import numpy as np
|
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.commons.logger import Logger
|
||||||
from deepface.models.FacialRecognition import FacialRecognition
|
from deepface.models.FacialRecognition import FacialRecognition
|
||||||
|
|
||||||
@ -11,7 +11,7 @@ logger = Logger(module="basemodels.Facenet")
|
|||||||
# --------------------------------
|
# --------------------------------
|
||||||
# dependency configuration
|
# dependency configuration
|
||||||
|
|
||||||
tf_version = functions.get_tf_major_version()
|
tf_version = package_utils.get_tf_major_version()
|
||||||
|
|
||||||
if tf_version == 1:
|
if tf_version == 1:
|
||||||
from keras.models import Model
|
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:
|
if os.path.isfile(home + "/.deepface/weights/facenet_weights.h5") != True:
|
||||||
logger.info("facenet_weights.h5 will be downloaded...")
|
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:
|
if os.path.isfile(home + "/.deepface/weights/facenet512_weights.h5") != True:
|
||||||
logger.info("facenet512_weights.h5 will be downloaded...")
|
logger.info("facenet512_weights.h5 will be downloaded...")
|
||||||
|
@ -3,7 +3,7 @@ import os
|
|||||||
import zipfile
|
import zipfile
|
||||||
import gdown
|
import gdown
|
||||||
import numpy as np
|
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.commons.logger import Logger
|
||||||
from deepface.models.FacialRecognition import FacialRecognition
|
from deepface.models.FacialRecognition import FacialRecognition
|
||||||
|
|
||||||
@ -12,7 +12,7 @@ logger = Logger(module="basemodels.FbDeepFace")
|
|||||||
# --------------------------------
|
# --------------------------------
|
||||||
# dependency configuration
|
# dependency configuration
|
||||||
|
|
||||||
tf_version = functions.get_tf_major_version()
|
tf_version = package_utils.get_tf_major_version()
|
||||||
|
|
||||||
if tf_version == 1:
|
if tf_version == 1:
|
||||||
from keras.models import Model, Sequential
|
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:
|
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...")
|
logger.info("VGGFace2_DeepFace_weights_val-0.9034.h5 will be downloaded...")
|
||||||
|
@ -3,13 +3,13 @@ import os
|
|||||||
import gdown
|
import gdown
|
||||||
import tensorflow as tf
|
import tensorflow as tf
|
||||||
import numpy as np
|
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.commons.logger import Logger
|
||||||
from deepface.models.FacialRecognition import FacialRecognition
|
from deepface.models.FacialRecognition import FacialRecognition
|
||||||
|
|
||||||
logger = Logger(module="basemodels.OpenFace")
|
logger = Logger(module="basemodels.OpenFace")
|
||||||
|
|
||||||
tf_version = functions.get_tf_major_version()
|
tf_version = package_utils.get_tf_major_version()
|
||||||
if tf_version == 1:
|
if tf_version == 1:
|
||||||
from keras.models import Model
|
from keras.models import Model
|
||||||
from keras.layers import Conv2D, ZeroPadding2D, Input, concatenate
|
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:
|
if os.path.isfile(home + "/.deepface/weights/openface_weights.h5") != True:
|
||||||
logger.info("openface_weights.h5 will be downloaded...")
|
logger.info("openface_weights.h5 will be downloaded...")
|
||||||
|
@ -5,7 +5,7 @@ import numpy as np
|
|||||||
import cv2 as cv
|
import cv2 as cv
|
||||||
import gdown
|
import gdown
|
||||||
|
|
||||||
from deepface.commons import functions
|
from deepface.commons import folder_utils
|
||||||
from deepface.commons.logger import Logger
|
from deepface.commons.logger import Logger
|
||||||
from deepface.models.FacialRecognition import FacialRecognition
|
from deepface.models.FacialRecognition import FacialRecognition
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ def load_model(
|
|||||||
Construct SFace model, download its weights and load
|
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"
|
file_name = home + "/.deepface/weights/face_recognition_sface_2021dec.onnx"
|
||||||
|
|
||||||
|
@ -2,7 +2,8 @@ from typing import List
|
|||||||
import os
|
import os
|
||||||
import gdown
|
import gdown
|
||||||
import numpy as np
|
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.models.FacialRecognition import FacialRecognition
|
||||||
from deepface.commons.logger import Logger
|
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:
|
if tf_version == 1:
|
||||||
from keras.models import Model, Sequential
|
from keras.models import Model, Sequential
|
||||||
from keras.layers import (
|
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)
|
# 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
|
# instead we are now calculating it with traditional way not with keras backend
|
||||||
embedding = self.model(img, training=False).numpy()[0].tolist()
|
embedding = self.model(img, training=False).numpy()[0].tolist()
|
||||||
embedding = distance.l2_normalize(embedding)
|
embedding = verification.l2_normalize(embedding)
|
||||||
return embedding.tolist()
|
return embedding.tolist()
|
||||||
|
|
||||||
|
|
||||||
@ -128,7 +129,7 @@ def load_model(
|
|||||||
|
|
||||||
model = base_model()
|
model = base_model()
|
||||||
|
|
||||||
home = functions.get_deepface_home()
|
home = folder_utils.get_deepface_home()
|
||||||
output = home + "/.deepface/weights/vgg_face_weights.h5"
|
output = home + "/.deepface/weights/vgg_face_weights.h5"
|
||||||
|
|
||||||
if os.path.isfile(output) != True:
|
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 bz2
|
||||||
import gdown
|
import gdown
|
||||||
import numpy as np
|
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.models.Detector import Detector, DetectedFace, FacialAreaRegion
|
||||||
from deepface.commons.logger import Logger
|
from deepface.commons.logger import Logger
|
||||||
|
|
||||||
@ -20,7 +20,7 @@ class DlibClient(Detector):
|
|||||||
Returns:
|
Returns:
|
||||||
model (Any)
|
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.
|
# this is not a must dependency. do not import it in the global level.
|
||||||
try:
|
try:
|
||||||
|
@ -36,7 +36,9 @@ class RetinaFaceClient(Detector):
|
|||||||
|
|
||||||
obj = rf.detect_faces(img, model=self.model, threshold=0.9)
|
obj = rf.detect_faces(img, model=self.model, threshold=0.9)
|
||||||
|
|
||||||
if isinstance(obj, dict):
|
if not isinstance(obj, dict):
|
||||||
|
return resp
|
||||||
|
|
||||||
for face_idx in obj.keys():
|
for face_idx in obj.keys():
|
||||||
identity = obj[face_idx]
|
identity = obj[face_idx]
|
||||||
facial_area = identity["facial_area"]
|
facial_area = identity["facial_area"]
|
||||||
|
@ -5,7 +5,7 @@ import cv2
|
|||||||
import pandas as pd
|
import pandas as pd
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from deepface.detectors import OpenCv
|
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.models.Detector import Detector, DetectedFace, FacialAreaRegion
|
||||||
from deepface.modules import detection
|
from deepface.modules import detection
|
||||||
from deepface.commons.logger import Logger
|
from deepface.commons.logger import Logger
|
||||||
@ -26,7 +26,7 @@ class SsdClient(Detector):
|
|||||||
model (dict)
|
model (dict)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
home = functions.get_deepface_home()
|
home = folder_utils.get_deepface_home()
|
||||||
|
|
||||||
# model structure
|
# model structure
|
||||||
if os.path.isfile(home + "/.deepface/weights/deploy.prototxt") != True:
|
if os.path.isfile(home + "/.deepface/weights/deploy.prototxt") != True:
|
||||||
|
@ -4,6 +4,7 @@ import numpy as np
|
|||||||
import gdown
|
import gdown
|
||||||
from deepface.models.Detector import Detector, DetectedFace, FacialAreaRegion
|
from deepface.models.Detector import Detector, DetectedFace, FacialAreaRegion
|
||||||
from deepface.modules import detection
|
from deepface.modules import detection
|
||||||
|
from deepface.commons import folder_utils
|
||||||
from deepface.commons.logger import Logger
|
from deepface.commons.logger import Logger
|
||||||
|
|
||||||
logger = Logger()
|
logger = Logger()
|
||||||
@ -39,9 +40,7 @@ class YoloClient(Detector):
|
|||||||
Please install using 'pip install ultralytics' "
|
Please install using 'pip install ultralytics' "
|
||||||
) from e
|
) from e
|
||||||
|
|
||||||
from deepface.commons.functions import get_deepface_home
|
weight_path = f"{folder_utils.get_deepface_home()}{PATH}"
|
||||||
|
|
||||||
weight_path = f"{get_deepface_home()}{PATH}"
|
|
||||||
|
|
||||||
# Download the model's weights if they don't exist
|
# Download the model's weights if they don't exist
|
||||||
if not os.path.isfile(weight_path):
|
if not os.path.isfile(weight_path):
|
||||||
|
@ -3,7 +3,7 @@ from typing import Any, List
|
|||||||
import cv2
|
import cv2
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import gdown
|
import gdown
|
||||||
from deepface.commons import functions
|
from deepface.commons import folder_utils
|
||||||
from deepface.models.Detector import Detector, DetectedFace, FacialAreaRegion
|
from deepface.models.Detector import Detector, DetectedFace, FacialAreaRegion
|
||||||
from deepface.modules import detection
|
from deepface.modules import detection
|
||||||
from deepface.commons.logger import Logger
|
from deepface.commons.logger import Logger
|
||||||
@ -31,7 +31,7 @@ class YuNetClient(Detector):
|
|||||||
# pylint: disable=C0301
|
# pylint: disable=C0301
|
||||||
url = "https://github.com/opencv/opencv_zoo/raw/main/models/face_detection_yunet/face_detection_yunet_2023mar.onnx"
|
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"
|
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:
|
if os.path.isfile(home + f"/.deepface/weights/{file_name}") is False:
|
||||||
logger.info(f"{file_name} will be downloaded...")
|
logger.info(f"{file_name} will be downloaded...")
|
||||||
output = home + f"/.deepface/weights/{file_name}"
|
output = home + f"/.deepface/weights/{file_name}"
|
||||||
|
@ -2,7 +2,7 @@ import os
|
|||||||
import gdown
|
import gdown
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from deepface.basemodels import VGGFace
|
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.commons.logger import Logger
|
||||||
from deepface.models.Demography import Demography
|
from deepface.models.Demography import Demography
|
||||||
|
|
||||||
@ -11,7 +11,7 @@ logger = Logger(module="extendedmodels.Age")
|
|||||||
# ----------------------------------------
|
# ----------------------------------------
|
||||||
# dependency configurations
|
# dependency configurations
|
||||||
|
|
||||||
tf_version = functions.get_tf_major_version()
|
tf_version = package_utils.get_tf_major_version()
|
||||||
|
|
||||||
if tf_version == 1:
|
if tf_version == 1:
|
||||||
from keras.models import Model, Sequential
|
from keras.models import Model, Sequential
|
||||||
@ -64,7 +64,7 @@ def load_model(
|
|||||||
|
|
||||||
# load weights
|
# 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:
|
if os.path.isfile(home + "/.deepface/weights/age_model_weights.h5") != True:
|
||||||
logger.info("age_model_weights.h5 will be downloaded...")
|
logger.info("age_model_weights.h5 will be downloaded...")
|
||||||
|
@ -2,7 +2,7 @@ import os
|
|||||||
import gdown
|
import gdown
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import cv2
|
import cv2
|
||||||
from deepface.commons import functions
|
from deepface.commons import package_utils, folder_utils
|
||||||
from deepface.commons.logger import Logger
|
from deepface.commons.logger import Logger
|
||||||
from deepface.models.Demography import Demography
|
from deepface.models.Demography import Demography
|
||||||
|
|
||||||
@ -12,7 +12,7 @@ logger = Logger(module="extendedmodels.Emotion")
|
|||||||
# pylint: disable=line-too-long
|
# pylint: disable=line-too-long
|
||||||
# -------------------------------------------
|
# -------------------------------------------
|
||||||
# dependency configuration
|
# dependency configuration
|
||||||
tf_version = functions.get_tf_major_version()
|
tf_version = package_utils.get_tf_major_version()
|
||||||
|
|
||||||
if tf_version == 1:
|
if tf_version == 1:
|
||||||
from keras.models import Sequential
|
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:
|
if os.path.isfile(home + "/.deepface/weights/facial_expression_model_weights.h5") != True:
|
||||||
logger.info("facial_expression_model_weights.h5 will be downloaded...")
|
logger.info("facial_expression_model_weights.h5 will be downloaded...")
|
||||||
|
@ -2,7 +2,7 @@ import os
|
|||||||
import gdown
|
import gdown
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from deepface.basemodels import VGGFace
|
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.commons.logger import Logger
|
||||||
from deepface.models.Demography import Demography
|
from deepface.models.Demography import Demography
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ logger = Logger(module="extendedmodels.Gender")
|
|||||||
# -------------------------------------
|
# -------------------------------------
|
||||||
# dependency configurations
|
# dependency configurations
|
||||||
|
|
||||||
tf_version = functions.get_tf_major_version()
|
tf_version = package_utils.get_tf_major_version()
|
||||||
if tf_version == 1:
|
if tf_version == 1:
|
||||||
from keras.models import Model, Sequential
|
from keras.models import Model, Sequential
|
||||||
from keras.layers import Convolution2D, Flatten, Activation
|
from keras.layers import Convolution2D, Flatten, Activation
|
||||||
@ -66,7 +66,7 @@ def load_model(
|
|||||||
|
|
||||||
# load weights
|
# 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:
|
if os.path.isfile(home + "/.deepface/weights/gender_model_weights.h5") != True:
|
||||||
logger.info("gender_model_weights.h5 will be downloaded...")
|
logger.info("gender_model_weights.h5 will be downloaded...")
|
||||||
|
@ -2,7 +2,7 @@ import os
|
|||||||
import gdown
|
import gdown
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from deepface.basemodels import VGGFace
|
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.commons.logger import Logger
|
||||||
from deepface.models.Demography import Demography
|
from deepface.models.Demography import Demography
|
||||||
|
|
||||||
@ -12,7 +12,7 @@ logger = Logger(module="extendedmodels.Race")
|
|||||||
# pylint: disable=line-too-long
|
# pylint: disable=line-too-long
|
||||||
# --------------------------
|
# --------------------------
|
||||||
# dependency configurations
|
# dependency configurations
|
||||||
tf_version = functions.get_tf_major_version()
|
tf_version = package_utils.get_tf_major_version()
|
||||||
|
|
||||||
if tf_version == 1:
|
if tf_version == 1:
|
||||||
from keras.models import Model, Sequential
|
from keras.models import Model, Sequential
|
||||||
@ -63,7 +63,7 @@ def load_model(
|
|||||||
|
|
||||||
# load weights
|
# 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:
|
if os.path.isfile(home + "/.deepface/weights/race_model_single_batch.h5") != True:
|
||||||
logger.info("race_model_single_batch.h5 will be downloaded...")
|
logger.info("race_model_single_batch.h5 will be downloaded...")
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
from typing import Union
|
from typing import Union
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
import numpy as np
|
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:
|
if tf_version == 1:
|
||||||
from keras.models import Model
|
from keras.models import Model
|
||||||
else:
|
else:
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from typing import Any, Union, List, Tuple
|
from typing import Any, Union, List, Tuple
|
||||||
import numpy as np
|
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:
|
if tf_version == 2:
|
||||||
from tensorflow.keras.models import Model
|
from tensorflow.keras.models import Model
|
||||||
else:
|
else:
|
||||||
|
@ -10,7 +10,7 @@ from PIL import Image
|
|||||||
from deepface.modules import preprocessing
|
from deepface.modules import preprocessing
|
||||||
from deepface.models.Detector import DetectedFace, FacialAreaRegion
|
from deepface.models.Detector import DetectedFace, FacialAreaRegion
|
||||||
from deepface.detectors import DetectorWrapper
|
from deepface.detectors import DetectorWrapper
|
||||||
from deepface.commons import functions
|
from deepface.commons import package_utils
|
||||||
from deepface.commons.logger import Logger
|
from deepface.commons.logger import Logger
|
||||||
|
|
||||||
logger = Logger(module="deepface/modules/detection.py")
|
logger = Logger(module="deepface/modules/detection.py")
|
||||||
@ -18,7 +18,7 @@ logger = Logger(module="deepface/modules/detection.py")
|
|||||||
# pylint: disable=no-else-raise
|
# 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:
|
if tf_major_version == 1:
|
||||||
from keras.preprocessing import image
|
from keras.preprocessing import image
|
||||||
elif tf_major_version == 2:
|
elif tf_major_version == 2:
|
||||||
@ -63,8 +63,11 @@ def extract_faces(
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
results (List[Dict[str, Any]]): A list of dictionaries, where each dictionary contains:
|
results (List[Dict[str, Any]]): A list of dictionaries, where each dictionary contains:
|
||||||
|
|
||||||
- "face" (np.ndarray): The detected face as a NumPy array.
|
- "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.
|
- "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.
|
- "confidence" (float): The confidence score associated with the detected face.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -10,9 +10,8 @@ import pandas as pd
|
|||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
|
|
||||||
# project dependencies
|
# project dependencies
|
||||||
from deepface.commons import distance as dst
|
|
||||||
from deepface.commons.logger import Logger
|
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
|
from deepface.models.FacialRecognition import FacialRecognition
|
||||||
|
|
||||||
logger = Logger(module="deepface/modules/recognition.py")
|
logger = Logger(module="deepface/modules/recognition.py")
|
||||||
@ -253,13 +252,17 @@ def find(
|
|||||||
)
|
)
|
||||||
|
|
||||||
if distance_metric == "cosine":
|
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":
|
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":
|
elif distance_metric == "euclidean_l2":
|
||||||
distance = dst.find_euclidean_distance(
|
distance = verification.find_euclidean_distance(
|
||||||
dst.l2_normalize(source_representation),
|
verification.l2_normalize(source_representation),
|
||||||
dst.l2_normalize(target_representation),
|
verification.l2_normalize(target_representation),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"invalid distance metric passes - {distance_metric}")
|
raise ValueError(f"invalid distance metric passes - {distance_metric}")
|
||||||
@ -267,7 +270,7 @@ def find(
|
|||||||
distances.append(distance)
|
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["threshold"] = target_threshold
|
||||||
result_df["distance"] = distances
|
result_df["distance"] = distances
|
||||||
|
@ -6,7 +6,6 @@ from typing import Any, Dict, Union
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
# project dependencies
|
# project dependencies
|
||||||
from deepface.commons import distance as dst
|
|
||||||
from deepface.modules import representation, detection, modeling
|
from deepface.modules import representation, detection, modeling
|
||||||
from deepface.models.FacialRecognition import FacialRecognition
|
from deepface.models.FacialRecognition import FacialRecognition
|
||||||
|
|
||||||
@ -138,12 +137,12 @@ def verify(
|
|||||||
img2_representation = img2_embedding_obj[0]["embedding"]
|
img2_representation = img2_embedding_obj[0]["embedding"]
|
||||||
|
|
||||||
if distance_metric == "cosine":
|
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":
|
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":
|
elif distance_metric == "euclidean_l2":
|
||||||
distance = dst.find_euclidean_distance(
|
distance = find_euclidean_distance(
|
||||||
dst.l2_normalize(img1_representation), dst.l2_normalize(img2_representation)
|
l2_normalize(img1_representation), l2_normalize(img2_representation)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
raise ValueError("Invalid distance_metric passed - ", distance_metric)
|
raise ValueError("Invalid distance_metric passed - ", distance_metric)
|
||||||
@ -152,7 +151,7 @@ def verify(
|
|||||||
regions.append((img1_region, img2_region))
|
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
|
distance = min(distances) # best distance
|
||||||
facial_areas = regions[np.argmin(distances)]
|
facial_areas = regions[np.argmin(distances)]
|
||||||
|
|
||||||
@ -171,3 +170,65 @@ def verify(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return resp_obj
|
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
|
#!/usr/bin/env bash
|
||||||
cd ../api
|
cd ../api/src
|
||||||
gunicorn --workers=1 --timeout=3600 --bind=0.0.0.0:5000 "app:create_app()"
|
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
|
import setuptools
|
||||||
|
|
||||||
with open("README.md", "r", encoding="utf-8") as fh:
|
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:
|
with open("requirements.txt", "r", encoding="utf-8") as f:
|
||||||
requirements = f.read().split("\n")
|
requirements = f.read().split("\n")
|
||||||
|
|
||||||
|
with open("package_info.json", "r", encoding="utf-8") as f:
|
||||||
|
package_info = json.load(f)
|
||||||
|
|
||||||
setuptools.setup(
|
setuptools.setup(
|
||||||
name="deepface",
|
name="deepface",
|
||||||
version="0.0.84",
|
version=package_info["version"],
|
||||||
author="Sefik Ilkin Serengil",
|
author="Sefik Ilkin Serengil",
|
||||||
author_email="serengil@gmail.com",
|
author_email="serengil@gmail.com",
|
||||||
description="A Lightweight Face Recognition and Facial Attribute Analysis Framework (Age, Gender, Emotion, Race) for Python",
|
description=(
|
||||||
data_files=[("", ["README.md", "requirements.txt"])],
|
"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=long_description,
|
||||||
long_description_content_type="text/markdown",
|
long_description_content_type="text/markdown",
|
||||||
url="https://github.com/serengil/deepface",
|
url="https://github.com/serengil/deepface",
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from deepface import DeepFace
|
from deepface import DeepFace
|
||||||
from deepface.commons import distance
|
from deepface.modules import verification
|
||||||
from deepface.models.FacialRecognition import FacialRecognition
|
from deepface.models.FacialRecognition import FacialRecognition
|
||||||
from deepface.commons.logger import Logger
|
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())
|
current_distance = np.sqrt(distance_vector.sum())
|
||||||
logger.info(f"Euclidean distance: {current_distance}")
|
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}")
|
logger.info(f"Threshold for {model_name}-euclidean pair is {threshold}")
|
||||||
|
|
||||||
if current_distance < threshold:
|
if current_distance < threshold:
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import cv2
|
import cv2
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
from deepface import DeepFace
|
from deepface import DeepFace
|
||||||
from deepface.commons import distance
|
from deepface.modules import verification
|
||||||
from deepface.commons.logger import Logger
|
from deepface.commons.logger import Logger
|
||||||
|
|
||||||
logger = Logger("tests/test_find.py")
|
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():
|
def test_find_with_exact_path():
|
||||||
|
@ -20,7 +20,16 @@ model_names = [
|
|||||||
"SFace",
|
"SFace",
|
||||||
]
|
]
|
||||||
|
|
||||||
detector_backends = ["opencv", "ssd", "dlib", "mtcnn", "retinaface", "yunet", "yolov8"]
|
detector_backends = [
|
||||||
|
"opencv",
|
||||||
|
"ssd",
|
||||||
|
"dlib",
|
||||||
|
"mtcnn",
|
||||||
|
# "mediapipe", # crashed in mac
|
||||||
|
"retinaface",
|
||||||
|
"yunet",
|
||||||
|
"yolov8",
|
||||||
|
]
|
||||||
|
|
||||||
# verification
|
# verification
|
||||||
for model_name in model_names:
|
for model_name in model_names:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user