Skip to content

Commit b8a8037

Browse files
committed
Add tolerance parameter to CLI
1 parent f216314 commit b8a8037

File tree

3 files changed

+37
-11
lines changed

3 files changed

+37
-11
lines changed

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,20 @@ 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+
If you are getting multiple matches for the same person, it might be that
134+
the people in your photos look very similar and a lower tolerance value
135+
is needed to make face comparisons more strict.
136+
137+
You can do that with the `--tolerance` parameter. The default tolerance
138+
value is 0.6 and lower numbers make face comparisons more strict:
139+
140+
```bash
141+
$ face_recognition --tolerance 0.54 ./pictures_of_people_i_know/ ./unknown_pictures/
142+
143+
/unknown_pictures/unknown.jpg,Barack Obama
144+
/face_recognition_test/unknown_pictures/unknown.jpg,unknown_person
145+
```
146+
133147
If you simply want to know the names of the people in each photograph but don't
134148
care about file names, you could do this:
135149

face_recognition/cli.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ 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):
35+
def test_image(image_to_check, known_names, known_face_encodings, tolerance=0.6):
3636
unknown_image = face_recognition.load_image_file(image_to_check)
3737

3838
# Scale down image if it's giant so things run a little faster
@@ -45,7 +45,7 @@ def test_image(image_to_check, known_names, known_face_encodings):
4545
unknown_encodings = face_recognition.face_encodings(unknown_image)
4646

4747
for unknown_encoding in unknown_encodings:
48-
result = face_recognition.compare_faces(known_face_encodings, unknown_encoding)
48+
result = face_recognition.compare_faces(known_face_encodings, unknown_encoding, tolerance=tolerance)
4949

5050
if True in result:
5151
[print("{},{}".format(image_to_check, name)) for is_match, name in zip(result, known_names) if is_match]
@@ -57,7 +57,7 @@ def image_files_in_folder(folder):
5757
return [os.path.join(folder, f) for f in os.listdir(folder) if re.match(r'.*\.(jpg|jpeg|png)', f, flags=re.I)]
5858

5959

60-
def process_images_in_process_pool(images_to_check, known_names, known_face_encodings, number_of_cpus):
60+
def process_images_in_process_pool(images_to_check, known_names, known_face_encodings, number_of_cpus, tolerance):
6161
if number_of_cpus == -1:
6262
processes = None
6363
else:
@@ -69,7 +69,7 @@ def process_images_in_process_pool(images_to_check, known_names, known_face_enco
6969
context = multiprocessing.get_context("forkserver")
7070

7171
pool = context.Pool(processes=processes)
72-
function_parameters = zip(images_to_check, itertools.repeat(known_names), itertools.repeat(known_face_encodings))
72+
function_parameters = zip(images_to_check, itertools.repeat(known_names), itertools.repeat(known_face_encodings), itertools.repeat(tolerance))
7373

7474
pool.starmap(test_image, function_parameters)
7575

@@ -78,7 +78,8 @@ def process_images_in_process_pool(images_to_check, known_names, known_face_enco
7878
@click.argument('known_people_folder')
7979
@click.argument('image_to_check')
8080
@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"')
81-
def main(known_people_folder, image_to_check, cpus):
81+
@click.option('--tolerance', default=0.6, help='Tolerance to use for face comparisons. Default is 0.6 and lower is more strict matching. Lower this if you get multiple matches for the same person. Try 0.54 for example.')
82+
def main(known_people_folder, image_to_check, cpus, tolerance):
8283
known_names, known_face_encodings = scan_known_people(known_people_folder)
8384

8485
# Multi-core processing only supported on Python 3.4 or greater
@@ -88,9 +89,9 @@ def main(known_people_folder, image_to_check, cpus):
8889

8990
if os.path.isdir(image_to_check):
9091
if cpus == 1:
91-
[test_image(image_file, known_names, known_face_encodings) for image_file in image_files_in_folder(image_to_check)]
92+
[test_image(image_file, known_names, known_face_encodings, tolerance) for image_file in image_files_in_folder(image_to_check)]
9293
else:
93-
process_images_in_process_pool(image_files_in_folder(image_to_check), known_names, known_face_encodings, cpus)
94+
process_images_in_process_pool(image_files_in_folder(image_to_check), known_names, known_face_encodings, cpus, tolerance)
9495
else:
9596
test_image(image_to_check, known_names, known_face_encodings)
9697

tests/test_face_recognition.py

Lines changed: 15 additions & 4 deletions
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 = '--help Show this message and exit.'
187187
runner = CliRunner()
188188
help_result = runner.invoke(cli.main, ['--help'])
189189
self.assertEqual(help_result.exit_code, 0)
@@ -195,7 +195,18 @@ def test_command_line_interface(self):
195195
image_folder = os.path.join(os.path.dirname(__file__), 'test_images')
196196
image_file = os.path.join(os.path.dirname(__file__), 'test_images', 'obama.jpg')
197197

198-
help_result = runner.invoke(cli.main, args=[image_folder, image_file])
198+
result = runner.invoke(cli.main, args=[image_folder, image_file])
199199

200-
self.assertEqual(help_result.exit_code, 0)
201-
self.assertTrue(target_string in help_result.output)
200+
self.assertEqual(result.exit_code, 0)
201+
self.assertTrue(target_string in result.output)
202+
203+
def test_command_line_interface_tolerance(self):
204+
target_string = 'obama.jpg,obama'
205+
runner = CliRunner()
206+
image_folder = os.path.join(os.path.dirname(__file__), 'test_images')
207+
image_file = os.path.join(os.path.dirname(__file__), 'test_images', 'obama.jpg')
208+
209+
result = runner.invoke(cli.main, args=[image_folder, image_file, "--tolerance", "0.55"])
210+
211+
self.assertEqual(result.exit_code, 0)
212+
self.assertTrue(target_string in result.output)

0 commit comments

Comments
 (0)