Spaces:
Veein
/
Runtime error

yuandong513
feat: init
17cd746
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