Skip to content

Commit bf18252

Browse files
committed
Add --show-distance paramter to CLI
1 parent 981a7d8 commit bf18252

File tree

3 files changed

+55
-12
lines changed

3 files changed

+55
-12
lines changed

README.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ with the filename and the name of the person found.
130130
An `unknown_person` is a face in the image that didn't match anyone in
131131
your folder of known people.
132132

133+
##### Adjusting Tolerance / Sensitivity
134+
133135
If you are getting multiple matches for the same person, it might be that
134136
the people in your photos look very similar and a lower tolerance value
135137
is needed to make face comparisons more strict.
@@ -144,6 +146,18 @@ $ face_recognition --tolerance 0.54 ./pictures_of_people_i_know/ ./unknown_pictu
144146
/face_recognition_test/unknown_pictures/unknown.jpg,unknown_person
145147
```
146148

149+
If you want to see the face distance calculated for each match in order
150+
to adjust the tolerance setting, you can use `--show-distance true`:
151+
152+
```bash
153+
$ face_recognition --show-distance true ./pictures_of_people_i_know/ ./unknown_pictures/
154+
155+
/unknown_pictures/unknown.jpg,Barack Obama,0.378542298956785
156+
/face_recognition_test/unknown_pictures/unknown.jpg,unknown_person,None
157+
```
158+
159+
##### More Examples
160+
147161
If you simply want to know the names of the people in each photograph but don't
148162
care about file names, you could do this:
149163

@@ -154,7 +168,9 @@ Barack Obama
154168
unknown_person
155169
```
156170

157-
Face recognition can also be done in parallel if you have a computer with
171+
##### Speeding up Face Recognition
172+
173+
Face recognition can be done in parallel if you have a computer with
158174
multiple CPU cores. For example if your system has 4 CPU cores, you can
159175
process about 4 times as many images in the same amount of time by using
160176
all your CPU cores in parallel.

face_recognition/cli.py

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,14 @@ def scan_known_people(known_people_folder):
3232
return known_names, known_face_encodings
3333

3434

35-
def test_image(image_to_check, known_names, known_face_encodings, tolerance=0.6):
35+
def print_result(filename, name, distance, show_distance=False):
36+
if show_distance:
37+
print("{},{},{}".format(filename, name, distance))
38+
else:
39+
print("{},{}".format(filename, name))
40+
41+
42+
def test_image(image_to_check, known_names, known_face_encodings, tolerance=0.6, show_distance=False):
3643
unknown_image = face_recognition.load_image_file(image_to_check)
3744

3845
# Scale down image if it's giant so things run a little faster
@@ -45,19 +52,20 @@ def test_image(image_to_check, known_names, known_face_encodings, tolerance=0.6)
4552
unknown_encodings = face_recognition.face_encodings(unknown_image)
4653

4754
for unknown_encoding in unknown_encodings:
48-
result = face_recognition.compare_faces(known_face_encodings, unknown_encoding, tolerance=tolerance)
55+
distances = face_recognition.face_distance(known_face_encodings, unknown_encoding)
56+
result = list(distances <= tolerance)
4957

5058
if True in result:
51-
[print("{},{}".format(image_to_check, name)) for is_match, name in zip(result, known_names) if is_match]
59+
[print_result(image_to_check, name, distance, show_distance) for is_match, name, distance in zip(result, known_names, distances) if is_match]
5260
else:
53-
print("{},unknown_person".format(image_to_check))
61+
print_result(image_to_check, "unknown_person", None, show_distance)
5462

5563

5664
def image_files_in_folder(folder):
5765
return [os.path.join(folder, f) for f in os.listdir(folder) if re.match(r'.*\.(jpg|jpeg|png)', f, flags=re.I)]
5866

5967

