uniface 0.1.4__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.
- uniface-0.1.4/LICENSE +21 -0
- uniface-0.1.4/PKG-INFO +281 -0
- uniface-0.1.4/README.md +252 -0
- uniface-0.1.4/setup.cfg +4 -0
- uniface-0.1.4/setup.py +44 -0
- uniface-0.1.4/tests/test_retinaface.py +78 -0
- uniface-0.1.4/uniface/__init__.py +30 -0
- uniface-0.1.4/uniface/alignment.py +84 -0
- uniface-0.1.4/uniface/common.py +178 -0
- uniface-0.1.4/uniface/constants.py +26 -0
- uniface-0.1.4/uniface/log.py +7 -0
- uniface-0.1.4/uniface/model_store.py +102 -0
- uniface-0.1.4/uniface/retinaface.py +256 -0
- uniface-0.1.4/uniface/version.py +15 -0
- uniface-0.1.4/uniface/visualization.py +36 -0
- uniface-0.1.4/uniface.egg-info/PKG-INFO +281 -0
- uniface-0.1.4/uniface.egg-info/SOURCES.txt +18 -0
- uniface-0.1.4/uniface.egg-info/dependency_links.txt +1 -0
- uniface-0.1.4/uniface.egg-info/requires.txt +10 -0
- uniface-0.1.4/uniface.egg-info/top_level.txt +1 -0
uniface-0.1.4/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Yakhyokhuja Valikhujaev
|
|
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.
|
uniface-0.1.4/PKG-INFO
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: uniface
|
|
3
|
+
Version: 0.1.4
|
|
4
|
+
Summary: UniFace: A Comprehensive Library for Face Detection, Recognition, Landmark Analysis, Age, and Gender Detection
|
|
5
|
+
Home-page: https://github.com/yakhyo/uniface
|
|
6
|
+
Author: Yakhyokhuja Valikhujaev
|
|
7
|
+
Author-email: yakhyo9696@gmail.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Keywords: face detection,face recognition,facial landmark,facial attribute,onnx,opencv,retinaface
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
17
|
+
Requires-Python: >=3.8
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Requires-Dist: numpy
|
|
21
|
+
Requires-Dist: opencv-python
|
|
22
|
+
Requires-Dist: onnx
|
|
23
|
+
Requires-Dist: onnxruntime
|
|
24
|
+
Requires-Dist: requests
|
|
25
|
+
Requires-Dist: torch
|
|
26
|
+
Requires-Dist: scikit-image
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: pytest; extra == "dev"
|
|
29
|
+
|
|
30
|
+
# UniFace: All-in-One Face Analysis Library
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
[](https://opensource.org/licenses/MIT)
|
|
34
|
+

|
|
35
|
+
[](https://pypi.org/project/uniface/)
|
|
36
|
+
[](https://github.com/yakhyo/uniface/actions)
|
|
37
|
+
[](https://pepy.tech/project/uniface)
|
|
38
|
+
[](https://www.python.org/dev/peps/pep-0008/)
|
|
39
|
+
[](https://github.com/yakhyo/uniface/releases)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
**uniface** is a lightweight face detection library designed for high-performance face localization, landmark detection and face alignment. The library supports ONNX models and provides utilities for bounding box visualization and landmark plotting. To train RetinaFace model, see https://github.com/yakhyo/retinaface-pytorch.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Features
|
|
47
|
+
|
|
48
|
+
- [ ] Age and gender detection (Planned).
|
|
49
|
+
- [ ] Face recognition (Planned).
|
|
50
|
+
- [x] Face Alignment (Added: 2024-11-21).
|
|
51
|
+
- [x] High-speed face detection using ONNX models (Added: 2024-11-20).
|
|
52
|
+
- [x] Accurate facial landmark localization (e.g., eyes, nose, and mouth) (Added: 2024-11-20).
|
|
53
|
+
- [x] Easy-to-use API for inference and visualization (Added: 2024-11-20).
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Installation
|
|
58
|
+
|
|
59
|
+
The easiest way to install **UniFace** is via [PyPI](https://pypi.org/project/uniface/). This will automatically install the library along with its prerequisites.
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
pip install uniface
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
To work with the latest version of **UniFace**, which may not yet be released on PyPI, you can install it directly from the repository:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
git clone https://github.com/yakhyo/uniface.git
|
|
69
|
+
cd uniface
|
|
70
|
+
pip install .
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Quick Start
|
|
76
|
+
|
|
77
|
+
To get started with face detection using **UniFace**, check out the [example notebook](examples/face_detection.ipynb).
|
|
78
|
+
It demonstrates how to initialize the model, run inference, and visualize the results.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Examples
|
|
83
|
+
|
|
84
|
+
Explore the following example notebooks to learn how to use **UniFace** effectively:
|
|
85
|
+
|
|
86
|
+
- [Face Detection](examples/face_detection.ipynb): Demonstrates how to perform face detection, draw bounding boxes, and landmarks on an image.
|
|
87
|
+
- [Face Alignment](examples/face_alignment.ipynb): Shows how to align faces using detected landmarks.
|
|
88
|
+
- [Age and Gender Detection](examples/age_gender.ipynb): Example for detecting age and gender from faces. (underdevelopment)
|
|
89
|
+
|
|
90
|
+
### Initialize the Model
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
from uniface import RetinaFace
|
|
94
|
+
|
|
95
|
+
# Initialize the RetinaFace model
|
|
96
|
+
uniface_inference = RetinaFace(
|
|
97
|
+
model="retinaface_mnet_v2", # Model name
|
|
98
|
+
conf_thresh=0.5, # Confidence threshold
|
|
99
|
+
pre_nms_topk=5000, # Pre-NMS Top-K detections
|
|
100
|
+
nms_thresh=0.4, # NMS IoU threshold
|
|
101
|
+
post_nms_topk=750 # Post-NMS Top-K detections
|
|
102
|
+
)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Run Inference
|
|
106
|
+
|
|
107
|
+
Inference on image:
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
import cv2
|
|
111
|
+
from uniface.visualization import draw_detections
|
|
112
|
+
|
|
113
|
+
# Load an image
|
|
114
|
+
image_path = "assets/test.jpg"
|
|
115
|
+
original_image = cv2.imread(image_path)
|
|
116
|
+
|
|
117
|
+
# Perform inference
|
|
118
|
+
boxes, landmarks = uniface_inference.detect(original_image)
|
|
119
|
+
|
|
120
|
+
# Visualize results
|
|
121
|
+
draw_detections(original_image, (boxes, landmarks), vis_threshold=0.6)
|
|
122
|
+
|
|
123
|
+
# Save the output image
|
|
124
|
+
output_path = "output.jpg"
|
|
125
|
+
cv2.imwrite(output_path, original_image)
|
|
126
|
+
print(f"Saved output image to {output_path}")
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Inference on video:
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
import cv2
|
|
133
|
+
from uniface.visualization import draw_detections
|
|
134
|
+
|
|
135
|
+
# Initialize the webcam
|
|
136
|
+
cap = cv2.VideoCapture(0)
|
|
137
|
+
|
|
138
|
+
if not cap.isOpened():
|
|
139
|
+
print("Error: Unable to access the webcam.")
|
|
140
|
+
exit()
|
|
141
|
+
|
|
142
|
+
while True:
|
|
143
|
+
# Capture a frame from the webcam
|
|
144
|
+
ret, frame = cap.read()
|
|
145
|
+
if not ret:
|
|
146
|
+
print("Error: Failed to read frame.")
|
|
147
|
+
break
|
|
148
|
+
|
|
149
|
+
# Perform inference
|
|
150
|
+
boxes, landmarks = uniface_inference.detect(frame)
|
|
151
|
+
|
|
152
|
+
# Draw detections on the frame
|
|
153
|
+
draw_detections(frame, (boxes, landmarks), vis_threshold=0.6)
|
|
154
|
+
|
|
155
|
+
# Display the output
|
|
156
|
+
cv2.imshow("Webcam Inference", frame)
|
|
157
|
+
|
|
158
|
+
# Exit if 'q' is pressed
|
|
159
|
+
if cv2.waitKey(1) & 0xFF == ord('q'):
|
|
160
|
+
break
|
|
161
|
+
|
|
162
|
+
# Release the webcam and close all OpenCV windows
|
|
163
|
+
cap.release()
|
|
164
|
+
cv2.destroyAllWindows()
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
### Evaluation results of available models on WiderFace
|
|
170
|
+
|
|
171
|
+
| RetinaFace Models | Easy | Medium | Hard |
|
|
172
|
+
| ------------------ | ---------- | ---------- | ---------- |
|
|
173
|
+
| retinaface_mnet025 | 88.48% | 87.02% | 80.61% |
|
|
174
|
+
| retinaface_mnet050 | 89.42% | 87.97% | 82.40% |
|
|
175
|
+
| retinaface_mnet_v1 | 90.59% | 89.14% | 84.13% |
|
|
176
|
+
| retinaface_mnet_v2 | 91.70% | 91.03% | 86.60% |
|
|
177
|
+
| retinaface_r18 | 92.50% | 91.02% | 86.63% |
|
|
178
|
+
| retinaface_r34 | **94.16%** | **93.12%** | **88.90%** |
|
|
179
|
+
|
|
180
|
+
## API Reference
|
|
181
|
+
|
|
182
|
+
### `RetinaFace` Class
|
|
183
|
+
|
|
184
|
+
#### Initialization
|
|
185
|
+
|
|
186
|
+
```python
|
|
187
|
+
RetinaFace(
|
|
188
|
+
model: str,
|
|
189
|
+
conf_thresh: float = 0.5,
|
|
190
|
+
pre_nms_topk: int = 5000,
|
|
191
|
+
nms_thresh: float = 0.4,
|
|
192
|
+
post_nms_topk: int = 750
|
|
193
|
+
)
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
**Parameters**:
|
|
197
|
+
|
|
198
|
+
- `model` _(str)_: Name of the model to use. Supported models:
|
|
199
|
+
- `retinaface_mnet025`, `retinaface_mnet050`, `retinaface_mnet_v1`, `retinaface_mnet_v2`
|
|
200
|
+
- `retinaface_r18`, `retinaface_r34`
|
|
201
|
+
- `conf_thresh` _(float, default=0.5)_: Minimum confidence score for detections.
|
|
202
|
+
- `pre_nms_topk` _(int, default=5000)_: Max detections to keep before NMS.
|
|
203
|
+
- `nms_thresh` _(float, default=0.4)_: IoU threshold for Non-Maximum Suppression.
|
|
204
|
+
- `post_nms_topk` _(int, default=750)_: Max detections to keep after NMS.
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
### `detect` Method
|
|
209
|
+
|
|
210
|
+
```python
|
|
211
|
+
detect(
|
|
212
|
+
image: np.ndarray,
|
|
213
|
+
max_num: int = 0,
|
|
214
|
+
metric: str = "default",
|
|
215
|
+
center_weight: float = 2.0
|
|
216
|
+
) -> Tuple[np.ndarray, np.ndarray]
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
**Description**:
|
|
220
|
+
Detects faces in the given image and returns bounding boxes and landmarks.
|
|
221
|
+
|
|
222
|
+
**Parameters**:
|
|
223
|
+
|
|
224
|
+
- `image` _(np.ndarray)_: Input image in BGR format.
|
|
225
|
+
- `max_num` _(int, default=0)_: Maximum number of faces to return. `0` means return all.
|
|
226
|
+
- `metric` _(str, default="default")_: Metric for prioritizing detections:
|
|
227
|
+
- `"default"`: Prioritize detections closer to the image center.
|
|
228
|
+
- `"max"`: Prioritize larger bounding box areas.
|
|
229
|
+
- `center_weight` _(float, default=2.0)_: Weight for prioritizing center-aligned faces.
|
|
230
|
+
|
|
231
|
+
**Returns**:
|
|
232
|
+
|
|
233
|
+
- `bounding_boxes` _(np.ndarray)_: Array of detections as `[x_min, y_min, x_max, y_max, confidence]`.
|
|
234
|
+
- `landmarks` _(np.ndarray)_: Array of landmarks as `[(x1, y1), ..., (x5, y5)]`.
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
### Visualization Utilities
|
|
239
|
+
|
|
240
|
+
#### `draw_detections`
|
|
241
|
+
|
|
242
|
+
```python
|
|
243
|
+
draw_detections(
|
|
244
|
+
image: np.ndarray,
|
|
245
|
+
detections: Tuple[np.ndarray, np.ndarray],
|
|
246
|
+
vis_threshold: float
|
|
247
|
+
) -> None
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
**Description**:
|
|
251
|
+
Draws bounding boxes and landmarks on the given image.
|
|
252
|
+
|
|
253
|
+
**Parameters**:
|
|
254
|
+
|
|
255
|
+
- `image` _(np.ndarray)_: The input image in BGR format.
|
|
256
|
+
- `detections` _(Tuple[np.ndarray, np.ndarray])_: A tuple of bounding boxes and landmarks.
|
|
257
|
+
- `vis_threshold` _(float)_: Minimum confidence score for visualization.
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## Contributing
|
|
262
|
+
|
|
263
|
+
We welcome contributions to enhance the library! Feel free to:
|
|
264
|
+
|
|
265
|
+
- Submit bug reports or feature requests.
|
|
266
|
+
- Fork the repository and create a pull request.
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## License
|
|
271
|
+
|
|
272
|
+
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## Acknowledgments
|
|
277
|
+
|
|
278
|
+
- Based on the RetinaFace model for face detection ([https://github.com/yakhyo/retinaface-pytorch](https://github.com/yakhyo/retinaface-pytorch)).
|
|
279
|
+
- Inspired by InsightFace and other face detection projects.
|
|
280
|
+
|
|
281
|
+
---
|
uniface-0.1.4/README.md
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
# UniFace: All-in-One Face Analysis Library
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+

|
|
6
|
+
[](https://pypi.org/project/uniface/)
|
|
7
|
+
[](https://github.com/yakhyo/uniface/actions)
|
|
8
|
+
[](https://pepy.tech/project/uniface)
|
|
9
|
+
[](https://www.python.org/dev/peps/pep-0008/)
|
|
10
|
+
[](https://github.com/yakhyo/uniface/releases)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
**uniface** is a lightweight face detection library designed for high-performance face localization, landmark detection and face alignment. The library supports ONNX models and provides utilities for bounding box visualization and landmark plotting. To train RetinaFace model, see https://github.com/yakhyo/retinaface-pytorch.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Features
|
|
18
|
+
|
|
19
|
+
- [ ] Age and gender detection (Planned).
|
|
20
|
+
- [ ] Face recognition (Planned).
|
|
21
|
+
- [x] Face Alignment (Added: 2024-11-21).
|
|
22
|
+
- [x] High-speed face detection using ONNX models (Added: 2024-11-20).
|
|
23
|
+
- [x] Accurate facial landmark localization (e.g., eyes, nose, and mouth) (Added: 2024-11-20).
|
|
24
|
+
- [x] Easy-to-use API for inference and visualization (Added: 2024-11-20).
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
|
|
30
|
+
The easiest way to install **UniFace** is via [PyPI](https://pypi.org/project/uniface/). This will automatically install the library along with its prerequisites.
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install uniface
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
To work with the latest version of **UniFace**, which may not yet be released on PyPI, you can install it directly from the repository:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
git clone https://github.com/yakhyo/uniface.git
|
|
40
|
+
cd uniface
|
|
41
|
+
pip install .
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Quick Start
|
|
47
|
+
|
|
48
|
+
To get started with face detection using **UniFace**, check out the [example notebook](examples/face_detection.ipynb).
|
|
49
|
+
It demonstrates how to initialize the model, run inference, and visualize the results.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Examples
|
|
54
|
+
|
|
55
|
+
Explore the following example notebooks to learn how to use **UniFace** effectively:
|
|
56
|
+
|
|
57
|
+
- [Face Detection](examples/face_detection.ipynb): Demonstrates how to perform face detection, draw bounding boxes, and landmarks on an image.
|
|
58
|
+
- [Face Alignment](examples/face_alignment.ipynb): Shows how to align faces using detected landmarks.
|
|
59
|
+
- [Age and Gender Detection](examples/age_gender.ipynb): Example for detecting age and gender from faces. (underdevelopment)
|
|
60
|
+
|
|
61
|
+
### Initialize the Model
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
from uniface import RetinaFace
|
|
65
|
+
|
|
66
|
+
# Initialize the RetinaFace model
|
|
67
|
+
uniface_inference = RetinaFace(
|
|
68
|
+
model="retinaface_mnet_v2", # Model name
|
|
69
|
+
conf_thresh=0.5, # Confidence threshold
|
|
70
|
+
pre_nms_topk=5000, # Pre-NMS Top-K detections
|
|
71
|
+
nms_thresh=0.4, # NMS IoU threshold
|
|
72
|
+
post_nms_topk=750 # Post-NMS Top-K detections
|
|
73
|
+
)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Run Inference
|
|
77
|
+
|
|
78
|
+
Inference on image:
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
import cv2
|
|
82
|
+
from uniface.visualization import draw_detections
|
|
83
|
+
|
|
84
|
+
# Load an image
|
|
85
|
+
image_path = "assets/test.jpg"
|
|
86
|
+
original_image = cv2.imread(image_path)
|
|
87
|
+
|
|
88
|
+
# Perform inference
|
|
89
|
+
boxes, landmarks = uniface_inference.detect(original_image)
|
|
90
|
+
|
|
91
|
+
# Visualize results
|
|
92
|
+
draw_detections(original_image, (boxes, landmarks), vis_threshold=0.6)
|
|
93
|
+
|
|
94
|
+
# Save the output image
|
|
95
|
+
output_path = "output.jpg"
|
|
96
|
+
cv2.imwrite(output_path, original_image)
|
|
97
|
+
print(f"Saved output image to {output_path}")
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Inference on video:
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
import cv2
|
|
104
|
+
from uniface.visualization import draw_detections
|
|
105
|
+
|
|
106
|
+
# Initialize the webcam
|
|
107
|
+
cap = cv2.VideoCapture(0)
|
|
108
|
+
|
|
109
|
+
if not cap.isOpened():
|
|
110
|
+
print("Error: Unable to access the webcam.")
|
|
111
|
+
exit()
|
|
112
|
+
|
|
113
|
+
while True:
|
|
114
|
+
# Capture a frame from the webcam
|
|
115
|
+
ret, frame = cap.read()
|
|
116
|
+
if not ret:
|
|
117
|
+
print("Error: Failed to read frame.")
|
|
118
|
+
break
|
|
119
|
+
|
|
120
|
+
# Perform inference
|
|
121
|
+
boxes, landmarks = uniface_inference.detect(frame)
|
|
122
|
+
|
|
123
|
+
# Draw detections on the frame
|
|
124
|
+
draw_detections(frame, (boxes, landmarks), vis_threshold=0.6)
|
|
125
|
+
|
|
126
|
+
# Display the output
|
|
127
|
+
cv2.imshow("Webcam Inference", frame)
|
|
128
|
+
|
|
129
|
+
# Exit if 'q' is pressed
|
|
130
|
+
if cv2.waitKey(1) & 0xFF == ord('q'):
|
|
131
|
+
break
|
|
132
|
+
|
|
133
|
+
# Release the webcam and close all OpenCV windows
|
|
134
|
+
cap.release()
|
|
135
|
+
cv2.destroyAllWindows()
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
### Evaluation results of available models on WiderFace
|
|
141
|
+
|
|
142
|
+
| RetinaFace Models | Easy | Medium | Hard |
|
|
143
|
+
| ------------------ | ---------- | ---------- | ---------- |
|
|
144
|
+
| retinaface_mnet025 | 88.48% | 87.02% | 80.61% |
|
|
145
|
+
| retinaface_mnet050 | 89.42% | 87.97% | 82.40% |
|
|
146
|
+
| retinaface_mnet_v1 | 90.59% | 89.14% | 84.13% |
|
|
147
|
+
| retinaface_mnet_v2 | 91.70% | 91.03% | 86.60% |
|
|
148
|
+
| retinaface_r18 | 92.50% | 91.02% | 86.63% |
|
|
149
|
+
| retinaface_r34 | **94.16%** | **93.12%** | **88.90%** |
|
|
150
|
+
|
|
151
|
+
## API Reference
|
|
152
|
+
|
|
153
|
+
### `RetinaFace` Class
|
|
154
|
+
|
|
155
|
+
#### Initialization
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
RetinaFace(
|
|
159
|
+
model: str,
|
|
160
|
+
conf_thresh: float = 0.5,
|
|
161
|
+
pre_nms_topk: int = 5000,
|
|
162
|
+
nms_thresh: float = 0.4,
|
|
163
|
+
post_nms_topk: int = 750
|
|
164
|
+
)
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
**Parameters**:
|
|
168
|
+
|
|
169
|
+
- `model` _(str)_: Name of the model to use. Supported models:
|
|
170
|
+
- `retinaface_mnet025`, `retinaface_mnet050`, `retinaface_mnet_v1`, `retinaface_mnet_v2`
|
|
171
|
+
- `retinaface_r18`, `retinaface_r34`
|
|
172
|
+
- `conf_thresh` _(float, default=0.5)_: Minimum confidence score for detections.
|
|
173
|
+
- `pre_nms_topk` _(int, default=5000)_: Max detections to keep before NMS.
|
|
174
|
+
- `nms_thresh` _(float, default=0.4)_: IoU threshold for Non-Maximum Suppression.
|
|
175
|
+
- `post_nms_topk` _(int, default=750)_: Max detections to keep after NMS.
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
### `detect` Method
|
|
180
|
+
|
|
181
|
+
```python
|
|
182
|
+
detect(
|
|
183
|
+
image: np.ndarray,
|
|
184
|
+
max_num: int = 0,
|
|
185
|
+
metric: str = "default",
|
|
186
|
+
center_weight: float = 2.0
|
|
187
|
+
) -> Tuple[np.ndarray, np.ndarray]
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
**Description**:
|
|
191
|
+
Detects faces in the given image and returns bounding boxes and landmarks.
|
|
192
|
+
|
|
193
|
+
**Parameters**:
|
|
194
|
+
|
|
195
|
+
- `image` _(np.ndarray)_: Input image in BGR format.
|
|
196
|
+
- `max_num` _(int, default=0)_: Maximum number of faces to return. `0` means return all.
|
|
197
|
+
- `metric` _(str, default="default")_: Metric for prioritizing detections:
|
|
198
|
+
- `"default"`: Prioritize detections closer to the image center.
|
|
199
|
+
- `"max"`: Prioritize larger bounding box areas.
|
|
200
|
+
- `center_weight` _(float, default=2.0)_: Weight for prioritizing center-aligned faces.
|
|
201
|
+
|
|
202
|
+
**Returns**:
|
|
203
|
+
|
|
204
|
+
- `bounding_boxes` _(np.ndarray)_: Array of detections as `[x_min, y_min, x_max, y_max, confidence]`.
|
|
205
|
+
- `landmarks` _(np.ndarray)_: Array of landmarks as `[(x1, y1), ..., (x5, y5)]`.
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
### Visualization Utilities
|
|
210
|
+
|
|
211
|
+
#### `draw_detections`
|
|
212
|
+
|
|
213
|
+
```python
|
|
214
|
+
draw_detections(
|
|
215
|
+
image: np.ndarray,
|
|
216
|
+
detections: Tuple[np.ndarray, np.ndarray],
|
|
217
|
+
vis_threshold: float
|
|
218
|
+
) -> None
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
**Description**:
|
|
222
|
+
Draws bounding boxes and landmarks on the given image.
|
|
223
|
+
|
|
224
|
+
**Parameters**:
|
|
225
|
+
|
|
226
|
+
- `image` _(np.ndarray)_: The input image in BGR format.
|
|
227
|
+
- `detections` _(Tuple[np.ndarray, np.ndarray])_: A tuple of bounding boxes and landmarks.
|
|
228
|
+
- `vis_threshold` _(float)_: Minimum confidence score for visualization.
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## Contributing
|
|
233
|
+
|
|
234
|
+
We welcome contributions to enhance the library! Feel free to:
|
|
235
|
+
|
|
236
|
+
- Submit bug reports or feature requests.
|
|
237
|
+
- Fork the repository and create a pull request.
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## License
|
|
242
|
+
|
|
243
|
+
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## Acknowledgments
|
|
248
|
+
|
|
249
|
+
- Based on the RetinaFace model for face detection ([https://github.com/yakhyo/retinaface-pytorch](https://github.com/yakhyo/retinaface-pytorch)).
|
|
250
|
+
- Inspired by InsightFace and other face detection projects.
|
|
251
|
+
|
|
252
|
+
---
|
uniface-0.1.4/setup.cfg
ADDED
uniface-0.1.4/setup.py
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from setuptools import setup, find_packages
|
|
3
|
+
|
|
4
|
+
# Read the README file for the long description
|
|
5
|
+
long_description = ""
|
|
6
|
+
if os.path.exists("README.md"):
|
|
7
|
+
with open("README.md", "r", encoding="utf-8") as f:
|
|
8
|
+
long_description = f.read()
|
|
9
|
+
|
|
10
|
+
setup(
|
|
11
|
+
name="uniface",
|
|
12
|
+
version="0.1.4",
|
|
13
|
+
packages=find_packages(),
|
|
14
|
+
install_requires=[
|
|
15
|
+
"numpy",
|
|
16
|
+
"opencv-python",
|
|
17
|
+
"onnx",
|
|
18
|
+
"onnxruntime",
|
|
19
|
+
"requests",
|
|
20
|
+
"torch",
|
|
21
|
+
"scikit-image"
|
|
22
|
+
],
|
|
23
|
+
extras_require={
|
|
24
|
+
"dev": ["pytest"],
|
|
25
|
+
},
|
|
26
|
+
description="UniFace: A Comprehensive Library for Face Detection, Recognition, Landmark Analysis, Age, and Gender Detection",
|
|
27
|
+
long_description=long_description,
|
|
28
|
+
long_description_content_type="text/markdown",
|
|
29
|
+
author="Yakhyokhuja Valikhujaev",
|
|
30
|
+
author_email="yakhyo9696@gmail.com",
|
|
31
|
+
url="https://github.com/yakhyo/uniface",
|
|
32
|
+
license="MIT",
|
|
33
|
+
classifiers=[
|
|
34
|
+
"Programming Language :: Python :: 3",
|
|
35
|
+
"Programming Language :: Python :: 3.8",
|
|
36
|
+
"Programming Language :: Python :: 3.9",
|
|
37
|
+
"Programming Language :: Python :: 3.10",
|
|
38
|
+
"License :: OSI Approved :: MIT License",
|
|
39
|
+
"Operating System :: OS Independent",
|
|
40
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
41
|
+
],
|
|
42
|
+
keywords="face detection, face recognition, facial landmark, facial attribute, onnx, opencv, retinaface",
|
|
43
|
+
python_requires=">=3.8",
|
|
44
|
+
)
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
import numpy as np
|
|
3
|
+
from uniface import RetinaFace
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@pytest.fixture
|
|
7
|
+
def retinaface_model():
|
|
8
|
+
"""
|
|
9
|
+
Fixture to initialize the RetinaFace model for testing.
|
|
10
|
+
"""
|
|
11
|
+
return RetinaFace(
|
|
12
|
+
model="retinaface_mnet_v2",
|
|
13
|
+
conf_thresh=0.5,
|
|
14
|
+
pre_nms_topk=5000,
|
|
15
|
+
nms_thresh=0.4,
|
|
16
|
+
post_nms_topk=750,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def test_model_initialization(retinaface_model):
|
|
21
|
+
"""
|
|
22
|
+
Test that the RetinaFace model initializes correctly.
|
|
23
|
+
"""
|
|
24
|
+
assert retinaface_model is not None, "Model initialization failed."
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_inference_on_640x640_image(retinaface_model):
|
|
28
|
+
"""
|
|
29
|
+
Test inference on a 640x640 BGR image.
|
|
30
|
+
"""
|
|
31
|
+
# Generate a mock 640x640 BGR image
|
|
32
|
+
mock_image = np.random.randint(0, 255, (640, 640, 3), dtype=np.uint8)
|
|
33
|
+
|
|
34
|
+
# Run inference
|
|
35
|
+
detections, landmarks = retinaface_model.detect(mock_image)
|
|
36
|
+
|
|
37
|
+
# Check output types
|
|
38
|
+
assert isinstance(detections, np.ndarray), "Detections should be a numpy array."
|
|
39
|
+
assert isinstance(landmarks, np.ndarray), "Landmarks should be a numpy array."
|
|
40
|
+
|
|
41
|
+
# Check that detections have the expected shape
|
|
42
|
+
if detections.size > 0: # If faces are detected
|
|
43
|
+
assert detections.shape[1] == 5, "Each detection should have 5 values (x1, y1, x2, y2, score)."
|
|
44
|
+
|
|
45
|
+
# Check landmarks shape
|
|
46
|
+
if landmarks.size > 0:
|
|
47
|
+
assert landmarks.shape[1:] == (5, 2), "Landmarks should have shape (N, 5, 2)."
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def test_confidence_threshold(retinaface_model):
|
|
51
|
+
"""
|
|
52
|
+
Test that detections respect the confidence threshold.
|
|
53
|
+
"""
|
|
54
|
+
# Generate a mock 640x640 BGR image
|
|
55
|
+
mock_image = np.random.randint(0, 255, (640, 640, 3), dtype=np.uint8)
|
|
56
|
+
|
|
57
|
+
# Run inference
|
|
58
|
+
detections, _ = retinaface_model.detect(mock_image)
|
|
59
|
+
|
|
60
|
+
# Ensure all detections have confidence scores above the threshold
|
|
61
|
+
if detections.size > 0: # If faces are detected
|
|
62
|
+
confidence_scores = detections[:, 4]
|
|
63
|
+
assert (confidence_scores >= 0.5).all(), "Some detections have confidence below the threshold."
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def test_no_faces_detected(retinaface_model):
|
|
67
|
+
"""
|
|
68
|
+
Test inference on an image without detectable faces.
|
|
69
|
+
"""
|
|
70
|
+
# Generate an empty (black) 640x640 image
|
|
71
|
+
empty_image = np.zeros((640, 640, 3), dtype=np.uint8)
|
|
72
|
+
|
|
73
|
+
# Run inference
|
|
74
|
+
detections, landmarks = retinaface_model.detect(empty_image)
|
|
75
|
+
|
|
76
|
+
# Ensure no detections or landmarks are found
|
|
77
|
+
assert detections.size == 0, "Detections should be empty for a blank image."
|
|
78
|
+
assert landmarks.size == 0, "Landmarks should be empty for a blank image."
|