test_face_recognition.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. """
  4. test_face_recognition
  5. ----------------------------------
  6. Tests for `face_recognition` module.
  7. """
  8. import unittest
  9. import os
  10. import numpy as np
  11. from click.testing import CliRunner
  12. from face_recognition import api
  13. from face_recognition import face_recognition_cli
  14. from face_recognition import face_detection_cli
  15. class Test_face_recognition(unittest.TestCase):
  16. def test_load_image_file(self):
  17. img = api.load_image_file(os.path.join(os.path.dirname(__file__), 'test_images', 'obama.jpg'))
  18. self.assertEqual(img.shape, (1137, 910, 3))
  19. def test_load_image_file_32bit(self):
  20. img = api.load_image_file(os.path.join(os.path.dirname(__file__), 'test_images', '32bit.png'))
  21. self.assertEqual(img.shape, (1200, 626, 3))
  22. def test_raw_face_locations(self):
  23. img = api.load_image_file(os.path.join(os.path.dirname(__file__), 'test_images', 'obama.jpg'))
  24. detected_faces = api._raw_face_locations(img)
  25. self.assertEqual(len(detected_faces), 1)
  26. self.assertEqual(detected_faces[0].top(), 142)
  27. self.assertEqual(detected_faces[0].bottom(), 409)
  28. def test_cnn_raw_face_locations(self):
  29. img = api.load_image_file(os.path.join(os.path.dirname(__file__), 'test_images', 'obama.jpg'))
  30. detected_faces = api._raw_face_locations(img, model="cnn")
  31. self.assertEqual(len(detected_faces), 1)
  32. self.assertAlmostEqual(detected_faces[0].rect.top(), 144, delta=25)
  33. self.assertAlmostEqual(detected_faces[0].rect.bottom(), 389, delta=25)
  34. def test_raw_face_locations_32bit_image(self):
  35. img = api.load_image_file(os.path.join(os.path.dirname(__file__), 'test_images', '32bit.png'))
  36. detected_faces = api._raw_face_locations(img)
  37. self.assertEqual(len(detected_faces), 1)
  38. self.assertEqual(detected_faces[0].top(), 290)
  39. self.assertEqual(detected_faces[0].bottom(), 558)
  40. def test_cnn_raw_face_locations_32bit_image(self):
  41. img = api.load_image_file(os.path.join(os.path.dirname(__file__), 'test_images', '32bit.png'))
  42. detected_faces = api._raw_face_locations(img, model="cnn")
  43. self.assertEqual(len(detected_faces), 1)
  44. self.assertAlmostEqual(detected_faces[0].rect.top(), 259, delta=25)
  45. self.assertAlmostEqual(detected_faces[0].rect.bottom(), 552, delta=25)
  46. def test_face_locations(self):
  47. img = api.load_image_file(os.path.join(os.path.dirname(__file__), 'test_images', 'obama.jpg'))
  48. detected_faces = api.face_locations(img)
  49. self.assertEqual(len(detected_faces), 1)
  50. self.assertEqual(detected_faces[0], (142, 617, 409, 349))
  51. def test_cnn_face_locations(self):
  52. img = api.load_image_file(os.path.join(os.path.dirname(__file__), 'test_images', 'obama.jpg'))
  53. detected_faces = api.face_locations(img, model="cnn")
  54. self.assertEqual(len(detected_faces), 1)
  55. self.assertAlmostEqual(detected_faces[0][0], 144, delta=25)
  56. self.assertAlmostEqual(detected_faces[0][1], 608, delta=25)
  57. self.assertAlmostEqual(detected_faces[0][2], 389, delta=25)
  58. self.assertAlmostEqual(detected_faces[0][3], 363, delta=25)
  59. def test_partial_face_locations(self):
  60. img = api.load_image_file(os.path.join(os.path.dirname(__file__), 'test_images', 'obama_partial_face.jpg'))
  61. detected_faces = api.face_locations(img)
  62. self.assertEqual(len(detected_faces), 1)
  63. self.assertEqual(detected_faces[0], (142, 191, 365, 0))
  64. img = api.load_image_file(os.path.join(os.path.dirname(__file__), 'test_images', 'obama_partial_face2.jpg'))
  65. detected_faces = api.face_locations(img)
  66. self.assertEqual(len(detected_faces), 1)
  67. self.assertEqual(detected_faces[0], (142, 551, 409, 349))
  68. def test_raw_face_locations_batched(self):
  69. img = api.load_image_file(os.path.join(os.path.dirname(__file__), 'test_images', 'obama.jpg'))
  70. images = [img, img, img]
  71. batched_detected_faces = api._raw_face_locations_batched(images, number_of_times_to_upsample=0)
  72. for detected_faces in batched_detected_faces:
  73. self.assertEqual(len(detected_faces), 1)
  74. self.assertEqual(detected_faces[0].rect.top(), 154)
  75. self.assertEqual(detected_faces[0].rect.bottom(), 390)
  76. def test_batched_face_locations(self):
  77. img = api.load_image_file(os.path.join(os.path.dirname(__file__), 'test_images', 'obama.jpg'))
  78. images = [img, img, img]
  79. batched_detected_faces = api.batch_face_locations(images, number_of_times_to_upsample=0)
  80. for detected_faces in batched_detected_faces:
  81. self.assertEqual(len(detected_faces), 1)
  82. self.assertEqual(detected_faces[0], (154, 611, 390, 375))
  83. def test_raw_face_landmarks(self):
  84. img = api.load_image_file(os.path.join(os.path.dirname(__file__), 'test_images', 'obama.jpg'))
  85. face_landmarks = api._raw_face_landmarks(img)
  86. example_landmark = face_landmarks[0].parts()[10]
  87. self.assertEqual(len(face_landmarks), 1)
  88. self.assertEqual(face_landmarks[0].num_parts, 68)
  89. self.assertEqual((example_landmark.x, example_landmark.y), (552, 399))
  90. def test_face_landmarks(self):
  91. img = api.load_image_file(os.path.join(os.path.dirname(__file__), 'test_images', 'obama.jpg'))
  92. face_landmarks = api.face_landmarks(img)
  93. self.assertEqual(
  94. set(face_landmarks[0].keys()),
  95. set(['chin', 'left_eyebrow', 'right_eyebrow', 'nose_bridge',
  96. 'nose_tip', 'left_eye', 'right_eye', 'top_lip',
  97. 'bottom_lip']))
  98. self.assertEqual(
  99. face_landmarks[0]['chin'],
  100. [(369, 220), (372, 254), (378, 289), (384, 322), (395, 353),
  101. (414, 382), (437, 407), (464, 424), (495, 428), (527, 420),
  102. (552, 399), (576, 372), (594, 344), (604, 314), (610, 282),
  103. (613, 250), (615, 219)])
  104. def test_face_landmarks_small_model(self):
  105. img = api.load_image_file(os.path.join(os.path.dirname(__file__), 'test_images', 'obama.jpg'))
  106. face_landmarks = api.face_landmarks(img, model="small")
  107. self.assertEqual(
  108. set(face_landmarks[0].keys()),
  109. set(['nose_tip', 'left_eye', 'right_eye']))
  110. self.assertEqual(face_landmarks[0]['nose_tip'], [(496, 295)])
  111. def test_face_encodings(self):
  112. img = api.load_image_file(os.path.join(os.path.dirname(__file__), 'test_images', 'obama.jpg'))
  113. encodings = api.face_encodings(img)
  114. self.assertEqual(len(encodings), 1)
  115. self.assertEqual(len(encodings[0]), 128)
  116. def test_face_distance(self):
  117. img_a1 = api.load_image_file(os.path.join(os.path.dirname(__file__), 'test_images', 'obama.jpg'))
  118. img_a2 = api.load_image_file(os.path.join(os.path.dirname(__file__), 'test_images', 'obama2.jpg'))
  119. img_a3 = api.load_image_file(os.path.join(os.path.dirname(__file__), 'test_images', 'obama3.jpg'))
  120. img_b1 = api.load_image_file(os.path.join(os.path.dirname(__file__), 'test_images', 'biden.jpg'))
  121. face_encoding_a1 = api.face_encodings(img_a1)[0]
  122. face_encoding_a2 = api.face_encodings(img_a2)[0]
  123. face_encoding_a3 = api.face_encodings(img_a3)[0]
  124. face_encoding_b1 = api.face_encodings(img_b1)[0]
  125. faces_to_compare = [
  126. face_encoding_a2,
  127. face_encoding_a3,
  128. face_encoding_b1]
  129. distance_results = api.face_distance(faces_to_compare, face_encoding_a1)
  130. # 0.6 is the default face distance match threshold. So we'll spot-check that the numbers returned
  131. # are above or below that based on if they should match (since the exact numbers could vary).
  132. self.assertEqual(type(distance_results), np.ndarray)
  133. self.assertLessEqual(distance_results[0], 0.6)
  134. self.assertLessEqual(distance_results[1], 0.6)
  135. self.assertGreater(distance_results[2], 0.6)
  136. def test_face_distance_empty_lists(self):
  137. img = api.load_image_file(os.path.join(os.path.dirname(__file__), 'test_images', 'biden.jpg'))
  138. face_encoding = api.face_encodings(img)[0]
  139. # empty python list
  140. faces_to_compare = []
  141. distance_results = api.face_distance(faces_to_compare, face_encoding)
  142. self.assertEqual(type(distance_results), np.ndarray)
  143. self.assertEqual(len(distance_results), 0)
  144. # empty numpy list
  145. faces_to_compare = np.array([])
  146. distance_results = api.face_distance(faces_to_compare, face_encoding)
  147. self.assertEqual(type(distance_results), np.ndarray)
  148. self.assertEqual(len(distance_results), 0)
  149. def test_compare_faces(self):
  150. img_a1 = api.load_image_file(os.path.join(os.path.dirname(__file__), 'test_images', 'obama.jpg'))
  151. img_a2 = api.load_image_file(os.path.join(os.path.dirname(__file__), 'test_images', 'obama2.jpg'))
  152. img_a3 = api.load_image_file(os.path.join(os.path.dirname(__file__), 'test_images', 'obama3.jpg'))
  153. img_b1 = api.load_image_file(os.path.join(os.path.dirname(__file__), 'test_images', 'biden.jpg'))
  154. face_encoding_a1 = api.face_encodings(img_a1)[0]
  155. face_encoding_a2 = api.face_encodings(img_a2)[0]
  156. face_encoding_a3 = api.face_encodings(img_a3)[0]
  157. face_encoding_b1 = api.face_encodings(img_b1)[0]
  158. faces_to_compare = [
  159. face_encoding_a2,
  160. face_encoding_a3,
  161. face_encoding_b1]
  162. match_results = api.compare_faces(faces_to_compare, face_encoding_a1)
  163. self.assertEqual(type(match_results), list)
  164. self.assertTrue(match_results[0])
  165. self.assertTrue(match_results[1])
  166. self.assertFalse(match_results[2])
  167. def test_compare_faces_empty_lists(self):
  168. img = api.load_image_file(os.path.join(os.path.dirname(__file__), 'test_images', 'biden.jpg'))
  169. face_encoding = api.face_encodings(img)[0]
  170. # empty python list
  171. faces_to_compare = []
  172. match_results = api.compare_faces(faces_to_compare, face_encoding)
  173. self.assertEqual(type(match_results), list)
  174. self.assertListEqual(match_results, [])
  175. # empty numpy list
  176. faces_to_compare = np.array([])
  177. match_results = api.compare_faces(faces_to_compare, face_encoding)
  178. self.assertEqual(type(match_results), list)
  179. self.assertListEqual(match_results, [])
  180. def test_command_line_interface_options(self):
  181. target_string = 'Show this message and exit.'
  182. runner = CliRunner()
  183. help_result = runner.invoke(face_recognition_cli.main, ['--help'])
  184. self.assertEqual(help_result.exit_code, 0)
  185. self.assertTrue(target_string in help_result.output)
  186. def test_command_line_interface(self):
  187. target_string = 'obama.jpg,obama'
  188. runner = CliRunner()
  189. image_folder = os.path.join(os.path.dirname(__file__), 'test_images')
  190. image_file = os.path.join(os.path.dirname(__file__), 'test_images', 'obama.jpg')
  191. result = runner.invoke(face_recognition_cli.main, args=[image_folder, image_file])
  192. self.assertEqual(result.exit_code, 0)
  193. self.assertTrue(target_string in result.output)
  194. def test_command_line_interface_big_image(self):
  195. target_string = 'obama3.jpg,obama'
  196. runner = CliRunner()
  197. image_folder = os.path.join(os.path.dirname(__file__), 'test_images')
  198. image_file = os.path.join(os.path.dirname(__file__), 'test_images', 'obama3.jpg')
  199. result = runner.invoke(face_recognition_cli.main, args=[image_folder, image_file])
  200. self.assertEqual(result.exit_code, 0)
  201. self.assertTrue(target_string in result.output)
  202. def test_command_line_interface_tolerance(self):
  203. target_string = 'obama.jpg,obama'
  204. runner = CliRunner()
  205. image_folder = os.path.join(os.path.dirname(__file__), 'test_images')
  206. image_file = os.path.join(os.path.dirname(__file__), 'test_images', 'obama.jpg')
  207. result = runner.invoke(face_recognition_cli.main, args=[image_folder, image_file, "--tolerance", "0.55"])
  208. self.assertEqual(result.exit_code, 0)
  209. self.assertTrue(target_string in result.output)
  210. def test_command_line_interface_show_distance(self):
  211. target_string = 'obama.jpg,obama,0.0'
  212. runner = CliRunner()
  213. image_folder = os.path.join(os.path.dirname(__file__), 'test_images')
  214. image_file = os.path.join(os.path.dirname(__file__), 'test_images', 'obama.jpg')
  215. result = runner.invoke(face_recognition_cli.main, args=[image_folder, image_file, "--show-distance", "1"])
  216. self.assertEqual(result.exit_code, 0)
  217. self.assertTrue(target_string in result.output)
  218. def test_fd_command_line_interface_options(self):
  219. target_string = 'Show this message and exit.'
  220. runner = CliRunner()
  221. help_result = runner.invoke(face_detection_cli.main, ['--help'])
  222. self.assertEqual(help_result.exit_code, 0)
  223. self.assertTrue(target_string in help_result.output)
  224. def test_fd_command_line_interface(self):
  225. runner = CliRunner()
  226. image_file = os.path.join(os.path.dirname(__file__), 'test_images', 'obama.jpg')
  227. result = runner.invoke(face_detection_cli.main, args=[image_file])
  228. self.assertEqual(result.exit_code, 0)
  229. parts = result.output.split(",")
  230. self.assertTrue("obama.jpg" in parts[0])
  231. self.assertEqual(len(parts), 5)
  232. def test_fd_command_line_interface_folder(self):
  233. runner = CliRunner()
  234. image_file = os.path.join(os.path.dirname(__file__), 'test_images')
  235. result = runner.invoke(face_detection_cli.main, args=[image_file])
  236. self.assertEqual(result.exit_code, 0)
  237. self.assertTrue("obama_partial_face2.jpg" in result.output)
  238. self.assertTrue("obama.jpg" in result.output)
  239. self.assertTrue("obama2.jpg" in result.output)
  240. self.assertTrue("obama3.jpg" in result.output)
  241. self.assertTrue("biden.jpg" in result.output)
  242. def test_fd_command_line_interface_hog_model(self):
  243. target_string = 'obama.jpg'
  244. runner = CliRunner()
  245. image_file = os.path.join(os.path.dirname(__file__), 'test_images', 'obama.jpg')
  246. result = runner.invoke(face_detection_cli.main, args=[image_file, "--model", "hog"])
  247. self.assertEqual(result.exit_code, 0)
  248. self.assertTrue(target_string in result.output)
  249. def test_fd_command_line_interface_cnn_model(self):
  250. target_string = 'obama.jpg'
  251. runner = CliRunner()
  252. image_file = os.path.join(os.path.dirname(__file__), 'test_images', 'obama.jpg')
  253. result = runner.invoke(face_detection_cli.main, args=[image_file, "--model", "cnn"])
  254. self.assertEqual(result.exit_code, 0)
  255. self.assertTrue(target_string in result.output)