提交 bf182525 编写于 作者: A Adam Geitgey

Add --show-distance paramter to CLI

上级 981a7d8b
......@@ -130,6 +130,8 @@ with the filename and the name of the person found.
An `unknown_person` is a face in the image that didn't match anyone in
your folder of known people.
##### Adjusting Tolerance / Sensitivity
If you are getting multiple matches for the same person, it might be that
the people in your photos look very similar and a lower tolerance value
is needed to make face comparisons more strict.
......@@ -144,6 +146,18 @@ $ face_recognition --tolerance 0.54 ./pictures_of_people_i_know/ ./unknown_pictu
/face_recognition_test/unknown_pictures/unknown.jpg,unknown_person
```
If you want to see the face distance calculated for each match in order
to adjust the tolerance setting, you can use `--show-distance true`:
```bash
$ face_recognition --show-distance true ./pictures_of_people_i_know/ ./unknown_pictures/
/unknown_pictures/unknown.jpg,Barack Obama,0.378542298956785
/face_recognition_test/unknown_pictures/unknown.jpg,unknown_person,None
```
##### More Examples
If you simply want to know the names of the people in each photograph but don't
care about file names, you could do this:
......@@ -154,7 +168,9 @@ Barack Obama
unknown_person
```
Face recognition can also be done in parallel if you have a computer with
##### Speeding up Face Recognition
Face recognition can be done in parallel if you have a computer with
multiple CPU cores. For example if your system has 4 CPU cores, you can
process about 4 times as many images in the same amount of time by using
all your CPU cores in parallel.
......
......@@ -32,7 +32,14 @@ def scan_known_people(known_people_folder):
return known_names, known_face_encodings
def test_image(image_to_check, known_names, known_face_encodings, tolerance=0.6):
def print_result(filename, name, distance, show_distance=False):
if show_distance:
print("{},{},{}".format(filename, name, distance))
else:
print("{},{}".format(filename, name))
def test_image(image_to_check, known_names, known_face_encodings, tolerance=0.6, show_distance=False):
unknown_image = face_recognition.load_image_file(image_to_check)
# 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)
unknown_encodings = face_recognition.face_encodings(unknown_image)
for unknown_encoding in unknown_encodings:
result = face_recognition.compare_faces(known_face_encodings, unknown_encoding, tolerance=tolerance)
distances = face_recognition.face_distance(known_face_encodings, unknown_encoding)
result = list(distances <= tolerance)
if True in result:
[print("{},{}".format(image_to_check, name)) for is_match, name in zip(result, known_names) if is_match]
[print_result(image_to_check, name, distance, show_distance) for is_match, name, distance in zip(result, known_names, distances) if is_match]
else:
print("{},unknown_person".format(image_to_check))
print_result(image_to_check, "unknown_person", None, show_distance)
def image_files_in_folder(folder):
return [os.path.join(folder, f) for f in os.listdir(folder) if re.match(r'.*\.(jpg|jpeg|png)', f, flags=re.I)]
def process_images_in_process_pool(images_to_check, known_names, known_face_encodings, number_of_cpus, tolerance):
def process_images_in_process_pool(images_to_check, known_names, known_face_encodings, number_of_cpus, tolerance, show_distance):
if number_of_cpus == -1:
processes = None
else:
......@@ -69,7 +77,14 @@ def process_images_in_process_pool(images_to_check, known_names, known_face_enco
context = multiprocessing.get_context("forkserver")
pool = context.Pool(processes=processes)
function_parameters = zip(images_to_check, itertools.repeat(known_names), itertools.repeat(known_face_encodings), itertools.repeat(tolerance))
function_parameters = zip(
images_to_check,
itertools.repeat(known_names),
itertools.repeat(known_face_encodings),
itertools.repeat(tolerance),
itertools.repeat(show_distance)
)
pool.starmap(test_image, function_parameters)
......@@ -79,7 +94,8 @@ def process_images_in_process_pool(images_to_check, known_names, known_face_enco
@click.argument('image_to_check')
@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"')
@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.')
def main(known_people_folder, image_to_check, cpus, tolerance):
@click.option('--show-distance', default=False, type=bool, help='Output face distance. Useful for tweaking tolerance setting.')
def main(known_people_folder, image_to_check, cpus, tolerance, show_distance):
known_names, known_face_encodings = scan_known_people(known_people_folder)
# 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):
if os.path.isdir(image_to_check):
if cpus == 1:
[test_image(image_file, known_names, known_face_encodings, tolerance) for image_file in image_files_in_folder(image_to_check)]
[test_image(image_file, known_names, known_face_encodings, tolerance, show_distance) for image_file in image_files_in_folder(image_to_check)]
else:
process_images_in_process_pool(image_files_in_folder(image_to_check), known_names, known_face_encodings, cpus, tolerance)
process_images_in_process_pool(image_files_in_folder(image_to_check), known_names, known_face_encodings, cpus, tolerance, show_distance)
else:
test_image(image_to_check, known_names, known_face_encodings)
test_image(image_to_check, known_names, known_face_encodings, tolerance, show_distance)
if __name__ == "__main__":
......
......@@ -183,7 +183,7 @@ class Test_face_recognition(unittest.TestCase):
self.assertListEqual(match_results, [])
def test_command_line_interface_options(self):
target_string = '--help Show this message and exit.'
target_string = 'Show this message and exit.'
runner = CliRunner()
help_result = runner.invoke(cli.main, ['--help'])
self.assertEqual(help_result.exit_code, 0)
......@@ -210,3 +210,14 @@ class Test_face_recognition(unittest.TestCase):
self.assertEqual(result.exit_code, 0)
self.assertTrue(target_string in result.output)
def test_command_line_interface_show_distance(self):
target_string = 'obama.jpg,obama,0.0'
runner = CliRunner()
image_folder = os.path.join(os.path.dirname(__file__), 'test_images')
image_file = os.path.join(os.path.dirname(__file__), 'test_images', 'obama.jpg')
result = runner.invoke(cli.main, args=[image_folder, image_file, "--show-distance", "1"])
self.assertEqual(result.exit_code, 0)
self.assertTrue(target_string in result.output)
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册