This script computes the reconstruction error between an input mesh and a ground truth mesh. Args: groundtruth_vertices (np.ndarray[N,3]): Ground truth vertices. grundtruth_landmark_points (np.ndarray[7,3]): Ground truth annotations. predicted_mesh_vertices (np.ndarra
(groundtruth_vertices,
grundtruth_landmark_points,
predicted_mesh_vertices, predicted_mesh_faces,
predicted_mesh_landmark_points)
| 222 | |
| 223 | |
| 224 | def fg_vertices_to_mesh_distance(groundtruth_vertices, |
| 225 | grundtruth_landmark_points, |
| 226 | predicted_mesh_vertices, predicted_mesh_faces, |
| 227 | predicted_mesh_landmark_points): |
| 228 | """This script computes the reconstruction error between an input mesh and |
| 229 | a ground truth mesh. |
| 230 | Args: |
| 231 | groundtruth_vertices (np.ndarray[N,3]): Ground truth vertices. |
| 232 | grundtruth_landmark_points (np.ndarray[7,3]): Ground truth annotations. |
| 233 | predicted_mesh_vertices (np.ndarray[M,3]): Predicted vertices. |
| 234 | predicted_mesh_faces (np.ndarray[K,3]): Vertex indices |
| 235 | composing the predicted mesh. |
| 236 | predicted_mesh_landmark_points (np.ndarray[7,3]): Predicted points. |
| 237 | |
| 238 | Return: |
| 239 | distance: Mean point to mesh distance. |
| 240 | |
| 241 | The grundtruth_landmark_points and predicted_mesh_landmark_points have to |
| 242 | contain points in the following order: |
| 243 | (1) right eye outer corner, (2) right eye inner corner, |
| 244 | (3) left eye inner corner, (4) left eye outer corner, |
| 245 | (5) nose bottom, (6) right mouth corner, (7) left mouth corner. |
| 246 | """ |
| 247 | |
| 248 | # Do procrustes based on the 7 points: |
| 249 | _, tform = compute_similarity_transform(predicted_mesh_landmark_points, |
| 250 | grundtruth_landmark_points, |
| 251 | return_tform=True) |
| 252 | # Use tform to transform all vertices. |
| 253 | predicted_mesh_vertices_aligned = ( |
| 254 | tform['scale'] * tform['rotation'].dot(predicted_mesh_vertices.T) + |
| 255 | tform['translation']).T |
| 256 | |
| 257 | # Compute the mask: A circular area around the center of the face. |
| 258 | nose_bottom = np.array(grundtruth_landmark_points[4]) |
| 259 | nose_bridge = (np.array(grundtruth_landmark_points[1]) + np.array( |
| 260 | grundtruth_landmark_points[2])) / 2 # between the inner eye corners |
| 261 | face_centre = nose_bottom + 0.3 * (nose_bridge - nose_bottom) |
| 262 | # Compute the radius for the face mask: |
| 263 | outer_eye_dist = np.linalg.norm( |
| 264 | np.array(grundtruth_landmark_points[0]) - |
| 265 | np.array(grundtruth_landmark_points[3])) |
| 266 | nose_dist = np.linalg.norm(nose_bridge - nose_bottom) |
| 267 | mask_radius = 1.2 * (outer_eye_dist + nose_dist) / 2 |
| 268 | |
| 269 | # Find all the vertex indices in mask area. |
| 270 | vertex_indices_mask = [] |
| 271 | # vertex indices in the source mesh (the ground truth scan) |
| 272 | points_on_groundtruth_scan_to_measure_from = [] |
| 273 | for vertex_idx, vertex in enumerate(groundtruth_vertices): |
| 274 | dist = np.linalg.norm( |
| 275 | vertex - face_centre |
| 276 | ) # We use Euclidean distance for the mask area for now. |
| 277 | if dist <= mask_radius: |
| 278 | vertex_indices_mask.append(vertex_idx) |
| 279 | points_on_groundtruth_scan_to_measure_from.append(vertex) |
| 280 | assert len(vertex_indices_mask) == len( |
| 281 | points_on_groundtruth_scan_to_measure_from) |
no test coverage detected