Predict the landmarks for each face present in the image. This function predicts a set of 68 2D or 3D images, one for each image present. If detect_faces is None the method will also run a face detector. Arguments: image_or_path {string or numpy.array or
(self, image_or_path, detected_faces=None, return_bboxes=False,
return_landmark_score=False)
| 182 | |
| 183 | @torch.no_grad() |
| 184 | def get_landmarks_from_image(self, image_or_path, detected_faces=None, return_bboxes=False, |
| 185 | return_landmark_score=False): |
| 186 | """Predict the landmarks for each face present in the image. |
| 187 | |
| 188 | This function predicts a set of 68 2D or 3D images, one for each image present. |
| 189 | If detect_faces is None the method will also run a face detector. |
| 190 | |
| 191 | Arguments: |
| 192 | image_or_path {string or numpy.array or torch.tensor} -- The input image or path to it. |
| 193 | |
| 194 | Keyword Arguments: |
| 195 | detected_faces {list of numpy.array} -- list of bounding boxes, one for each face found |
| 196 | in the image (default: {None}) |
| 197 | return_bboxes {boolean} -- If True, return the face bounding boxes in addition to the keypoints. |
| 198 | return_landmark_score {boolean} -- If True, return the keypoint scores along with the keypoints. |
| 199 | |
| 200 | Return: |
| 201 | result: |
| 202 | 1. if both return_bboxes and return_landmark_score are False, result will be: |
| 203 | landmark |
| 204 | 2. Otherwise, result will be one of the following, depending on the actual value of return_* arguments. |
| 205 | (landmark, landmark_score, detected_face) |
| 206 | (landmark, None, detected_face) |
| 207 | (landmark, landmark_score, None ) |
| 208 | """ |
| 209 | image = get_image(image_or_path) |
| 210 | |
| 211 | if detected_faces is None: |
| 212 | detected_faces = self.face_detector.detect_from_image(image.copy()) |
| 213 | |
| 214 | if len(detected_faces) == 0: |
| 215 | warnings.warn("No faces were detected.") |
| 216 | if return_bboxes or return_landmark_score: |
| 217 | return None, None, None |
| 218 | else: |
| 219 | return None |
| 220 | |
| 221 | # Precompute centers, scales, and crops for all faces |
| 222 | centers = [] |
| 223 | scales = [] |
| 224 | crops = [] |
| 225 | for d in detected_faces: |
| 226 | center = np.array( |
| 227 | [d[2] - (d[2] - d[0]) / 2.0, d[3] - (d[3] - d[1]) / 2.0]) |
| 228 | center[1] = center[1] - (d[3] - d[1]) * CENTER_Y_OFFSET |
| 229 | scale = (d[2] - d[0] + d[3] - d[1]) / self.face_detector.reference_scale |
| 230 | centers.append(center) |
| 231 | scales.append(scale) |
| 232 | crops.append(crop(image, center, scale).transpose((2, 0, 1)).astype(np.float32) / 255.0) |
| 233 | |
| 234 | # Batch FAN forward pass (chunked by max_batch_size) |
| 235 | all_crops = torch.from_numpy(np.stack(crops)) |
| 236 | out_chunks = [] |
| 237 | for start in range(0, len(crops), self.max_batch_size): |
| 238 | inp_chunk = all_crops[start:start + self.max_batch_size].to(self.device, dtype=self.dtype) |
| 239 | out_chunk = self.face_alignment_net(inp_chunk) |
| 240 | if isinstance(out_chunk, list): |
| 241 | out_chunk = out_chunk[-1] |
no test coverage detected