ICP算法的基本思路是通过不断迭代的方式来优化点云之间的配准。算法首先通过一些初步的对齐方式(例如粗略的初始变换或最近点匹配)来估计点云之间的变换关系,然后在此基础上进行迭代。
import open3d as o3d
import numpy as np
std_mesh_path = './4425de5e-2c7c-4958-aabd-a52f455b5f62.obj' # 模版路径
trans_mesh_path = './fc372157-6f0c-4f51-a4de-2751b332eb1d.obj' # 需要变换路径
show = True # 显示变换前后模型
output = False # 保存变换后模型
output_path = './output/fc372157-6f0c-4f51-a4de-2751b332eb1d.obj'
step = 40 # 迭代步数 (测试值40)
number_of_points = 2000 # 在模型中sample的点数量 (测试值2000)
if __name__ == '__main__':
mesh1 = o3d.io.read_triangle_mesh(std_mesh_path) # 导入模型
mesh2 = o3d.io.read_triangle_mesh(trans_mesh_path) # 导入模型
mesh1.compute_vertex_normals()
mesh2.compute_vertex_normals()
# 均匀采样5000个点转点云 mesh转换成pcd
pcd1 = mesh1.sample_points_uniformly(number_of_points=number_of_points)
pcd2 = mesh2.sample_points_uniformly(number_of_points=number_of_points)
# pcd转换成np数据
arr1 = np.asarray(pcd1.points)
arr2 = np.asarray(pcd2.points)
if show:
pcd1.paint_uniform_color([1, 0, 0]) # 标准模型显示为红色
pcd2.paint_uniform_color([0, 1, 0]) # 调整模型指定显示为绿
o3d.visualization.draw_geometries([pcd1, pcd2])
# 逐步迭代模型
for step_i in range(step):
print("step", step_i)
centroid1 = arr1.sum(axis=0) / number_of_points
centroid2 = arr2.sum(axis=0) / number_of_points
if(step_i < 20):
pcd2.translate(centroid2 + (centroid1 - centroid2), relative=False)
arr2 = np.asarray(pcd2.points)
if output:
mesh2.translate(centroid2 + (centroid1 - centroid2), relative=False)
centroid1 = arr1.sum(axis=0) / number_of_points
centroid2 = arr2.sum(axis=0) / number_of_points
# 得到去质心坐标
shoes1_decentroid = arr1 - centroid1
shoes2_decentroid = arr2 - centroid2
W = np.zeros(shape=(3, 3))
# 将目标模型进行排序
for i in range(number_of_points):
# 计算出 模型1 中每个点在 模型2 最近的点
minarg = np.argmin(np.power(np.linalg.norm(shoes2_decentroid-shoes1_decentroid[i], axis=1), 2)) # 得到最近点下标
W = W + (np.outer(shoes1_decentroid[i], shoes2_decentroid[minarg].T))
# 对 W 进行SVD分解
u, sigma, vt = np.linalg.svd(W, full_matrices=0, compute_uv=1)
rotate_matrix = np.dot(u, vt) # 旋转矩阵
transpose_vecter = centroid1 - (np.dot(rotate_matrix, centroid2)) # 平移矩阵
pcd2.rotate(rotate_matrix)
pcd2.translate(transpose_vecter, relative=False)
if output:
mesh2.rotate(rotate_matrix)
mesh2.translate(transpose_vecter, relative=False)
if output:
o3d.io.write_triangle_mesh(output_path, mesh2)
if show:
o3d.visualization.draw_geometries([pcd1, pcd2])