| | import numpy as np |
| | import open3d as o3d |
| | from scipy.spatial.transform import Rotation |
| | from scipy.linalg import orthogonal_procrustes |
| |
|
| | from open3d.pipelines.registration import registration_ransac_based_on_correspondence |
| |
|
| |
|
| | def rigid_transform_3D(A, B): |
| | assert A.shape == B.shape, "Input arrays must have the same shape" |
| | assert A.shape[1] == 3, "Input arrays must be Nx3" |
| | |
| | N = A.shape[0] |
| |
|
| | |
| | centroid_A = np.mean(A, axis=0) |
| | centroid_B = np.mean(B, axis=0) |
| |
|
| | |
| | AA = A - centroid_A |
| | BB = B - centroid_B |
| |
|
| | |
| | H = np.dot(AA.T, BB) |
| |
|
| | |
| | U, S, Vt = np.linalg.svd(H) |
| |
|
| | |
| | R = np.dot(Vt.T, U.T) |
| |
|
| | |
| | if np.linalg.det(R) < 0: |
| | Vt[2, :] *= -1 |
| | R = np.dot(Vt.T, U.T) |
| | |
| | |
| | t = centroid_B - np.dot(R, centroid_A) |
| |
|
| | |
| | transform_matrix = np.eye(4) |
| | transform_matrix[:3, :3] = R |
| | transform_matrix[:3, 3] = t |
| |
|
| | return transform_matrix |
| |
|
| |
|
| | def compute_rigid_transform(points1, points2): |
| | """ |
| | 计算从points1到points2的刚体变换(包括尺度、旋转和平移)。 |
| | |
| | 参数: |
| | points1, points2: np.ndarray, 形状为(68, 3)的数组,分别为两组3D对应点。 |
| | |
| | 返回: |
| | scale: float, 尺度因子 |
| | R: np.ndarray, 3x3的旋转矩阵 |
| | t: np.ndarray, 3维的平移向量 |
| | """ |
| | |
| | mean1 = np.mean(points1, axis=0) |
| | centered_points1 = points1 - mean1 |
| | mean2 = np.mean(points2, axis=0) |
| | centered_points2 = points2 - mean2 |
| | |
| | |
| | R, _ = orthogonal_procrustes(centered_points1, centered_points2) |
| | t = mean2 - R @ mean1 |
| | |
| | |
| | scale = np.mean(np.linalg.norm(centered_points2, axis=1) / |
| | np.linalg.norm(centered_points1, axis=1)) |
| | |
| | return scale, R, t |
| |
|
| |
|
| | def compute_rigid_transform_new(points_A, points_B): |
| | |
| | center_A = np.mean(points_A, axis=0) |
| | center_B = np.mean(points_B, axis=0) |
| | points_A_centered = points_A - center_A |
| | points_B_centered = points_B - center_B |
| | |
| | |
| | cov_matrix = np.dot(points_A_centered.T, points_B_centered) |
| | |
| | |
| | U, S, Vt = np.linalg.svd(cov_matrix) |
| | |
| | |
| | rotation_matrix = np.dot(Vt.T, U.T) |
| | |
| | |
| | if np.linalg.det(rotation_matrix) < 0: |
| | Vt[2,:] *= -1 |
| | rotation_matrix = np.dot(Vt.T, U.T) |
| | |
| | |
| | scale = np.trace(np.dot(points_A_centered.T, points_B_centered)) / np.trace(np.dot(points_A_centered.T, points_A_centered)) |
| | |
| | |
| | translation_vector = center_B - scale * np.dot(rotation_matrix, center_A) |
| | |
| | return scale, rotation_matrix, translation_vector |
| |
|
| |
|
| |
|
| |
|
| | |
| | obj_A = '/home/gyalex/Desktop/our_face.obj' |
| | obj_B = '/home/gyalex/Desktop/Neutral.obj' |
| |
|
| | mesh_A = o3d.io.read_triangle_mesh(obj_A) |
| | mesh_B = o3d.io.read_triangle_mesh(obj_B) |
| |
|
| | vertices_A = np.asarray(mesh_A.vertices) |
| | vertices_B = np.asarray(mesh_B.vertices) |
| |
|
| | list_A = list() |
| | list_B = list() |
| | with open('/home/gyalex/Desktop/our_marker.txt', 'r') as f: |
| | lines_A = f.readlines() |
| | for line in lines_A: |
| | hh = line.strip().split() |
| | list_A.append(int(hh[0])) |
| |
|
| | with open('/home/gyalex/Desktop/ARKit_landmarks.txt', 'r') as f: |
| | lines_B = f.readlines() |
| | for line in lines_B: |
| | hh = line.strip().split() |
| | list_B.append(int(hh[0])) |
| |
|
| | A = vertices_A[list_A,:] |
| | B = vertices_B[list_B,:] |
| |
|
| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| |
|
| | |
| | |
| |
|
| | |
| |
|
| | pcd_source = o3d.utility.Vector3dVector(A) |
| | pcd_target = o3d.utility.Vector3dVector(B) |
| |
|
| | corres_source = list() |
| | for idx in range(68): corres_source.append(idx) |
| | corres_target = list() |
| | for idx in range(68): corres_target.append(idx) |
| |
|
| | |
| | corres_source_points = pcd_source |
| | corres_target_points = pcd_target |
| |
|
| | corres = o3d.utility.Vector2iVector([[src, tgt] for src, tgt in zip(corres_source, corres_target)]) |
| |
|
| | |
| | reg_result = registration_ransac_based_on_correspondence( |
| | pcd_source, |
| | pcd_target, |
| | corres, |
| | estimation_method=o3d.pipelines.registration.TransformationEstimationPointToPoint(), |
| | ransac_n=3, |
| | criteria=o3d.pipelines.registration.RANSACConvergenceCriteria(max_iteration=100000, epsilon=1e-6) |
| | ) |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | |
| | |
| |
|
| | a = 0 |