faceswitch 0.2.1__tar.gz → 0.2.2__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.
- faceswitch-0.2.2/PKG-INFO +218 -0
- faceswitch-0.2.2/README.md +177 -0
- {faceswitch-0.2.1 → faceswitch-0.2.2}/pyproject.toml +4 -2
- {faceswitch-0.2.1 → faceswitch-0.2.2}/src/faceswitch/__init__.py +8 -1
- {faceswitch-0.2.1 → faceswitch-0.2.2}/src/faceswitch/detectors/__init__.py +8 -1
- faceswitch-0.2.2/src/faceswitch/detectors/retinaface/__init__.py +6 -0
- faceswitch-0.2.2/src/faceswitch/detectors/retinaface/config.py +10 -0
- faceswitch-0.2.2/src/faceswitch/detectors/retinaface/detector.py +40 -0
- {faceswitch-0.2.1 → faceswitch-0.2.2}/src/faceswitch/detectors/yolo/detector.py +2 -2
- faceswitch-0.2.2/src/faceswitch.egg-info/PKG-INFO +218 -0
- {faceswitch-0.2.1 → faceswitch-0.2.2}/src/faceswitch.egg-info/SOURCES.txt +4 -0
- {faceswitch-0.2.1 → faceswitch-0.2.2}/src/faceswitch.egg-info/requires.txt +4 -0
- faceswitch-0.2.2/tests/test_hog_detector.py +97 -0
- faceswitch-0.2.2/tests/test_retinaface_detector.py +79 -0
- faceswitch-0.2.2/tests/test_yolo_detector.py +98 -0
- faceswitch-0.2.1/PKG-INFO +0 -139
- faceswitch-0.2.1/README.md +0 -101
- faceswitch-0.2.1/src/faceswitch.egg-info/PKG-INFO +0 -139
- faceswitch-0.2.1/tests/test_hog_detector.py +0 -34
- faceswitch-0.2.1/tests/test_yolo_detector.py +0 -36
- {faceswitch-0.2.1 → faceswitch-0.2.2}/LICENSE +0 -0
- {faceswitch-0.2.1 → faceswitch-0.2.2}/setup.cfg +0 -0
- {faceswitch-0.2.1 → faceswitch-0.2.2}/src/faceswitch/core/__init__.py +0 -0
- {faceswitch-0.2.1 → faceswitch-0.2.2}/src/faceswitch/core/interfaces.py +0 -0
- {faceswitch-0.2.1 → faceswitch-0.2.2}/src/faceswitch/core/types.py +0 -0
- {faceswitch-0.2.1 → faceswitch-0.2.2}/src/faceswitch/detectors/hog/__init__.py +0 -0
- {faceswitch-0.2.1 → faceswitch-0.2.2}/src/faceswitch/detectors/hog/config.py +0 -0
- {faceswitch-0.2.1 → faceswitch-0.2.2}/src/faceswitch/detectors/hog/detector.py +0 -0
- {faceswitch-0.2.1 → faceswitch-0.2.2}/src/faceswitch/detectors/yolo/__init__.py +0 -0
- {faceswitch-0.2.1 → faceswitch-0.2.2}/src/faceswitch/detectors/yolo/config.py +0 -0
- {faceswitch-0.2.1 → faceswitch-0.2.2}/src/faceswitch/py.typed +0 -0
- {faceswitch-0.2.1 → faceswitch-0.2.2}/src/faceswitch.egg-info/dependency_links.txt +0 -0
- {faceswitch-0.2.1 → faceswitch-0.2.2}/src/faceswitch.egg-info/top_level.txt +0 -0
- {faceswitch-0.2.1 → faceswitch-0.2.2}/tests/test_public_api.py +0 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: faceswitch
|
|
3
|
+
Version: 0.2.2
|
|
4
|
+
Summary: Simple multi-model face detection library
|
|
5
|
+
Author: FaceSwitch Contributors
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/game-sys/FaceSwitch
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/game-sys/FaceSwitch/issues
|
|
9
|
+
Project-URL: Documentation, https://github.com/game-sys/FaceSwitch/blob/main/README.md
|
|
10
|
+
Keywords: face-detection,computer-vision,hog,dlib
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Image Recognition
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Provides-Extra: hog
|
|
24
|
+
Requires-Dist: dlib>=19.24; extra == "hog"
|
|
25
|
+
Provides-Extra: yolo
|
|
26
|
+
Requires-Dist: ultralytics>=8.0.0; extra == "yolo"
|
|
27
|
+
Requires-Dist: torch>=2.0.0; extra == "yolo"
|
|
28
|
+
Provides-Extra: examples
|
|
29
|
+
Requires-Dist: opencv-python>=4.8; extra == "examples"
|
|
30
|
+
Provides-Extra: dev
|
|
31
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
32
|
+
Provides-Extra: retinaface
|
|
33
|
+
Requires-Dist: retina-face; extra == "retinaface"
|
|
34
|
+
Provides-Extra: all
|
|
35
|
+
Requires-Dist: dlib>=19.24; extra == "all"
|
|
36
|
+
Requires-Dist: ultralytics>=8.0.0; extra == "all"
|
|
37
|
+
Requires-Dist: torch>=2.0.0; extra == "all"
|
|
38
|
+
Requires-Dist: opencv-python>=4.8; extra == "all"
|
|
39
|
+
Requires-Dist: retina-face; extra == "all"
|
|
40
|
+
Dynamic: license-file
|
|
41
|
+
|
|
42
|
+
# FaceSwitch
|
|
43
|
+
|
|
44
|
+
**Detect faces in any image with one line of Python — swap the detector without changing your code.**
|
|
45
|
+
|
|
46
|
+
FaceSwitch is a lightweight Python library that wraps multiple face detection engines behind a single, consistent interface. Pick the detector that suits your needs, swap it later without rewriting anything, and only install what you actually use.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## What does it do?
|
|
51
|
+
|
|
52
|
+
You give it an image. It tells you where the faces are.
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
from faceswitch.detectors.yolo import YoloDetector
|
|
56
|
+
import cv2
|
|
57
|
+
|
|
58
|
+
image = cv2.imread("photo.jpg")
|
|
59
|
+
detector = YoloDetector()
|
|
60
|
+
faces = detector.detect(image)
|
|
61
|
+
|
|
62
|
+
for face in faces:
|
|
63
|
+
print(f"Face at ({face.x1}, {face.y1}) → ({face.x2}, {face.y2})")
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Every detector returns the same thing — a list of face boxes — so switching from YOLO to HOG (or any other detector) is just changing one import line.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Installation
|
|
71
|
+
|
|
72
|
+
You need Python 3.10 or newer.
|
|
73
|
+
|
|
74
|
+
**Step 1 — install the base library:**
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
pip install faceswitch
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Step 2 — install the detector you want to use:**
|
|
81
|
+
|
|
82
|
+
| Detector | What it is | Install command |
|
|
83
|
+
|---|---|---|
|
|
84
|
+
| HOG | Classic CPU-based detector (fast, lightweight, no GPU needed) | `pip install "faceswitch[hog]"` |
|
|
85
|
+
| YOLO | Deep learning detector (more accurate, works best with GPU) | `pip install "faceswitch[yolo]"` |
|
|
86
|
+
| RetinaFace | High-accuracy ResNet detector (best for difficult angles and small faces) | `pip install "faceswitch[retinaface]"` |
|
|
87
|
+
|
|
88
|
+
| RetinaFace | Deep learning face detector using ResNet+FPN with multi-scale anchors for high-accuracy detection. | `pip install "faceswitch[retinaface]"` |
|
|
89
|
+
|
|
90
|
+
**Or install everything at once:**
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
pip install "faceswitch[all]"
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Quick start — 3 lines to detect faces
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
import cv2
|
|
102
|
+
from faceswitch.detectors.hog import HogDetector # swap this line to switch detectors
|
|
103
|
+
|
|
104
|
+
image = cv2.imread("photo.jpg")
|
|
105
|
+
faces = HogDetector().detect(image)
|
|
106
|
+
|
|
107
|
+
print(f"Found {len(faces)} face(s)")
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
To use a different detector, change only the import:
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
from faceswitch.detectors.yolo import YoloDetector # YOLO
|
|
114
|
+
from faceswitch.detectors.retinaface import RetinaFaceDetector # RetinaFace
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Everything else stays exactly the same.
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Understanding the results
|
|
122
|
+
|
|
123
|
+
`detector.detect(image)` always returns a list of `FaceBox` objects. Each one looks like this:
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
FaceBox(x1=120, y1=45, x2=210, y2=160, confidence=0.97)
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
| Field | Meaning |
|
|
130
|
+
|---|---|
|
|
131
|
+
| `x1`, `y1` | Top-left corner of the face box (pixels) |
|
|
132
|
+
| `x2`, `y2` | Bottom-right corner of the face box (pixels) |
|
|
133
|
+
| `confidence` | How sure the detector is (0.0 to 1.0). Some detectors don't provide this (`None`). |
|
|
134
|
+
|
|
135
|
+
**Draw the boxes on your image:**
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
import cv2
|
|
139
|
+
from faceswitch.detectors.yolo import YoloDetector
|
|
140
|
+
|
|
141
|
+
image = cv2.imread("photo.jpg")
|
|
142
|
+
faces = YoloDetector().detect(image)
|
|
143
|
+
|
|
144
|
+
for face in faces:
|
|
145
|
+
cv2.rectangle(image, (face.x1, face.y1), (face.x2, face.y2), (0, 255, 0), 2)
|
|
146
|
+
|
|
147
|
+
cv2.imwrite("result.jpg", image)
|
|
148
|
+
print(f"Saved result.jpg with {len(faces)} face(s) highlighted")
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Choosing the right detector
|
|
154
|
+
|
|
155
|
+
| | HOG | YOLO | RetinaFace |
|
|
156
|
+
|---|---|---|---|
|
|
157
|
+
| **Speed** | Fast | Medium | Slower |
|
|
158
|
+
| **Accuracy** | Basic | High | Very high |
|
|
159
|
+
| **GPU needed?** | No | Optional | No |
|
|
160
|
+
| **Best for** | Quick scripts, low-power machines | General use, real-time video | Difficult angles, small faces, production use |
|
|
161
|
+
| **Install size** | Small (~80MB) | Large (~500MB with torch) | Large (~200MB with TensorFlow) |
|
|
162
|
+
|
|
163
|
+
**Not sure?** Start with HOG. If it misses faces, switch to YOLO or RetinaFace — your code won't change.
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Available detectors
|
|
168
|
+
|
|
169
|
+
### HOG — `pip install "faceswitch[hog]"`
|
|
170
|
+
|
|
171
|
+
Uses dlib's Histogram of Oriented Gradients detector. Works entirely on CPU, very fast, good for frontal faces.
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
from faceswitch.detectors.hog import HogDetector
|
|
175
|
+
faces = HogDetector().detect(image)
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### YOLO — `pip install "faceswitch[yolo]"`
|
|
179
|
+
|
|
180
|
+
Uses Ultralytics YOLOv8. Deep learning-based, excellent accuracy on varied poses and lighting. Downloads a model on first use (~6MB).
|
|
181
|
+
|
|
182
|
+
```python
|
|
183
|
+
from faceswitch.detectors.yolo import YoloDetector
|
|
184
|
+
faces = YoloDetector().detect(image)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### RetinaFace — `pip install "faceswitch[retinaface]"`
|
|
188
|
+
|
|
189
|
+
Uses the serengil/retinaface ResNet+FPN model. Best accuracy on small faces, side profiles, and crowded images. Downloads model weights on first use (~120MB).
|
|
190
|
+
|
|
191
|
+
```python
|
|
192
|
+
from faceswitch.detectors.retinaface import RetinaFaceDetector
|
|
193
|
+
faces = RetinaFaceDetector().detect(image)
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## Common questions
|
|
199
|
+
|
|
200
|
+
**Do I need a GPU?**
|
|
201
|
+
No. All detectors run on CPU. YOLO and RetinaFace are faster with a GPU but don't require one.
|
|
202
|
+
|
|
203
|
+
**I get "ImportError: ... install faceswitch[hog]"**
|
|
204
|
+
You installed the base library but not the detector dependency. Run the install command from the table above.
|
|
205
|
+
|
|
206
|
+
**The detector downloads a model on first use — is that normal?**
|
|
207
|
+
Yes. YOLO (~6MB) and RetinaFace (~120MB) download their model weights automatically the first time you use them. After that, they're cached locally.
|
|
208
|
+
|
|
209
|
+
**Can I use my own image loading library instead of OpenCV?**
|
|
210
|
+
Yes, as long as the image is a NumPy array with shape `(height, width, 3)` and `uint8` dtype (standard BGR or RGB image). `cv2.imread()` gives you this automatically.
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## More detectors coming
|
|
215
|
+
|
|
216
|
+
FaceSwitch is actively maintained. New detectors are added regularly — run `pip install --upgrade faceswitch` to get the latest.
|
|
217
|
+
|
|
218
|
+
Current version: **0.2.2** | [GitHub](https://github.com/game-sys/FaceSwitch) | [PyPI](https://pypi.org/project/faceswitch/)
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# FaceSwitch
|
|
2
|
+
|
|
3
|
+
**Detect faces in any image with one line of Python — swap the detector without changing your code.**
|
|
4
|
+
|
|
5
|
+
FaceSwitch is a lightweight Python library that wraps multiple face detection engines behind a single, consistent interface. Pick the detector that suits your needs, swap it later without rewriting anything, and only install what you actually use.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## What does it do?
|
|
10
|
+
|
|
11
|
+
You give it an image. It tells you where the faces are.
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
from faceswitch.detectors.yolo import YoloDetector
|
|
15
|
+
import cv2
|
|
16
|
+
|
|
17
|
+
image = cv2.imread("photo.jpg")
|
|
18
|
+
detector = YoloDetector()
|
|
19
|
+
faces = detector.detect(image)
|
|
20
|
+
|
|
21
|
+
for face in faces:
|
|
22
|
+
print(f"Face at ({face.x1}, {face.y1}) → ({face.x2}, {face.y2})")
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Every detector returns the same thing — a list of face boxes — so switching from YOLO to HOG (or any other detector) is just changing one import line.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
You need Python 3.10 or newer.
|
|
32
|
+
|
|
33
|
+
**Step 1 — install the base library:**
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pip install faceswitch
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**Step 2 — install the detector you want to use:**
|
|
40
|
+
|
|
41
|
+
| Detector | What it is | Install command |
|
|
42
|
+
|---|---|---|
|
|
43
|
+
| HOG | Classic CPU-based detector (fast, lightweight, no GPU needed) | `pip install "faceswitch[hog]"` |
|
|
44
|
+
| YOLO | Deep learning detector (more accurate, works best with GPU) | `pip install "faceswitch[yolo]"` |
|
|
45
|
+
| RetinaFace | High-accuracy ResNet detector (best for difficult angles and small faces) | `pip install "faceswitch[retinaface]"` |
|
|
46
|
+
|
|
47
|
+
| RetinaFace | Deep learning face detector using ResNet+FPN with multi-scale anchors for high-accuracy detection. | `pip install "faceswitch[retinaface]"` |
|
|
48
|
+
|
|
49
|
+
**Or install everything at once:**
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pip install "faceswitch[all]"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Quick start — 3 lines to detect faces
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
import cv2
|
|
61
|
+
from faceswitch.detectors.hog import HogDetector # swap this line to switch detectors
|
|
62
|
+
|
|
63
|
+
image = cv2.imread("photo.jpg")
|
|
64
|
+
faces = HogDetector().detect(image)
|
|
65
|
+
|
|
66
|
+
print(f"Found {len(faces)} face(s)")
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
To use a different detector, change only the import:
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
from faceswitch.detectors.yolo import YoloDetector # YOLO
|
|
73
|
+
from faceswitch.detectors.retinaface import RetinaFaceDetector # RetinaFace
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Everything else stays exactly the same.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Understanding the results
|
|
81
|
+
|
|
82
|
+
`detector.detect(image)` always returns a list of `FaceBox` objects. Each one looks like this:
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
FaceBox(x1=120, y1=45, x2=210, y2=160, confidence=0.97)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
| Field | Meaning |
|
|
89
|
+
|---|---|
|
|
90
|
+
| `x1`, `y1` | Top-left corner of the face box (pixels) |
|
|
91
|
+
| `x2`, `y2` | Bottom-right corner of the face box (pixels) |
|
|
92
|
+
| `confidence` | How sure the detector is (0.0 to 1.0). Some detectors don't provide this (`None`). |
|
|
93
|
+
|
|
94
|
+
**Draw the boxes on your image:**
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
import cv2
|
|
98
|
+
from faceswitch.detectors.yolo import YoloDetector
|
|
99
|
+
|
|
100
|
+
image = cv2.imread("photo.jpg")
|
|
101
|
+
faces = YoloDetector().detect(image)
|
|
102
|
+
|
|
103
|
+
for face in faces:
|
|
104
|
+
cv2.rectangle(image, (face.x1, face.y1), (face.x2, face.y2), (0, 255, 0), 2)
|
|
105
|
+
|
|
106
|
+
cv2.imwrite("result.jpg", image)
|
|
107
|
+
print(f"Saved result.jpg with {len(faces)} face(s) highlighted")
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Choosing the right detector
|
|
113
|
+
|
|
114
|
+
| | HOG | YOLO | RetinaFace |
|
|
115
|
+
|---|---|---|---|
|
|
116
|
+
| **Speed** | Fast | Medium | Slower |
|
|
117
|
+
| **Accuracy** | Basic | High | Very high |
|
|
118
|
+
| **GPU needed?** | No | Optional | No |
|
|
119
|
+
| **Best for** | Quick scripts, low-power machines | General use, real-time video | Difficult angles, small faces, production use |
|
|
120
|
+
| **Install size** | Small (~80MB) | Large (~500MB with torch) | Large (~200MB with TensorFlow) |
|
|
121
|
+
|
|
122
|
+
**Not sure?** Start with HOG. If it misses faces, switch to YOLO or RetinaFace — your code won't change.
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Available detectors
|
|
127
|
+
|
|
128
|
+
### HOG — `pip install "faceswitch[hog]"`
|
|
129
|
+
|
|
130
|
+
Uses dlib's Histogram of Oriented Gradients detector. Works entirely on CPU, very fast, good for frontal faces.
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
from faceswitch.detectors.hog import HogDetector
|
|
134
|
+
faces = HogDetector().detect(image)
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### YOLO — `pip install "faceswitch[yolo]"`
|
|
138
|
+
|
|
139
|
+
Uses Ultralytics YOLOv8. Deep learning-based, excellent accuracy on varied poses and lighting. Downloads a model on first use (~6MB).
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
from faceswitch.detectors.yolo import YoloDetector
|
|
143
|
+
faces = YoloDetector().detect(image)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### RetinaFace — `pip install "faceswitch[retinaface]"`
|
|
147
|
+
|
|
148
|
+
Uses the serengil/retinaface ResNet+FPN model. Best accuracy on small faces, side profiles, and crowded images. Downloads model weights on first use (~120MB).
|
|
149
|
+
|
|
150
|
+
```python
|
|
151
|
+
from faceswitch.detectors.retinaface import RetinaFaceDetector
|
|
152
|
+
faces = RetinaFaceDetector().detect(image)
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Common questions
|
|
158
|
+
|
|
159
|
+
**Do I need a GPU?**
|
|
160
|
+
No. All detectors run on CPU. YOLO and RetinaFace are faster with a GPU but don't require one.
|
|
161
|
+
|
|
162
|
+
**I get "ImportError: ... install faceswitch[hog]"**
|
|
163
|
+
You installed the base library but not the detector dependency. Run the install command from the table above.
|
|
164
|
+
|
|
165
|
+
**The detector downloads a model on first use — is that normal?**
|
|
166
|
+
Yes. YOLO (~6MB) and RetinaFace (~120MB) download their model weights automatically the first time you use them. After that, they're cached locally.
|
|
167
|
+
|
|
168
|
+
**Can I use my own image loading library instead of OpenCV?**
|
|
169
|
+
Yes, as long as the image is a NumPy array with shape `(height, width, 3)` and `uint8` dtype (standard BGR or RGB image). `cv2.imread()` gives you this automatically.
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## More detectors coming
|
|
174
|
+
|
|
175
|
+
FaceSwitch is actively maintained. New detectors are added regularly — run `pip install --upgrade faceswitch` to get the latest.
|
|
176
|
+
|
|
177
|
+
Current version: **0.2.2** | [GitHub](https://github.com/game-sys/FaceSwitch) | [PyPI](https://pypi.org/project/faceswitch/)
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "faceswitch"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.2"
|
|
8
8
|
description = "Simple multi-model face detection library"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -34,11 +34,13 @@ hog = ["dlib>=19.24"]
|
|
|
34
34
|
yolo = ["ultralytics>=8.0.0", "torch>=2.0.0"]
|
|
35
35
|
examples = ["opencv-python>=4.8"]
|
|
36
36
|
dev = ["pytest>=8.0"]
|
|
37
|
+
retinaface = ["retina-face"]
|
|
37
38
|
all = [
|
|
38
39
|
"dlib>=19.24",
|
|
39
40
|
"ultralytics>=8.0.0",
|
|
40
41
|
"torch>=2.0.0",
|
|
41
|
-
"opencv-python>=4.8"
|
|
42
|
+
"opencv-python>=4.8",
|
|
43
|
+
"retina-face"
|
|
42
44
|
]
|
|
43
45
|
|
|
44
46
|
[tool.setuptools]
|
|
@@ -13,4 +13,11 @@ try:
|
|
|
13
13
|
except ImportError:
|
|
14
14
|
pass
|
|
15
15
|
|
|
16
|
-
__version__ = "0.2.
|
|
16
|
+
__version__ = "0.2.2"
|
|
17
|
+
|
|
18
|
+
try:
|
|
19
|
+
from faceswitch.detectors.retinaface import RetinaFaceDetector, RetinaFaceDetectorConfig # noqa: F401
|
|
20
|
+
|
|
21
|
+
__all__ += ["RetinaFaceDetector", "RetinaFaceDetectorConfig"]
|
|
22
|
+
except ImportError:
|
|
23
|
+
pass
|
|
@@ -9,4 +9,11 @@ try:
|
|
|
9
9
|
|
|
10
10
|
__all__ += ["YoloDetector", "YoloDetectorConfig"]
|
|
11
11
|
except ImportError:
|
|
12
|
-
pass
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
try:
|
|
15
|
+
from faceswitch.detectors.retinaface import RetinaFaceDetector, RetinaFaceDetectorConfig # noqa: F401
|
|
16
|
+
|
|
17
|
+
__all__ += ["RetinaFaceDetector", "RetinaFaceDetectorConfig"]
|
|
18
|
+
except ImportError:
|
|
19
|
+
pass
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
from numpy.typing import NDArray
|
|
6
|
+
|
|
7
|
+
from faceswitch.core.interfaces import FaceDetector
|
|
8
|
+
from faceswitch.core.types import FaceBox
|
|
9
|
+
from faceswitch.detectors.retinaface.config import RetinaFaceDetectorConfig
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class RetinaFaceDetector(FaceDetector):
|
|
13
|
+
"""RetinaFace face detector."""
|
|
14
|
+
|
|
15
|
+
def __init__(self, config: RetinaFaceDetectorConfig | None = None) -> None:
|
|
16
|
+
try:
|
|
17
|
+
from retinaface import RetinaFace as _rf # type: ignore
|
|
18
|
+
except ImportError as exc:
|
|
19
|
+
raise ImportError(
|
|
20
|
+
"RetinaFaceDetector requires optional dependency 'retinaface'. "
|
|
21
|
+
"Install with: pip install 'faceswitch[retinaface]'"
|
|
22
|
+
) from exc
|
|
23
|
+
|
|
24
|
+
self.config = config or RetinaFaceDetectorConfig()
|
|
25
|
+
self._model = _rf
|
|
26
|
+
|
|
27
|
+
def detect(self, image: NDArray[np.uint8]) -> list[FaceBox]:
|
|
28
|
+
"""Detect faces and return list of FaceBox (xyxy)."""
|
|
29
|
+
if image is None:
|
|
30
|
+
return []
|
|
31
|
+
|
|
32
|
+
results = self._model.detect_faces(image)
|
|
33
|
+
if not isinstance(results, dict):
|
|
34
|
+
return []
|
|
35
|
+
boxes = []
|
|
36
|
+
for face in results.values():
|
|
37
|
+
x1, y1, x2, y2 = face["facial_area"]
|
|
38
|
+
score = float(face.get("score", 1.0))
|
|
39
|
+
boxes.append(FaceBox(x1=int(x1), y1=int(y1), x2=int(x2), y2=int(y2), confidence=score))
|
|
40
|
+
return boxes
|
|
@@ -18,8 +18,8 @@ class YoloDetector(FaceDetector):
|
|
|
18
18
|
# Put the real URL(s) you want to support
|
|
19
19
|
_MODEL_URLS: dict[str, str] = {
|
|
20
20
|
"yolov8n-face.pt": "https://github.com/YapaLab/yolo-face/releases/download/1.0.0/yolov8n-face.pt",
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
"yolov8m-face.pt": "https://github.com/YapaLab/yolo-face/releases/download/1.0.0/yolov8m-face.pt",
|
|
22
|
+
"yolov8l-face.pt": "https://github.com/YapaLab/yolo-face/releases/download/1.0.0/yolov8l-face.pt",
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
def __init__(self, config: YoloDetectorConfig | None = None) -> None:
|