一、目的
从不同的角度拍摄一个物体,得到多张点云图像,把他们放在一个坐标系里,岂不是就能还原这个物体的完整面貌
参考笔记:【三维重建】点云配准拼接学习笔记_点云局部拼接-CSDN博客
这个笔记中说:
“寻找不同视角下不同点云之间的映射关系,利用一定的算法将同一目标场景的不同点云转换到同一个坐标系下。”是的,这就是我的目的
“问题的关键是如何让得到坐标变换的参数R(旋转矩阵)和T(平移向量),使得两视角下测得的三维数据经坐标变换后的距离最小” 我的数据的已知信息:相机每次绕z轴旋转1°,不平移,所以我的坐标变换矩阵是已知的
所以我不需要配准,直接变换+集中到一个坐标系即可
二、过程
1.求R(旋转矩阵)/T(平移矩阵)
从负5度到正5度[-5,5]每隔一个角度拍两张,一共11个角度。以0度为原始坐标系,我一共需要求10对R&T(分别对应旋转角度为:-5,-4,-3,-2,-1&1,2,3,4,5,不平移)
2.对点云进行刚性变换
就是用其次坐标表示每个点的位置,和刚性变换矩阵进行矩阵乘法计算后得到A坐标系在B坐标系中的点的xyz坐标,然后再从齐次坐标变回xyz形式
3. 把统一后的多个点云放在一个坐标系中
直接合并就行(把所有文件放在一起)
代码如下:
import numpy as np
import os
def load_point_cloud(file_path):
"""加载点云数据"""
points = np.loadtxt(file_path).T
return points
def rotation_matrix_z(theta_deg):
"""生成绕 Z 轴旋转的旋转矩阵"""
theta_rad = np.radians(theta_deg)
return np.array([
[np.cos(theta_rad), -np.sin(theta_rad), 0],
[np.sin(theta_rad), np.cos(theta_rad), 0],
[0, 0, 1]
])
def homogeneous_transformation_matrix(rotation):
"""将旋转矩阵组合成齐次变换矩阵"""
H = np.eye(4)
H[:3, :3] = rotation
return H
def apply_transformation(points, transformation_matrix):
"""应用齐次变换矩阵"""
# 添加一行全为1的行,以便进行齐次坐标变换
hom_points = np.vstack((points, np.ones((1, points.shape[1]))))
transformed_hom_points = np.dot(transformation_matrix, hom_points)
# 归一化齐次坐标
transformed_points = transformed_hom_points[:3, :] / transformed_hom_points[3, :]
return transformed_points
def preprocess_and_merge_point_clouds(base_dir):
"""预处理并合并点云数据"""
# 角度列表
angles_deg = [-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5]
# 文件名列表
filenames = [os.path.join(base_dir, f"point_cloud_{i}.xyz") for i in range(1, 23)]
# 初始化合并后的点云数组
merged_points = np.empty((3, 0))
for i, filename in enumerate(filenames):
# 加载点云数据
points = load_point_cloud(filename)
# 计算旋转矩阵和平移矩阵
angle = angles_deg[i // 2] if i % 2 == 0 else angles_deg[i // 2]
R_z = rotation_matrix_z(angle)
H = homogeneous_transformation_matrix(R_z)
# 应用变换
transformed_points = apply_transformation(points, H)
# 合并点云
merged_points = np.hstack((merged_points, transformed_points))
return merged_points
# 使用示例
base_dir = r'G:\pointclouds\train'
merged_cloud = preprocess_and_merge_point_clouds(base_dir)
# 保存合并后的点云数据
output_file = os.path.join(base_dir, 'merged_point_cloud.xyz')
np.savetxt(output_file, merged_cloud.T)
print(f"Merged point cloud saved to: {output_file}")
三、可视化
如图所示,看起来效果还行,但是目前我没有想到验证点云准确性的方法(比如噪声大不大,是否11个角度按我理想的状态合并了,这些都不知道)
代码如下:
import numpy as np
import open3d as o3d
def load_point_cloud(file_path):
"""加载点云数据"""
points = np.loadtxt(file_path).T
return points
def visualize_point_cloud(file_path):
"""加载并可视化点云数据"""
# 加载点云数据
points = load_point_cloud(file_path)
# 创建 PointCloud 对象
pcd = o3d.geometry.PointCloud()
pcd.points = o3d.utility.Vector3dVector(points.T)
# 可视化点云
vis = o3d.visualization.Visualizer()
vis.create_window(window_name="Point Cloud Visualization")
vis.add_geometry(pcd)
# 设置初始视角
ctr = vis.get_view_control()
ctr.set_front([0, 0, -1]) # 设置摄像机前方方向
ctr.set_lookat([0, 0, 0]) # 设置摄像机注视点
ctr.set_up([0, -1, 0]) # 设置摄像机向上方向
# 保持窗口打开,允许用户改变视角
while True:
vis.poll_events()
vis.update_renderer()
if not vis.get_window().should_close():
continue
break
vis.destroy_window()
# 使用示例
file_path = r'G:\train\merged_point_cloud.xyz'
visualize_point_cloud(file_path)
刚准备插入结果图就结束了,结果一运行,弹出窗口不到1s就会闪退;明明刚才运行的好好的,不知道什么情况orz
更新:已解决
方法:
1.我修改了numpy的版本
pip install -U numpy==1.24.3
2.我改了代码,不使用之前的“while True......break"而是直接用vis.run()代替
import numpy as np
import open3d as o3d
def load_point_cloud(file_path):
"""加载点云数据"""
points = np.loadtxt(file_path).T
return points
def visualize_point_cloud(file_path):
"""加载并可视化点云数据"""
# 加载点云数据
points = load_point_cloud(file_path)
# 创建 PointCloud 对象
pcd = o3d.geometry.PointCloud()
pcd.points = o3d.utility.Vector3dVector(points.T)
# 初始化可视化器
vis = o3d.visualization.Visualizer()
vis.create_window(window_name="Point Cloud Visualization")
vis.add_geometry(pcd)
# 设置初始视角
ctr = vis.get_view_control()
ctr.set_front([0, 0, -1]) # 设置摄像机前方方向
ctr.set_lookat([0, 0, 0]) # 设置摄像机注视点
ctr.set_up([0, -1, 0]) # 设置摄像机向上方向
# 启动可视化
vis.run() # 这将开始事件循环并处理窗口关闭逻辑
vis.destroy_window()
# 使用示例
file_path = r'G:\YJY\test\test1\deep-rs-Master\base_dir\dataset_root\PUNnet\pointclouds\train\merged_point_cloud_x.xyz'
visualize_point_cloud(file_path)
我不知道是哪个修改起到了作用(应该是第二个,不过numpy版本我也没有改回去了)
最后的效果图如下: