Register
Login
Resources
Docs Blog Datasets Glossary Case Studies Tutorials & Webinars
Product
Data Engine LLMs Platform Enterprise
Pricing Explore
Connect to our Discord channel

api.py 10 KB

You have to be logged in to leave a comment. Sign In
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
  1. # -*- coding: utf-8 -*-
  2. import PIL.Image
  3. import dlib
  4. import numpy as np
  5. from PIL import ImageFile
  6. try:
  7. import face_recognition_models
  8. except Exception:
  9. print("Please install `face_recognition_models` with this command before using `face_recognition`:\n")
  10. print("pip install git+https://github.com/ageitgey/face_recognition_models")
  11. quit()
  12. ImageFile.LOAD_TRUNCATED_IMAGES = True
  13. face_detector = dlib.get_frontal_face_detector()
  14. predictor_68_point_model = face_recognition_models.pose_predictor_model_location()
  15. pose_predictor_68_point = dlib.shape_predictor(predictor_68_point_model)
  16. predictor_5_point_model = face_recognition_models.pose_predictor_five_point_model_location()
  17. pose_predictor_5_point = dlib.shape_predictor(predictor_5_point_model)
  18. cnn_face_detection_model = face_recognition_models.cnn_face_detector_model_location()
  19. cnn_face_detector = dlib.cnn_face_detection_model_v1(cnn_face_detection_model)
  20. face_recognition_model = face_recognition_models.face_recognition_model_location()
  21. face_encoder = dlib.face_recognition_model_v1(face_recognition_model)
  22. def _rect_to_css(rect):
  23. """
  24. Convert a dlib 'rect' object to a plain tuple in (top, right, bottom, left) order
  25. :param rect: a dlib 'rect' object
  26. :return: a plain tuple representation of the rect in (top, right, bottom, left) order
  27. """
  28. return rect.top(), rect.right(), rect.bottom(), rect.left()
  29. def _css_to_rect(css):
  30. """
  31. Convert a tuple in (top, right, bottom, left) order to a dlib `rect` object
  32. :param css: plain tuple representation of the rect in (top, right, bottom, left) order
  33. :return: a dlib `rect` object
  34. """
  35. return dlib.rectangle(css[3], css[0], css[1], css[2])
  36. def _trim_css_to_bounds(css, image_shape):
  37. """
  38. Make sure a tuple in (top, right, bottom, left) order is within the bounds of the image.
  39. :param css: plain tuple representation of the rect in (top, right, bottom, left) order
  40. :param image_shape: numpy shape of the image array
  41. :return: a trimmed plain tuple representation of the rect in (top, right, bottom, left) order
  42. """
  43. return max(css[0], 0), min(css[1], image_shape[1]), min(css[2], image_shape[0]), max(css[3], 0)
  44. def face_distance(face_encodings, face_to_compare):
  45. """
  46. Given a list of face encodings, compare them to a known face encoding and get a euclidean distance
  47. for each comparison face. The distance tells you how similar the faces are.
  48. :param faces: List of face encodings to compare
  49. :param face_to_compare: A face encoding to compare against
  50. :return: A numpy ndarray with the distance for each face in the same order as the 'faces' array
  51. """
  52. if len(face_encodings) == 0:
  53. return np.empty((0))
  54. return np.linalg.norm(face_encodings - face_to_compare, axis=1)
  55. def load_image_file(file, mode='RGB'):
  56. """
  57. Loads an image file (.jpg, .png, etc) into a numpy array
  58. :param file: image file name or file object to load
  59. :param mode: format to convert the image to. Only 'RGB' (8-bit RGB, 3 channels) and 'L' (black and white) are supported.
  60. :return: image contents as numpy array
  61. """
  62. im = PIL.Image.open(file)
  63. if mode:
  64. im = im.convert(mode)
  65. return np.array(im)
  66. def _raw_face_locations(img, number_of_times_to_upsample=1, model="hog"):
  67. """
  68. Returns an array of bounding boxes of human faces in a image
  69. :param img: An image (as a numpy array)
  70. :param number_of_times_to_upsample: How many times to upsample the image looking for faces. Higher numbers find smaller faces.
  71. :param model: Which face detection model to use. "hog" is less accurate but faster on CPUs. "cnn" is a more accurate
  72. deep-learning model which is GPU/CUDA accelerated (if available). The default is "hog".
  73. :return: A list of dlib 'rect' objects of found face locations
  74. """
  75. if model == "cnn":
  76. return cnn_face_detector(img, number_of_times_to_upsample)
  77. else:
  78. return face_detector(img, number_of_times_to_upsample)
  79. def face_locations(img, number_of_times_to_upsample=1, model="hog"):
  80. """
  81. Returns an array of bounding boxes of human faces in a image
  82. :param img: An image (as a numpy array)
  83. :param number_of_times_to_upsample: How many times to upsample the image looking for faces. Higher numbers find smaller faces.
  84. :param model: Which face detection model to use. "hog" is less accurate but faster on CPUs. "cnn" is a more accurate
  85. deep-learning model which is GPU/CUDA accelerated (if available). The default is "hog".
  86. :return: A list of tuples of found face locations in css (top, right, bottom, left) order
  87. """
  88. if model == "cnn":
  89. return [_trim_css_to_bounds(_rect_to_css(face.rect), img.shape) for face in _raw_face_locations(img, number_of_times_to_upsample, "cnn")]
  90. else:
  91. return [_trim_css_to_bounds(_rect_to_css(face), img.shape) for face in _raw_face_locations(img, number_of_times_to_upsample, model)]
  92. def _raw_face_locations_batched(images, number_of_times_to_upsample=1, batch_size=128):
  93. """
  94. Returns an 2d array of dlib rects of human faces in a image using the cnn face detector
  95. :param img: A list of images (each as a numpy array)
  96. :param number_of_times_to_upsample: How many times to upsample the image looking for faces. Higher numbers find smaller faces.
  97. :return: A list of dlib 'rect' objects of found face locations
  98. """
  99. return cnn_face_detector(images, number_of_times_to_upsample, batch_size=batch_size)
  100. def batch_face_locations(images, number_of_times_to_upsample=1, batch_size=128):
  101. """
  102. Returns an 2d array of bounding boxes of human faces in a image using the cnn face detector
  103. If you are using a GPU, this can give you much faster results since the GPU
  104. can process batches of images at once. If you aren't using a GPU, you don't need this function.
  105. :param images: A list of images (each as a numpy array)
  106. :param number_of_times_to_upsample: How many times to upsample the image looking for faces. Higher numbers find smaller faces.
  107. :param batch_size: How many images to include in each GPU processing batch.
  108. :return: A list of tuples of found face locations in css (top, right, bottom, left) order
  109. """
  110. def convert_cnn_detections_to_css(detections):
  111. return [_trim_css_to_bounds(_rect_to_css(face.rect), images[0].shape) for face in detections]
  112. raw_detections_batched = _raw_face_locations_batched(images, number_of_times_to_upsample, batch_size)
  113. return list(map(convert_cnn_detections_to_css, raw_detections_batched))
  114. def _raw_face_landmarks(face_image, face_locations=None, model="large"):
  115. if face_locations is None:
  116. face_locations = _raw_face_locations(face_image)
  117. else:
  118. face_locations = [_css_to_rect(face_location) for face_location in face_locations]
  119. pose_predictor = pose_predictor_68_point
  120. if model == "small":
  121. pose_predictor = pose_predictor_5_point
  122. return [pose_predictor(face_image, face_location) for face_location in face_locations]
  123. def face_landmarks(face_image, face_locations=None, model="large"):
  124. """
  125. Given an image, returns a dict of face feature locations (eyes, nose, etc) for each face in the image
  126. :param face_image: image to search
  127. :param face_locations: Optionally provide a list of face locations to check.
  128. :param model: Optional - which model to use. "large" (default) or "small" which only returns 5 points but is faster.
  129. :return: A list of dicts of face feature locations (eyes, nose, etc)
  130. """
  131. landmarks = _raw_face_landmarks(face_image, face_locations, model)
  132. landmarks_as_tuples = [[(p.x, p.y) for p in landmark.parts()] for landmark in landmarks]
  133. # For a definition of each point index, see https://cdn-images-1.medium.com/max/1600/1*AbEg31EgkbXSQehuNJBlWg.png
  134. if model == 'large':
  135. return [{
  136. "chin": points[0:17],
  137. "left_eyebrow": points[17:22],
  138. "right_eyebrow": points[22:27],
  139. "nose_bridge": points[27:31],
  140. "nose_tip": points[31:36],
  141. "left_eye": points[36:42],
  142. "right_eye": points[42:48],
  143. "top_lip": points[48:55] + [points[64]] + [points[63]] + [points[62]] + [points[61]] + [points[60]],
  144. "bottom_lip": points[54:60] + [points[48]] + [points[60]] + [points[67]] + [points[66]] + [points[65]] + [points[64]]
  145. } for points in landmarks_as_tuples]
  146. elif model == 'small':
  147. return [{
  148. "nose_tip": [points[4]],
  149. "left_eye": points[2:4],
  150. "right_eye": points[0:2],
  151. } for points in landmarks_as_tuples]
  152. else:
  153. raise ValueError("Invalid landmarks model type. Supported models are ['small', 'large'].")
  154. def face_encodings(face_image, known_face_locations=None, num_jitters=1, model="small"):
  155. """
  156. Given an image, return the 128-dimension face encoding for each face in the image.
  157. :param face_image: The image that contains one or more faces
  158. :param known_face_locations: Optional - the bounding boxes of each face if you already know them.
  159. :param num_jitters: How many times to re-sample the face when calculating encoding. Higher is more accurate, but slower (i.e. 100 is 100x slower)
  160. :param model: Optional - which model to use. "large" (default) or "small" which only returns 5 points but is faster.
  161. :return: A list of 128-dimensional face encodings (one for each face in the image)
  162. """
  163. raw_landmarks = _raw_face_landmarks(face_image, known_face_locations, model)
  164. return [np.array(face_encoder.compute_face_descriptor(face_image, raw_landmark_set, num_jitters)) for raw_landmark_set in raw_landmarks]
  165. def compare_faces(known_face_encodings, face_encoding_to_check, tolerance=0.6):
  166. """
  167. Compare a list of face encodings against a candidate encoding to see if they match.
  168. :param known_face_encodings: A list of known face encodings
  169. :param face_encoding_to_check: A single face encoding to compare against the list
  170. :param tolerance: How much distance between faces to consider it a match. Lower is more strict. 0.6 is typical best performance.
  171. :return: A list of True/False values indicating which known_face_encodings match the face encoding to check
  172. """
  173. return list(face_distance(known_face_encodings, face_encoding_to_check) <= tolerance)
Tip!

Press p or to see the previous file or, n or to see the next file

Comments

Loading...