Spaces:
Veein
/
Runtime error

File size: 6,100 Bytes
17cd746
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
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]  # Number of points

    # Compute centroids of A and B
    centroid_A = np.mean(A, axis=0)
    centroid_B = np.mean(B, axis=0)

    # Center the points around the centroids
    AA = A - centroid_A
    BB = B - centroid_B

    # H = AA^T * BB
    H = np.dot(AA.T, BB)

    # Singular Value Decomposition
    U, S, Vt = np.linalg.svd(H)

    # Compute rotation
    R = np.dot(Vt.T, U.T)

    # Ensure a proper rotation (det(R) should be +1)
    if np.linalg.det(R) < 0:
        Vt[2, :] *= -1
        R = np.dot(Vt.T, U.T)
    
    # Compute translation
    t = centroid_B - np.dot(R, centroid_A)

    # Construct the transform matrix (4x4)
    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
    
    # 使用orthogonal_procrustes计算旋转和平移
    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)
    
    # SVD分解
    U, S, Vt = np.linalg.svd(cov_matrix)
    
    # 确保旋转矩阵为正交且右手系,这里我们取Vt的转置作为旋转矩阵
    rotation_matrix = np.dot(Vt.T, U.T)
    
    # 检查行列式是否为-1(表示反射,不满足旋转矩阵要求),如果是,则调整一个列的符号
    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,:]  # 第一组3D点
B = vertices_B[list_B,:]  # 第二组3D点

# scale, R, t = compute_rigid_transform(A, B)

# # 定义尺度变换矩阵
# scale_matrix = np.eye(4)
# scale_matrix[0, 0] = scale  # x轴方向放大2倍
# scale_matrix[1, 1] = scale  # y轴方向放大2倍
# scale_matrix[2, 2] = scale  # z轴方向放大2倍

# transform_matrix = np.eye(4)
# transform_matrix[:3, :3] = scale
# transform_matrix[:3, 3] = R*t

# mesh_A.transform(transform_matrix)
# # mesh_A.transform(scale_matrix)

# o3d.io.write_triangle_mesh('/home/gyalex/Desktop/our_face_new.obj', mesh_A)

pcd_source = o3d.utility.Vector3dVector(A)  # 示例源点云数据
pcd_target = o3d.utility.Vector3dVector(B)  # 示例目标点云数据 + 1偏移,仅作示例

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)])

# 应用RANSAC进行基于对应点的配准
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)
)

# # 使用RANSAC进行配准
# convergence_criteria = o3d.pipelines.registration.RANSACConvergenceCriteria(max_iteration=50000, max_validation=500)
# ransac_result = o3d.pipelines.registration.registration_ransac_based_on_correspondence(
#     pcd_source,
#     pcd_target,
#     corres,
#     o3d.pipelines.registration.TransformationEstimationPointToPoint(),
#     3,  # RANSAC阈值,根据实际情况调整
#     convergence_criteria,
#     [o3d.pipelines.registration.CorrespondenceCheckerBasedOnEdgeLength(0.9),
#      o3d.pipelines.registration.CorrespondenceCheckerBasedOnDistance(0.05)],
#     o3d.pipelines.registration.RANSACLoss())

# 应用变换到源mesh
# mesh_source_aligned = mesh_source.transform(reg_result.transformation)

a = 0