forked from realpython/materials
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdetector.py
More file actions
117 lines (96 loc) · 3.34 KB
/
Copy pathdetector.py
File metadata and controls
117 lines (96 loc) · 3.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import pickle
from collections import Counter
from pathlib import Path
import face_recognition
from PIL import Image, ImageDraw
DEFAULT_ENCODINGS_PATH = Path("output/encodings.pkl")
BOUNDING_BOX_COLOR = "blue"
TEXT_COLOR = "white"
# Create directories if they don't already exist
Path("training").mkdir(exist_ok=True)
Path("output").mkdir(exist_ok=True)
Path("validation").mkdir(exist_ok=True)
def encode_known_faces(
model: str = "hog", encodings_location: Path = DEFAULT_ENCODINGS_PATH
) -> None:
"""
Loads images in the training directory and builds a dictionary of their
names and encodings.
"""
names = []
encodings = []
for filepath in Path("training").glob("*/*"):
name = filepath.parent.name
image = face_recognition.load_image_file(filepath)
face_locations = face_recognition.face_locations(image, model=model)
face_encodings = face_recognition.face_encodings(image, face_locations)
for encoding in face_encodings:
names.append(name)
encodings.append(encoding)
name_encodings = {"names": names, "encodings": encodings}
with encodings_location.open(mode="wb") as f:
pickle.dump(name_encodings, f)
def recognize_faces(
image_location: str,
model: str = "hog",
encodings_location: Path = DEFAULT_ENCODINGS_PATH,
) -> None:
"""
Given an unknown image, get the locations and encodings of any faces and
compares them against the known encodings to find potential matches.
"""
with encodings_location.open(mode="rb") as f:
loaded_encodings = pickle.load(f)
input_image = face_recognition.load_image_file(image_location)
input_face_locations = face_recognition.face_locations(
input_image, model=model
)
input_face_encodings = face_recognition.face_encodings(
input_image, input_face_locations
)
pillow_image = Image.fromarray(input_image)
draw = ImageDraw.Draw(pillow_image)
for bounding_box, unknown_encoding in zip(
input_face_locations, input_face_encodings
):
name = _recognize_face(unknown_encoding, loaded_encodings)
if not name:
name = "Unknown"
_display_face(draw, bounding_box, name)
del draw
pillow_image.show()
def _recognize_face(unknown_encoding, loaded_encodings):
"""
Given an unknown encoding and all known encodings, find the known
encoding with the most matches.
"""
boolean_matches = face_recognition.compare_faces(
loaded_encodings["encodings"], unknown_encoding
)
votes = Counter(
name
for match, name in zip(boolean_matches, loaded_encodings["names"])
if match
)
if votes:
return votes.most_common(1)[0][0]
def _display_face(draw, bounding_box, name):
"""
Draws bounding boxes around faces, a caption area, and text captions.
"""
top, right, bottom, left = bounding_box
draw.rectangle(((left, top), (right, bottom)), outline=BOUNDING_BOX_COLOR)
text_left, text_top, text_right, text_bottom = draw.textbbox(
(left, bottom), name
)
draw.rectangle(
((text_left, text_top), (text_right, text_bottom)),
fill=BOUNDING_BOX_COLOR,
outline=BOUNDING_BOX_COLOR,
)
draw.text(
(text_left, text_top),
name,
fill=TEXT_COLOR,
)
recognize_faces("unknown.jpg")