60-
def process_images_in_process_pool(images_to_check, known_names, known_face_encodings, number_of_cpus, tolerance):
68+
def process_images_in_process_pool(images_to_check, known_names, known_face_encodings, number_of_cpus, tolerance, show_distance):
6169
if number_of_cpus == -1:
6270
processes = None
6371
else:
@@ -69,7 +77,14 @@ def process_images_in_process_pool(images_to_check, known_names, known_face_enco
6977
context = multiprocessing.get_context("forkserver")
7078

7179
pool = context.Pool(processes=processes)
72-
function_parameters = zip(images_to_check, itertools.repeat(known_names), itertools.repeat(known_face_encodings), itertools.repeat(tolerance))
80+
81+
function_parameters = zip(
82+
images_to_check,
83+
itertools.repeat(known_names),
84+
itertools.repeat(known_face_encodings),
85+
itertools.repeat(tolerance),
86+
itertools.repeat(show_distance)
87+
)
7388

7489
pool.starmap(test_image, function_parameters)
7590

@@ -79,7 +94,8 @@ def process_images_in_process_pool(images_to_check, known_names, known_face_enco
7994
@click.argument('image_to_check')
8095
@click.option('--cpus', default=1, help='number of CPU cores to use in parallel (can speed up processing lots of images). -1 means "use all in system"')
8196
@click.option('--tolerance', default=0.6, help='Tolerance for face comparisons. Default is 0.6. Lower this if you get multiple matches for the same person.')
82-
def main(known_people_folder, image_to_check, cpus, tolerance):
97+
@click.option('--show-distance', default=False, type=bool, help='Output face distance. Useful for tweaking tolerance setting.')
98+
def main(known_people_folder, image_to_check, cpus, tolerance, show_distance):
8399
known_names, known_face_encodings = scan_known_people(known_people_folder)
84100

85101
# Multi-core processing only supported on Python 3.4 or greater
@@ -89,11 +105,11 @@ def main(known_people_folder, image_to_check, cpus, tolerance):
89105

90106
if os.path.isdir(image_to_check):
91107
if cpus == 1:
92-
[test_image(image_file, known_names, known_face_encodings, tolerance) for image_file in image_files_in_folder(image_to_check)]
108+
[test_image(image_file, known_names, known_face_encodings, tolerance, show_distance) for image_file in image_files_in_folder(image_to_check)]
93109
else:
94-
process_images_in_process_pool(image_files_in_folder(image_to_check), known_names, known_face_encodings, cpus, tolerance)
110+
process_images_in_process_pool(image_files_in_folder(image_to_check), known_names, known_face_encodings, cpus, tolerance, show_distance)
95111
else:
96-
test_image(image_to_check, known_names, known_face_encodings)
112+
test_image(image_to_check, known_names, known_face_encodings, tolerance, show_distance)
97113

98114

99115
if __name__ == "__main__":

tests/test_face_recognition.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ def test_compare_faces_empty_lists(self):
183183
self.assertListEqual(match_results, [])
184184

185185
def test_command_line_interface_options(self):
186-
target_string = '--help Show this message and exit.'
186+
target_string = 'Show this message and exit.'
187187
runner = CliRunner()
188188
help_result = runner.invoke(cli.main, ['--help'])
189189
self.assertEqual(help_result.exit_code, 0)
@@ -210,3 +210,14 @@ def test_command_line_interface_tolerance(self):
210210

211211
self.assertEqual(result.exit_code, 0)
212212
self.assertTrue(target_string in result.output)
213+
214+
def test_command_line_interface_show_distance(self):
215+
target_string = 'obama.jpg,obama,0.0'
216+
runner = CliRunner()
217+
image_folder = os.path.join(os.path.dirname(__file__), 'test_images')
218+
image_file = os.path.join(os.path.dirname(__file__), 'test_images', 'obama.jpg')
219+
220+
result = runner.invoke(cli.main, args=[image_folder, image_file, "--show-distance", "1"])
221+
222+
self.assertEqual(result.exit_code, 0)
223+
self.assertTrue(target_string in result.output)

0 commit comments

Comments
 (0)