Computes a similarity transform (sR, t) that takes a set of 3D points source_points (N x 3) closest to a set of 3D points target_points, where R is an 3x3 rotation matrix, t 3x1 translation, s scale. And return the transformed 3D points source_points_hat (N x 3). i.e. solves the ort
(source_points,
target_points,
return_tform=False)
| 7 | |
| 8 | |
| 9 | def compute_similarity_transform(source_points, |
| 10 | target_points, |
| 11 | return_tform=False): |
| 12 | """Computes a similarity transform (sR, t) that takes a set of 3D points |
| 13 | source_points (N x 3) closest to a set of 3D points target_points, where R |
| 14 | is an 3x3 rotation matrix, t 3x1 translation, s scale. |
| 15 | |
| 16 | And return the |
| 17 | transformed 3D points source_points_hat (N x 3). i.e. solves the orthogonal |
| 18 | Procrutes problem. |
| 19 | Notes: |
| 20 | Points number: N |
| 21 | Args: |
| 22 | source_points (np.ndarray([N, 3])): Source point set. |
| 23 | target_points (np.ndarray([N, 3])): Target point set. |
| 24 | return_tform (bool) : Whether return transform |
| 25 | Returns: |
| 26 | source_points_hat (np.ndarray([N, 3])): Transformed source point set. |
| 27 | transform (dict): Returns if return_tform is True. |
| 28 | Returns rotation: r, 'scale': s, 'translation':t. |
| 29 | """ |
| 30 | |
| 31 | assert target_points.shape[0] == source_points.shape[0] |
| 32 | assert target_points.shape[1] == 3 and source_points.shape[1] == 3 |
| 33 | |
| 34 | source_points = source_points.T |
| 35 | target_points = target_points.T |
| 36 | |
| 37 | # 1. Remove mean. |
| 38 | mu1 = source_points.mean(axis=1, keepdims=True) |
| 39 | mu2 = target_points.mean(axis=1, keepdims=True) |
| 40 | X1 = source_points - mu1 |
| 41 | X2 = target_points - mu2 |
| 42 | |
| 43 | # 2. Compute variance of X1 used for scale. |
| 44 | var1 = np.sum(X1**2) |
| 45 | |
| 46 | # 3. The outer product of X1 and X2. |
| 47 | K = X1.dot(X2.T) |
| 48 | |
| 49 | # 4. Solution that Maximizes trace(R'K) is R=U*V', where U, V are |
| 50 | # singular vectors of K. |
| 51 | U, _, Vh = np.linalg.svd(K) |
| 52 | V = Vh.T |
| 53 | # Construct Z that fixes the orientation of R to get det(R)=1. |
| 54 | Z = np.eye(U.shape[0]) |
| 55 | Z[-1, -1] *= np.sign(np.linalg.det(U.dot(V.T))) |
| 56 | # Construct R. |
| 57 | R = V.dot(Z.dot(U.T)) |
| 58 | |
| 59 | # 5. Recover scale. |
| 60 | scale = np.trace(R.dot(K)) / var1 |
| 61 | |
| 62 | # 6. Recover translation. |
| 63 | t = mu2 - scale * (R.dot(mu1)) |
| 64 | |
| 65 | # 7. Transform the source points: |
| 66 | source_points_hat = scale * R.dot(source_points) + t |
no outgoing calls
no test coverage detected