fast-face-python 0.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fast_face_python-0.1.1/LICENSE +21 -0
- fast_face_python-0.1.1/MANIFEST.in +6 -0
- fast_face_python-0.1.1/PKG-INFO +237 -0
- fast_face_python-0.1.1/README.md +207 -0
- fast_face_python-0.1.1/pyproject.toml +49 -0
- fast_face_python-0.1.1/setup.cfg +4 -0
- fast_face_python-0.1.1/src/fast_face/__init__.py +6 -0
- fast_face_python-0.1.1/src/fast_face/models/__init__.py +11 -0
- fast_face_python-0.1.1/src/fast_face/models/adaface.py +91 -0
- fast_face_python-0.1.1/src/fast_face/models/base.py +108 -0
- fast_face_python-0.1.1/src/fast_face/models/base_recognition.py +46 -0
- fast_face_python-0.1.1/src/fast_face/models/downloader.py +46 -0
- fast_face_python-0.1.1/src/fast_face/models/factory.py +69 -0
- fast_face_python-0.1.1/src/fast_face/models/retinaface.py +109 -0
- fast_face_python-0.1.1/src/fast_face/models/session.py +29 -0
- fast_face_python-0.1.1/src/fast_face/models/yunet.py +202 -0
- fast_face_python-0.1.1/src/fast_face/schema.py +13 -0
- fast_face_python-0.1.1/src/fast_face/tools.py +501 -0
- fast_face_python-0.1.1/src/fast_face_python.egg-info/PKG-INFO +237 -0
- fast_face_python-0.1.1/src/fast_face_python.egg-info/SOURCES.txt +25 -0
- fast_face_python-0.1.1/src/fast_face_python.egg-info/dependency_links.txt +1 -0
- fast_face_python-0.1.1/src/fast_face_python.egg-info/requires.txt +25 -0
- fast_face_python-0.1.1/src/fast_face_python.egg-info/top_level.txt +1 -0
- fast_face_python-0.1.1/tests/test_adaface.py +126 -0
- fast_face_python-0.1.1/tests/test_import.py +9 -0
- fast_face_python-0.1.1/tests/test_retinaface.py +39 -0
- fast_face_python-0.1.1/tests/test_yunet.py +21 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 xMaulana
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fast-face-python
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Fast and easy face detection using ONNX runtime.
|
|
5
|
+
Author: xMaulana
|
|
6
|
+
Requires-Python: >=3.11
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Requires-Dist: numpy
|
|
10
|
+
Requires-Dist: Pillow
|
|
11
|
+
Requires-Dist: opencv-python
|
|
12
|
+
Requires-Dist: pydantic-settings>=2.15.0
|
|
13
|
+
Provides-Extra: cpu
|
|
14
|
+
Requires-Dist: onnxruntime>=1.24.3; extra == "cpu"
|
|
15
|
+
Provides-Extra: gpu
|
|
16
|
+
Requires-Dist: onnxruntime-gpu<=1.26.1,>=1.24.3; extra == "gpu"
|
|
17
|
+
Requires-Dist: nvidia-cudnn-cu12; extra == "gpu"
|
|
18
|
+
Requires-Dist: nvidia-cublas-cu12; extra == "gpu"
|
|
19
|
+
Requires-Dist: nvidia-cuda-runtime-cu12; extra == "gpu"
|
|
20
|
+
Provides-Extra: openvino
|
|
21
|
+
Requires-Dist: onnxruntime-openvino>=1.24.1; extra == "openvino"
|
|
22
|
+
Provides-Extra: rocm
|
|
23
|
+
Requires-Dist: onnxruntime-rocm>=1.22.1; extra == "rocm"
|
|
24
|
+
Provides-Extra: dev
|
|
25
|
+
Requires-Dist: pytest; extra == "dev"
|
|
26
|
+
Requires-Dist: ruff; extra == "dev"
|
|
27
|
+
Requires-Dist: build; extra == "dev"
|
|
28
|
+
Requires-Dist: twine; extra == "dev"
|
|
29
|
+
Dynamic: license-file
|
|
30
|
+
|
|
31
|
+
# fast-face-python
|
|
32
|
+
|
|
33
|
+
Fast and easy face detection using ONNX runtime.
|
|
34
|
+
|
|
35
|
+
## Overview
|
|
36
|
+
|
|
37
|
+
fast-face-python provides a unified interface for running face detection and recognition models using ONNX Runtime. It handles model downloading, preprocessing, inference, and post-processing, including non-maximum suppression for detection and alignment for recognition.
|
|
38
|
+
|
|
39
|
+
The library supports batched inference and configurable execution providers such as CPU, CUDA, ROCm (AMD GPU), and OpenVINO.
|
|
40
|
+
|
|
41
|
+
## Features
|
|
42
|
+
|
|
43
|
+
* Face Detection: YuNet, RetinaFace (MobileNet, ResNet50)
|
|
44
|
+
* Face Recognition: AdaFace (IR18, IR50, IR101)
|
|
45
|
+
* Hardware Acceleration: CPU, CUDA, ROCm (AMD GPU), and OpenVINO support via ONNX Runtime
|
|
46
|
+
* Batched Inference: Process multiple images simultaneously
|
|
47
|
+
* Automatic Model Management: Downloads required ONNX model weights on first use
|
|
48
|
+
|
|
49
|
+
## Requirements
|
|
50
|
+
|
|
51
|
+
* Python >= 3.11
|
|
52
|
+
* OpenCV
|
|
53
|
+
* NumPy
|
|
54
|
+
* Pillow
|
|
55
|
+
* ONNX Runtime
|
|
56
|
+
|
|
57
|
+
## Installation
|
|
58
|
+
|
|
59
|
+
Install the package using pip:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
pip install fast-face-python
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
For NVIDIA GPU support via CUDA 12:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
pip install "fast-face-python[gpu]"
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
For AMD GPU support via ROCm:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
pip install "fast-face-python[rocm]"
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
For OpenVINO support:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
pip install "fast-face-python[openvino]"
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Usage
|
|
84
|
+
|
|
85
|
+
### Face Detection
|
|
86
|
+
|
|
87
|
+
Instantiate a detection model using `FaceModelFactory` and call the `detect` method. The method accepts an image path, a NumPy array in RGB format, or a list of either.
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
from fast_face import FaceModelFactory
|
|
91
|
+
|
|
92
|
+
# Initialize the model (weights are downloaded automatically if missing)
|
|
93
|
+
model = FaceModelFactory.get_model("YUNET", top_k=500, conf_threshold=0.6)
|
|
94
|
+
|
|
95
|
+
# Run detection on a local image file
|
|
96
|
+
results = model.detect("image.jpg", return_dict=True)
|
|
97
|
+
|
|
98
|
+
# Process the detections for the first image
|
|
99
|
+
for det in results[0]:
|
|
100
|
+
bbox = det["bbox"]
|
|
101
|
+
confidence = det["score"]
|
|
102
|
+
landmarks = det["landmarks"]
|
|
103
|
+
print(f"Face detected at {bbox} with confidence {confidence}")
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
To run inference on an existing OpenCV image, convert it to RGB first:
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
import cv2
|
|
110
|
+
|
|
111
|
+
img = cv2.imread("image.jpg")
|
|
112
|
+
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
|
|
113
|
+
|
|
114
|
+
results = model.detect(img_rgb, return_dict=True)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Face Recognition
|
|
118
|
+
|
|
119
|
+
Recognition models extract L2-normalized embeddings from aligned face images.
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
import numpy as np
|
|
123
|
+
from fast_face import FaceModelFactory
|
|
124
|
+
|
|
125
|
+
model = FaceModelFactory.get_model("ADAFACE_IR50")
|
|
126
|
+
|
|
127
|
+
# Provide pre-aligned 112x112 RGB face crops
|
|
128
|
+
face_crop1 = np.random.randint(0, 255, (112, 112, 3), dtype=np.uint8)
|
|
129
|
+
face_crop2 = np.random.randint(0, 255, (112, 112, 3), dtype=np.uint8)
|
|
130
|
+
|
|
131
|
+
# Extract embeddings for the batch
|
|
132
|
+
embeddings = model.extract([face_crop1, face_crop2])
|
|
133
|
+
|
|
134
|
+
print(f"Extracted {embeddings.shape[0]} embeddings of dimension {embeddings.shape[1]}")
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
If you have unaligned images and face landmarks from a detection model, you can pass the landmarks to automatically align the faces before extraction:
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
landmarks = np.array([
|
|
141
|
+
[200.0, 200.0], [280.0, 200.0], [240.0, 250.0],
|
|
142
|
+
[210.0, 300.0], [270.0, 300.0]
|
|
143
|
+
], dtype=np.float32)
|
|
144
|
+
|
|
145
|
+
embeddings = model.extract([img_rgb], landmarks=[landmarks])
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Execution Providers (Hardware Acceleration)
|
|
149
|
+
|
|
150
|
+
By default, all models run using CPU (`["CPUExecutionProvider"]`). You can enable hardware acceleration (CUDA, ROCm, OpenVINO, CoreML, etc.) by passing the `providers` argument to `FaceModelFactory.get_model()`:
|
|
151
|
+
|
|
152
|
+
#### NVIDIA GPU (CUDA)
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
model = FaceModelFactory.get_model(
|
|
156
|
+
"RETINAFACE_RESNET50",
|
|
157
|
+
providers=["CUDAExecutionProvider", "CPUExecutionProvider"],
|
|
158
|
+
)
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
#### AMD GPU (ROCm)
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
model = FaceModelFactory.get_model(
|
|
165
|
+
"ADAFACE_IR101",
|
|
166
|
+
providers=["ROCMExecutionProvider", "CPUExecutionProvider"],
|
|
167
|
+
)
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
#### Intel OpenVINO
|
|
171
|
+
|
|
172
|
+
```python
|
|
173
|
+
model = FaceModelFactory.get_model(
|
|
174
|
+
"YUNET",
|
|
175
|
+
providers=["OpenVINOExecutionProvider", "CPUExecutionProvider"],
|
|
176
|
+
)
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
#### Custom Provider Options
|
|
180
|
+
|
|
181
|
+
You can also pass tuple configurations with custom options (such as device ID or memory limits):
|
|
182
|
+
|
|
183
|
+
```python
|
|
184
|
+
cuda_provider = (
|
|
185
|
+
"CUDAExecutionProvider",
|
|
186
|
+
{
|
|
187
|
+
"device_id": 0,
|
|
188
|
+
"arena_extend_strategy": "kNextPowerOfTwo",
|
|
189
|
+
"gpu_mem_limit": 2 * 1024 * 1024 * 1024, # 2 GB
|
|
190
|
+
},
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
model = FaceModelFactory.get_model(
|
|
194
|
+
"RETINAFACE_RESNET50",
|
|
195
|
+
providers=[cuda_provider, "CPUExecutionProvider"],
|
|
196
|
+
)
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Supported Models
|
|
200
|
+
|
|
201
|
+
The following model identifiers are supported by `FaceModelFactory`:
|
|
202
|
+
|
|
203
|
+
* `YUNET`
|
|
204
|
+
* `RETINAFACE_MOBILENET`
|
|
205
|
+
* `RETINAFACE_RESNET50`
|
|
206
|
+
* `ADAFACE_IR18`
|
|
207
|
+
* `ADAFACE_IR50`
|
|
208
|
+
* `ADAFACE_IR101`
|
|
209
|
+
|
|
210
|
+
## Development
|
|
211
|
+
|
|
212
|
+
To set up the repository for development, install the `dev` dependencies:
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
pip install -e ".[dev,cpu]"
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Testing
|
|
219
|
+
|
|
220
|
+
The project uses `pytest` for testing. Run the test suite:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
pytest tests/
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Formatting and Linting
|
|
227
|
+
|
|
228
|
+
The project uses `ruff` for code formatting and linting:
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
ruff check .
|
|
232
|
+
ruff format .
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## License
|
|
236
|
+
|
|
237
|
+
This project is licensed under the terms found in the `LICENSE` file.
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# fast-face-python
|
|
2
|
+
|
|
3
|
+
Fast and easy face detection using ONNX runtime.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
fast-face-python provides a unified interface for running face detection and recognition models using ONNX Runtime. It handles model downloading, preprocessing, inference, and post-processing, including non-maximum suppression for detection and alignment for recognition.
|
|
8
|
+
|
|
9
|
+
The library supports batched inference and configurable execution providers such as CPU, CUDA, ROCm (AMD GPU), and OpenVINO.
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
* Face Detection: YuNet, RetinaFace (MobileNet, ResNet50)
|
|
14
|
+
* Face Recognition: AdaFace (IR18, IR50, IR101)
|
|
15
|
+
* Hardware Acceleration: CPU, CUDA, ROCm (AMD GPU), and OpenVINO support via ONNX Runtime
|
|
16
|
+
* Batched Inference: Process multiple images simultaneously
|
|
17
|
+
* Automatic Model Management: Downloads required ONNX model weights on first use
|
|
18
|
+
|
|
19
|
+
## Requirements
|
|
20
|
+
|
|
21
|
+
* Python >= 3.11
|
|
22
|
+
* OpenCV
|
|
23
|
+
* NumPy
|
|
24
|
+
* Pillow
|
|
25
|
+
* ONNX Runtime
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
Install the package using pip:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install fast-face-python
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
For NVIDIA GPU support via CUDA 12:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pip install "fast-face-python[gpu]"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
For AMD GPU support via ROCm:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install "fast-face-python[rocm]"
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
For OpenVINO support:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pip install "fast-face-python[openvino]"
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Usage
|
|
54
|
+
|
|
55
|
+
### Face Detection
|
|
56
|
+
|
|
57
|
+
Instantiate a detection model using `FaceModelFactory` and call the `detect` method. The method accepts an image path, a NumPy array in RGB format, or a list of either.
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
from fast_face import FaceModelFactory
|
|
61
|
+
|
|
62
|
+
# Initialize the model (weights are downloaded automatically if missing)
|
|
63
|
+
model = FaceModelFactory.get_model("YUNET", top_k=500, conf_threshold=0.6)
|
|
64
|
+
|
|
65
|
+
# Run detection on a local image file
|
|
66
|
+
results = model.detect("image.jpg", return_dict=True)
|
|
67
|
+
|
|
68
|
+
# Process the detections for the first image
|
|
69
|
+
for det in results[0]:
|
|
70
|
+
bbox = det["bbox"]
|
|
71
|
+
confidence = det["score"]
|
|
72
|
+
landmarks = det["landmarks"]
|
|
73
|
+
print(f"Face detected at {bbox} with confidence {confidence}")
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
To run inference on an existing OpenCV image, convert it to RGB first:
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
import cv2
|
|
80
|
+
|
|
81
|
+
img = cv2.imread("image.jpg")
|
|
82
|
+
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
|
|
83
|
+
|
|
84
|
+
results = model.detect(img_rgb, return_dict=True)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Face Recognition
|
|
88
|
+
|
|
89
|
+
Recognition models extract L2-normalized embeddings from aligned face images.
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
import numpy as np
|
|
93
|
+
from fast_face import FaceModelFactory
|
|
94
|
+
|
|
95
|
+
model = FaceModelFactory.get_model("ADAFACE_IR50")
|
|
96
|
+
|
|
97
|
+
# Provide pre-aligned 112x112 RGB face crops
|
|
98
|
+
face_crop1 = np.random.randint(0, 255, (112, 112, 3), dtype=np.uint8)
|
|
99
|
+
face_crop2 = np.random.randint(0, 255, (112, 112, 3), dtype=np.uint8)
|
|
100
|
+
|
|
101
|
+
# Extract embeddings for the batch
|
|
102
|
+
embeddings = model.extract([face_crop1, face_crop2])
|
|
103
|
+
|
|
104
|
+
print(f"Extracted {embeddings.shape[0]} embeddings of dimension {embeddings.shape[1]}")
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
If you have unaligned images and face landmarks from a detection model, you can pass the landmarks to automatically align the faces before extraction:
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
landmarks = np.array([
|
|
111
|
+
[200.0, 200.0], [280.0, 200.0], [240.0, 250.0],
|
|
112
|
+
[210.0, 300.0], [270.0, 300.0]
|
|
113
|
+
], dtype=np.float32)
|
|
114
|
+
|
|
115
|
+
embeddings = model.extract([img_rgb], landmarks=[landmarks])
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Execution Providers (Hardware Acceleration)
|
|
119
|
+
|
|
120
|
+
By default, all models run using CPU (`["CPUExecutionProvider"]`). You can enable hardware acceleration (CUDA, ROCm, OpenVINO, CoreML, etc.) by passing the `providers` argument to `FaceModelFactory.get_model()`:
|
|
121
|
+
|
|
122
|
+
#### NVIDIA GPU (CUDA)
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
model = FaceModelFactory.get_model(
|
|
126
|
+
"RETINAFACE_RESNET50",
|
|
127
|
+
providers=["CUDAExecutionProvider", "CPUExecutionProvider"],
|
|
128
|
+
)
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
#### AMD GPU (ROCm)
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
model = FaceModelFactory.get_model(
|
|
135
|
+
"ADAFACE_IR101",
|
|
136
|
+
providers=["ROCMExecutionProvider", "CPUExecutionProvider"],
|
|
137
|
+
)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
#### Intel OpenVINO
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
model = FaceModelFactory.get_model(
|
|
144
|
+
"YUNET",
|
|
145
|
+
providers=["OpenVINOExecutionProvider", "CPUExecutionProvider"],
|
|
146
|
+
)
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
#### Custom Provider Options
|
|
150
|
+
|
|
151
|
+
You can also pass tuple configurations with custom options (such as device ID or memory limits):
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
cuda_provider = (
|
|
155
|
+
"CUDAExecutionProvider",
|
|
156
|
+
{
|
|
157
|
+
"device_id": 0,
|
|
158
|
+
"arena_extend_strategy": "kNextPowerOfTwo",
|
|
159
|
+
"gpu_mem_limit": 2 * 1024 * 1024 * 1024, # 2 GB
|
|
160
|
+
},
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
model = FaceModelFactory.get_model(
|
|
164
|
+
"RETINAFACE_RESNET50",
|
|
165
|
+
providers=[cuda_provider, "CPUExecutionProvider"],
|
|
166
|
+
)
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Supported Models
|
|
170
|
+
|
|
171
|
+
The following model identifiers are supported by `FaceModelFactory`:
|
|
172
|
+
|
|
173
|
+
* `YUNET`
|
|
174
|
+
* `RETINAFACE_MOBILENET`
|
|
175
|
+
* `RETINAFACE_RESNET50`
|
|
176
|
+
* `ADAFACE_IR18`
|
|
177
|
+
* `ADAFACE_IR50`
|
|
178
|
+
* `ADAFACE_IR101`
|
|
179
|
+
|
|
180
|
+
## Development
|
|
181
|
+
|
|
182
|
+
To set up the repository for development, install the `dev` dependencies:
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
pip install -e ".[dev,cpu]"
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Testing
|
|
189
|
+
|
|
190
|
+
The project uses `pytest` for testing. Run the test suite:
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
pytest tests/
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Formatting and Linting
|
|
197
|
+
|
|
198
|
+
The project uses `ruff` for code formatting and linting:
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
ruff check .
|
|
202
|
+
ruff format .
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## License
|
|
206
|
+
|
|
207
|
+
This project is licensed under the terms found in the `LICENSE` file.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "fast-face-python"
|
|
7
|
+
version = "0.1.1"
|
|
8
|
+
description = "Fast and easy face detection using ONNX runtime."
|
|
9
|
+
authors = [
|
|
10
|
+
{ name="xMaulana" },
|
|
11
|
+
]
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
requires-python = ">=3.11"
|
|
14
|
+
dependencies = [
|
|
15
|
+
"numpy",
|
|
16
|
+
"Pillow",
|
|
17
|
+
"opencv-python",
|
|
18
|
+
"pydantic-settings>=2.15.0",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
[project.optional-dependencies]
|
|
22
|
+
cpu = [
|
|
23
|
+
"onnxruntime>=1.24.3",
|
|
24
|
+
]
|
|
25
|
+
gpu = [
|
|
26
|
+
"onnxruntime-gpu>=1.24.3, <=1.26.1",
|
|
27
|
+
"nvidia-cudnn-cu12",
|
|
28
|
+
"nvidia-cublas-cu12",
|
|
29
|
+
"nvidia-cuda-runtime-cu12"
|
|
30
|
+
]
|
|
31
|
+
openvino = [
|
|
32
|
+
"onnxruntime-openvino>=1.24.1"
|
|
33
|
+
]
|
|
34
|
+
rocm = [
|
|
35
|
+
"onnxruntime-rocm>=1.22.1"
|
|
36
|
+
]
|
|
37
|
+
dev = [
|
|
38
|
+
"pytest",
|
|
39
|
+
"ruff",
|
|
40
|
+
"build",
|
|
41
|
+
"twine"
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
[tool.setuptools]
|
|
45
|
+
package-dir = {"" = "src"}
|
|
46
|
+
packages = ["fast_face", "fast_face.models"]
|
|
47
|
+
|
|
48
|
+
[tool.uv]
|
|
49
|
+
cache-dir = ".uv_cache"
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
import cv2
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
from ..schema import ProviderType
|
|
7
|
+
from ..tools import align_face
|
|
8
|
+
from .base_recognition import BaseRecognitionModel
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class AdaFace(BaseRecognitionModel):
|
|
12
|
+
"""AdaFace face recognition model for embedding extraction.
|
|
13
|
+
|
|
14
|
+
Supports IR-18, IR-50, and IR-101 backbones.
|
|
15
|
+
Expects RGB input images; converts to BGR internally as required by AdaFace.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def __init__(
|
|
19
|
+
self,
|
|
20
|
+
model_path: str,
|
|
21
|
+
align_size: tuple[int, int] = (112, 112),
|
|
22
|
+
providers: list[ProviderType] | None = None,
|
|
23
|
+
**kwargs,
|
|
24
|
+
):
|
|
25
|
+
if providers is None:
|
|
26
|
+
providers = ["CPUExecutionProvider"]
|
|
27
|
+
super().__init__(
|
|
28
|
+
model_path=model_path,
|
|
29
|
+
providers=providers,
|
|
30
|
+
sess_options=kwargs.get("sess_options"),
|
|
31
|
+
)
|
|
32
|
+
self.align_size = align_size
|
|
33
|
+
|
|
34
|
+
def preprocess(self, imgs: list[np.ndarray]) -> np.ndarray:
|
|
35
|
+
"""Preprocess aligned face images: RGB->BGR, normalize to [-1, 1], transpose to NCHW."""
|
|
36
|
+
processed = []
|
|
37
|
+
for img in imgs:
|
|
38
|
+
bgr = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
|
|
39
|
+
|
|
40
|
+
h, w = bgr.shape[:2]
|
|
41
|
+
if (w, h) != self.align_size:
|
|
42
|
+
bgr = cv2.resize(bgr, self.align_size)
|
|
43
|
+
|
|
44
|
+
processed.append(bgr)
|
|
45
|
+
|
|
46
|
+
batch = np.stack(processed, axis=0).astype(np.float32)
|
|
47
|
+
|
|
48
|
+
batch = (batch / 255.0 - 0.5) / 0.5
|
|
49
|
+
|
|
50
|
+
batch = np.transpose(batch, (0, 3, 1, 2))
|
|
51
|
+
return batch
|
|
52
|
+
|
|
53
|
+
def extract(
|
|
54
|
+
self,
|
|
55
|
+
imgs: list[np.ndarray] | np.ndarray,
|
|
56
|
+
landmarks: list[np.ndarray | dict[str, Any]] | None = None,
|
|
57
|
+
) -> np.ndarray:
|
|
58
|
+
"""Extract L2-normalized face embeddings from images.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
imgs: List of face images in RGB, or a single image array.
|
|
62
|
+
If landmarks are provided, images should be the full/cropped
|
|
63
|
+
frames from which faces will be aligned.
|
|
64
|
+
landmarks: Optional list of landmarks for face alignment.
|
|
65
|
+
Each element can be an np.ndarray of shape (5, 2) or (10,),
|
|
66
|
+
or a dictionary with landmark keys.
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
np.ndarray: L2-normalized embeddings of shape (N, embedding_dim).
|
|
70
|
+
"""
|
|
71
|
+
if isinstance(imgs, np.ndarray) and imgs.ndim == 3:
|
|
72
|
+
imgs = [imgs]
|
|
73
|
+
|
|
74
|
+
if landmarks is not None:
|
|
75
|
+
aligned_imgs = []
|
|
76
|
+
for img, lmk in zip(imgs, landmarks):
|
|
77
|
+
aligned = align_face(img, lmk, align_size=self.align_size)
|
|
78
|
+
aligned_imgs.append(aligned)
|
|
79
|
+
else:
|
|
80
|
+
aligned_imgs = imgs
|
|
81
|
+
|
|
82
|
+
batch = self.preprocess(aligned_imgs)
|
|
83
|
+
outputs = self.session(batch)
|
|
84
|
+
|
|
85
|
+
embeddings = outputs[0]
|
|
86
|
+
|
|
87
|
+
norms = np.linalg.norm(embeddings, axis=1, keepdims=True)
|
|
88
|
+
norms = np.maximum(norms, 1e-10)
|
|
89
|
+
embeddings = embeddings / norms
|
|
90
|
+
|
|
91
|
+
return embeddings
|