(
vertices, triangles=None, scales=[1.0], batch=None, normals=None, reg=1e-10
)
| 413 | |
| 414 | |
| 415 | def curvatures( |
| 416 | vertices, triangles=None, scales=[1.0], batch=None, normals=None, reg=1e-10 |
| 417 | ): |
| 418 | # Number of points, number of scales: |
| 419 | N, S = vertices.shape[0], len(scales) |
| 420 | #ranges = diagonal_ranges(batch) |
| 421 | |
| 422 | # Compute the normals at different scales + vertice areas: |
| 423 | normals_s, _ = mesh_normals_areas( |
| 424 | vertices, triangles=triangles, normals=normals, scale=scales, batch=batch |
| 425 | ) # (N, S, 3), (N,) |
| 426 | |
| 427 | # Local tangent bases: |
| 428 | uv_s = tangent_vectors(normals_s) # (N, S, 2, 3) |
| 429 | |
| 430 | features = [] |
| 431 | |
| 432 | for s, scale in enumerate(scales): |
| 433 | # Extract the relevant descriptors at the current scale: |
| 434 | normals = normals_s[:, s, :].contiguous() # (N, 3) |
| 435 | uv = uv_s[:, s, :, :].contiguous() # (N, 2, 3) |
| 436 | |
| 437 | # Encode as symbolic tensors: |
| 438 | # Points: |
| 439 | x_i = LazyTensor(vertices.view(N, 1, 3)) |
| 440 | x_j = LazyTensor(vertices.view(1, N, 3)) |
| 441 | # Normals: |
| 442 | n_i = LazyTensor(normals.view(N, 1, 3)) |
| 443 | n_j = LazyTensor(normals.view(1, N, 3)) |
| 444 | # Tangent bases: |
| 445 | uv_i = LazyTensor(uv.view(N, 1, 6)) |
| 446 | |
| 447 | # Pseudo-geodesic squared distance: |
| 448 | d2_ij = ((x_j - x_i) ** 2).sum(-1) * ((2 - (n_i | n_j)) ** 2) # (N, N, 1) |
| 449 | # Gaussian window: |
| 450 | window_ij = (-d2_ij / (2 * (scale ** 2))).exp() # (N, N, 1) |
| 451 | |
| 452 | # Project on the tangent plane: |
| 453 | P_ij = uv_i.matvecmult(x_j - x_i) # (N, N, 2) |
| 454 | Q_ij = uv_i.matvecmult(n_j - n_i) # (N, N, 2) |
| 455 | # Concatenate: |
| 456 | PQ_ij = P_ij.concat(Q_ij) # (N, N, 2+2) |
| 457 | |
| 458 | # Covariances, with a scale-dependent weight: |
| 459 | PPt_PQt_ij = P_ij.tensorprod(PQ_ij) # (N, N, 2*(2+2)) |
| 460 | PPt_PQt_ij = window_ij * PPt_PQt_ij # (N, N, 2*(2+2)) |
| 461 | |
| 462 | # Reduction - with batch support: |
| 463 | #PPt_PQt_ij.ranges = ranges |
| 464 | PPt_PQt = PPt_PQt_ij.sum(1) # (N, 2*(2+2)) |
| 465 | |
| 466 | # Reshape to get the two covariance matrices: |
| 467 | PPt_PQt = PPt_PQt.view(N, 2, 2, 2) |
| 468 | PPt, PQt = PPt_PQt[:, :, 0, :], PPt_PQt[:, :, 1, :] # (N, 2, 2), (N, 2, 2) |
| 469 | |
| 470 | # Add a small ridge regression: |
| 471 | PQt[:, 0, 0] += reg |
| 472 | PQt[:, 1, 1] += reg |
no test coverage detected