3、点云数据生成(一):使用Open3D生成基本几何体点云(立方体、球体、圆柱体),理解点云坐标与颜色

各位好,欢迎来到《点云生成与滤波处理实战手册》的第三讲。

今天咱们聊聊一个基础但特别重要的话题——怎么用Open3D生成基本几何体的点云。说白了,就是让计算机“凭空”变出立方体、球体、圆柱体的点云数据。

你可能会问:“为什么要自己生成?直接扫描不就行了?”嗯,我在项目里遇到过这种情况:算法调试阶段,你手头没有激光雷达,或者扫描数据太脏、有遮挡。这时候,自己生成干净的点云数据,就是最好的调试工具。它能帮你快速验证算法逻辑,排除数据噪声的干扰。

核心要点:Open3D 提供了 create_mesh_boxcreate_mesh_spherecreate_mesh_cylinder 等函数,但注意——它们生成的是三角网格,不是点云。我们需要从网格中采样点,才能得到点云。

3.1 从网格到点云:一个关键转换

我个人习惯把Open3D的几何体生成流程拆成三步:

  1. 创建网格对象(Mesh)
  2. 从网格采样点(Sample Points)
  3. 赋予颜色(Assign Colors)

为什么不能直接生成点云?因为Open3D的设计哲学是:网格是“连续”的几何表示,点云是“离散”的采样结果。你想想看,一个球体表面有无穷多个点,我们只能取有限个。所以必须通过采样。

来看一个最简单的例子——生成一个立方体点云:

import open3d as o3d
import numpy as np

# 1. 创建立方体网格(边长2,中心在原点)
mesh_box = o3d.geometry.TriangleMesh.create_box(width=2.0, height=2.0, depth=2.0)
mesh_box.translate([-1, -1, -1])  # 将中心移到原点

# 2. 采样点云(均匀采样500个点)
pcd = mesh_box.sample_points_uniformly(number_of_points=500)

# 3. 赋予颜色(这里用蓝色)
pcd.paint_uniform_color([0.1, 0.2, 0.8])

# 可视化
o3d.visualization.draw_geometries([pcd], window_name="立方体点云")

这里有个坑,我曾经踩过:create_box 默认的立方体是从 [0,0,0][2,2,2],中心在 [1,1,1]。如果你不平移,后面做旋转或对称操作时,坐标会乱套。所以我习惯先平移,让几何体中心对齐原点。

3.2 球体与圆柱体:参数控制与采样密度

球体和圆柱体稍微复杂一点,因为它们有半径分辨率的概念。

先看球体:

# 生成球体网格(半径1.0,分辨率20)
mesh_sphere = o3d.geometry.TriangleMesh.create_sphere(radius=1.0, resolution=20)
pcd_sphere = mesh_sphere.sample_points_uniformly(number_of_points=1000)
pcd_sphere.paint_uniform_color([0.8, 0.2, 0.1])  # 红色

resolution 参数控制网格的细分程度。数值越大,网格越精细,采样出的点云越接近理想球体。但注意,resolution=20 已经会产生约 400 个三角面,采样 1000 个点绰绰有余。

圆柱体呢?它需要半径和高度:

# 生成圆柱体网格(半径0.5,高度2.0)
mesh_cylinder = o3d.geometry.TriangleMesh.create_cylinder(radius=0.5, height=2.0, resolution=20)
pcd_cylinder = mesh_cylinder.sample_points_uniformly(number_of_points=800)
pcd_cylinder.paint_uniform_color([0.2, 0.8, 0.2])  # 绿色

小技巧:采样点数不是越多越好。我一般遵循“每平方厘米 50-100 个点”的经验法则。比如一个半径1的球体,表面积约12.56,取 600-1200 个点就够用了。点太多,可视化会卡;点太少,形状特征不明显。

3.3 理解点云坐标与颜色

生成点云后,我们得理解它内部的数据结构。说白了,点云就是一个 N×3 的坐标矩阵,加上一个 N×3 的颜色矩阵。

