不同角度拍摄的点云拼成一个点云的实现方法

一、目的

从不同的角度拍摄一个物体,得到多张点云图像,把他们放在一个坐标系里,岂不是就能还原这个物体的完整面貌

参考笔记:【三维重建】点云配准拼接学习笔记_点云局部拼接-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版本我也没有改回去了)

最后的效果图如下:

单角度
多角度
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值