目录
前期试读,后续会将博客加入下列链接的专栏,欢迎订阅
Open3D点云算法与点云深度学习案例汇总(长期更新)-CSDN博客
一、概述
将点云投影到圆柱上需要将每个点投影到圆柱的表面。我们需要定义圆柱的轴线、半径,并计算每个点到轴线的投影位置。然后,根据这些投影位置计算出投影到圆柱表面上的点。
1.1原理介绍
圆柱可以用一个轴线(由轴线方向向量和轴线上任意一点定义)和半径来定义。将点云投影到圆柱上的步骤如下:
- 计算每个点到圆柱轴线的投影位置。
- 将这些投影位置投影到圆柱表面。
1.2实现步骤
- 生成或读取点云数据:使用 Open3D 生成或读取点云数据。
- 定义圆柱:给定圆柱的轴线(方向向量和轴线上任意一点)和半径。
- 计算投影向量:计算每个点在圆柱轴线上的投影位置,然后将这些位置投影到圆柱表面。
- 替换点云数据:用投影位置替换原始点云数据。
- 可视化结果:使用 Open3D 可视化投影后的点云数据。
二、代码实现
2.1关键函数
计算投影向量:
- 在 project_to_cylinder 函数中,首先计算每个点到圆柱轴线的投影位置。具体来说,先计算每个点到轴线起点的向量,然后计算这些向量在轴线方向上的投影,得到投影点在轴线上的位置。
- 计算每个点到轴线的径向向量,并将其归一化到圆柱半径,得到投影到圆柱表面上的点。
def project_to_cylinder(pcd, cylinder_axis_point, cylinder_axis_direction, cylinder_radius):
"""
将点云投影到给定的圆柱上。
参数:
pcd (open3d.geometry.PointCloud): 输入点云。
cylinder_axis_point (np.ndarray): 圆柱轴线上任意一点 (x, y, z)。
cylinder_axis_direction (np.ndarray): 圆柱轴线的方向向量 (dx, dy, dz)。
cylinder_radius (float): 圆柱的半径。
返回:
open3d.geometry.PointCloud: 投影后的点云。
"""
points = np.asarray(pcd.points)
cylinder_axis_point = np.asarray(cylinder_axis_point)
cylinder_axis_direction = np.asarray(cylinder_axis_direction)
cylinder_axis_direction = cylinder_axis_direction / np.linalg.norm(cylinder_axis_direction) # 归一化方向向量
# 计算每个点到圆柱轴线的投影
vectors_to_axis = points - cylinder_axis_point
projections_onto_axis = np.dot(vectors_to_axis, cylinder_axis_direction)[:, None] * cylinder_axis_direction
projected_points_on_axis = projections_onto_axis + cylinder_axis_point
# 计算每个点到轴线的径向向量,并归一化到圆柱半径
radial_vectors = points - projected_points_on_axis
radial_vectors_normalized = radial_vectors / np.linalg.norm(radial_vectors, axis=1, keepdims=True) * cylinder_radius
# 计算投影到圆柱表面上的点
projected_points = projected_points_on_axis + radial_vectors_normalized
# 创建新的点云
projected_pcd = o3d.geometry.PointCloud()
projected_pcd.points = o3d.utility.Vector3dVector(projected_points)
return projected_pcd
2.2完整代码
import open3d as o3d
import numpy as np
def generate_random_point_cloud(num_points=1000):
"""
生成随机点云数据。
参数:
num_points (int): 点的数量。
返回:
open3d.geometry.PointCloud: 生成的点云。
"""
points = np.random.uniform(-10, 10, (num_points, 3))
pcd = o3d.geometry.PointCloud()
pcd.points = o3d.utility.Vector3dVector(points)
return pcd
def project_to_cylinder(pcd, cylinder_axis_point, cylinder_axis_direction, cylinder_radius):
"""
将点云投影到给定的圆柱上。
参数:
pcd (open3d.geometry.PointCloud): 输入点云。
cylinder_axis_point (np.ndarray): 圆柱轴线上任意一点 (x, y, z)。
cylinder_axis_direction (np.ndarray): 圆柱轴线的方向向量 (dx, dy, dz)。
cylinder_radius (float): 圆柱的半径。
返回:
open3d.geometry.PointCloud: 投影后的点云。
"""
points = np.asarray(pcd.points)
cylinder_axis_point = np.asarray(cylinder_axis_point)
cylinder_axis_direction = np.asarray(cylinder_axis_direction)
cylinder_axis_direction = cylinder_axis_direction / np.linalg.norm(cylinder_axis_direction) # 归一化方向向量
# 计算每个点到圆柱轴线的投影
vectors_to_axis = points - cylinder_axis_point
projections_onto_axis = np.dot(vectors_to_axis, cylinder_axis_direction)[:, None] * cylinder_axis_direction
projected_points_on_axis = projections_onto_axis + cylinder_axis_point
# 计算每个点到轴线的径向向量,并归一化到圆柱半径
radial_vectors = points - projected_points_on_axis
radial_vectors_normalized = radial_vectors / np.linalg.norm(radial_vectors, axis=1, keepdims=True) * cylinder_radius
# 计算投影到圆柱表面上的点
projected_points = projected_points_on_axis + radial_vectors_normalized
# 创建新的点云
projected_pcd = o3d.geometry.PointCloud()
projected_pcd.points = o3d.utility.Vector3dVector(projected_points)
return projected_pcd
# 生成随机点云
num_points = 1000
pcd = generate_random_point_cloud(num_points)
# 定义圆柱 (例如,轴线方向向量为 (0, 0, 1),轴线上一点为 (0, 0, 0),半径为 5)
#圆柱由一个轴线方向向量、轴线上任意一点和半径定义。方向向量需要归一化,即方向向量的长度为1。
cylinder_axis_point = np.array([0.0, 0.0, 0.0])
cylinder_axis_direction = np.array([0.0, 0.0, 1.0])
cylinder_radius = 5.0
# 将点云投影到圆柱上
projected_pcd = project_to_cylinder(pcd, cylinder_axis_point, cylinder_axis_direction, cylinder_radius)
# 可视化原始点云和投影后的点云
o3d.visualization.draw_geometries([pcd], window_name="Original Point Cloud", width=800, height=600, left=50, top=50)
o3d.visualization.draw_geometries([projected_pcd], window_name="Projected Point Cloud on Cylinder", width=800, height=600, left=850, top=50)
# 保存投影后的点云
o3d.io.write_point_cloud("projected_cylinder.pcd", projected_pcd)