来看一下如何获取这些数据:

# 获取点坐标(N行3列)
points = np.asarray(pcd.points)
print("点云坐标形状:", points.shape)  # 例如 (500, 3)
print("前5个点坐标:\n", points[:5])

# 获取颜色(N行3列,值范围0-1)
colors = np.asarray(pcd.colors)
print("颜色形状:", colors.shape)      # 例如 (500, 3)
print("前5个点颜色:\n", colors[:5])

坐标的单位是什么?Open3D 默认使用。所以一个边长2的立方体,就是2米见方。颜色值在 [0, 1] 之间,不是 [0, 255]。这一点和很多图像处理库不同,要注意。

注意:如果你从其他软件(如CloudCompare)导入点云,颜色值可能是0-255。记得除以255归一化。我曾经因为这个坑,调试了整整一个下午才发现颜色显示不对。

3.4 综合示例:生成三种几何体并对比

下面我把三种几何体放在一起,生成并显示,方便对比:

import open3d as o3d
import numpy as np

# 创建立方体
mesh_box = o3d.geometry.TriangleMesh.create_box(2, 2, 2)
mesh_box.translate([-1, -1, -1])
pcd_box = mesh_box.sample_points_uniformly(500)
pcd_box.paint_uniform_color([0.1, 0.2, 0.8])

# 创建球体
mesh_sphere = o3d.geometry.TriangleMesh.create_sphere(1.0, resolution=20)
pcd_sphere = mesh_sphere.sample_points_uniformly(1000)
pcd_sphere.paint_uniform_color([0.8, 0.2, 0.1])

# 创建圆柱体
mesh_cylinder = o3d.geometry.TriangleMesh.create_cylinder(0.5, 2.0, resolution=20)
pcd_cylinder = mesh_cylinder.sample_points_uniformly(800)
pcd_cylinder.paint_uniform_color([0.2, 0.8, 0.2])

# 平移位置,避免重叠
pcd_box.translate([-3, 0, 0])
pcd_cylinder.translate([3, 0, 0])

# 可视化
o3d.visualization.draw_geometries(
    [pcd_box, pcd_sphere, pcd_cylinder],
    window_name="三种基本几何体点云",
    width=1200, height=600
)

运行这段代码,你会看到三个不同颜色、不同形状的点云并排显示。蓝色立方体、红色球体、绿色圆柱体。嗯,这里要注意:圆柱体的高度是2米,半径0.5米,看起来会比较“瘦高”。如果你想要更粗的圆柱,调大半径就行。

3.5 知识体系:本章核心逻辑

为了让你更直观地理解本章的知识结构,我画了一张流程图:

点云生成核心流程 创建网格 create_mesh_*() 采样点云 sample_points_uniformly() 赋予颜色 paint_uniform_color() 立方体 (Box) 球体 (Sphere) 圆柱体 (Cylinder) width, height, depth radius, resolution radius, height, resolution 核心数据结构:points (N×3) + colors (N×3) 坐标单位:米 | 颜色范围:[0, 1]

这张图清晰地展示了从网格到点云的完整链路。你跟着这个流程走,基本不会出错。

3.6 避坑指南与个人经验

最后,分享几个我实际项目中遇到的坑:

  • 采样不均匀:sample_points_uniformly 是均匀采样,但网格面片大小不同时,大面片上点会更多。如果你需要严格均匀分布,可以用 sample_points_poisson_disk 做泊松盘采样。
  • 颜色丢失:如果你保存点云为 .ply 文件,记得用 write_point_cloud 并指定 write_ascii=True,否则颜色信息可能丢失。
  • 坐标偏移:多个几何体组合时,一定要先平移再合并。我习惯用 pcd.translate([dx, dy, dz]) 分别调整位置。

好了,这一讲的内容就到这里。你学会了用Open3D生成三种基本几何体的点云,也理解了坐标和颜色的存储方式。下一讲我们会继续深入,看看如何生成更复杂的点云数据。


公众号:蓝海资料掘金营,微信deep3321