第1章:点云数据基础

大家好,我是这门课的主讲。今天咱们聊聊点云数据的基础。说实话,我刚入行那会儿,面对一堆三维坐标点,脑子里全是问号。这东西到底怎么存?坐标系怎么转?可视化又该怎么搞?

别急,这一章我带你把这些基础打扎实。你想想看,点云处理就像盖房子,地基不牢,后面再花哨的算法都是空中楼阁。

1.1 点云数据格式:PCD、PLY、LAS

点云数据格式,说白了就是三维点的存储方式。不同的传感器、不同的应用场景,用的格式也不一样。我这些年接触最多的就是三种:PCD、PLY、LAS。

PCD格式

PCD是Point Cloud Data的缩写,是PCL库的亲儿子。我个人习惯用PCD做算法验证,因为它结构简单,读写快。

# .PCD v0.7 - Point Cloud Data file format
VERSION 0.7
FIELDS x y z rgb
SIZE 4 4 4 4
TYPE F F F U
COUNT 1 1 1 1
WIDTH 5
HEIGHT 1
VIEWPOINT 0 0 0 1 0 0 0
POINTS 5
DATA ascii
0.1 0.2 0.3 4294967295
0.2 0.3 0.4 4278190335
0.3 0.4 0.5 4286578687
0.4 0.5 0.6 4290826495
0.5 0.6 0.7 4294967295
小技巧:PCD支持ASCII和二进制两种存储方式。数据量大时,二进制格式能节省大量磁盘空间和读写时间。我在处理激光雷达的百万级点云时,从来不用ASCII。

PLY格式

PLY(Polygon File Format)比PCD更灵活。它不仅能存点云,还能存网格、颜色、法向量。我在做三维重建项目时,经常用PLY保存最终结果。

ply
format ascii 1.0
element vertex 8
property float x
property float y
property float z
property uchar red
property uchar green
property uchar blue
element face 6
property list uchar int vertex_indices
end_header
0 0 0 255 0 0
1 0 0 0 255 0
1 1 0 0 0 255
0 1 0 255 255 0
0 0 1 255 0 255
1 0 1 0 255 255
1 1 1 128 128 128
0 1 1 255 255 255
3 0 1 2
3 0 2 3
...
注意:PLY的header部分必须严格按格式写,少一个property都可能解析失败。我曾经因为少写了一个换行符,调试了整整一个下午。

LAS格式

LAS是LiDAR数据的工业标准,主要用于测绘和地理信息系统。它存储的信息非常丰富,除了坐标,还有强度、分类、回波次数等。

属性 PCD PLY LAS
主要用途 算法验证 三维重建 测绘/GIS
支持颜色 是 是 是
支持法向量 否 是 否
支持分类 否 否 是
压缩率 低 中 高

1.2 点云坐标系与变换

坐标系这东西,搞自动驾驶的人天天打交道。你想想看,激光雷达有自己的坐标系,IMU有坐标系,车身有坐标系,世界还有坐标系。这么多坐标系,怎么统一?

说白了,就是做变换。旋转、平移、缩放,一个4x4的齐次变换矩阵全搞定。

import numpy as np

def create_transform_matrix(rotation_matrix, translation_vector):
    """
    创建4x4齐次变换矩阵
    """
    T = np.eye(4)
    T[:3, :3] = rotation_matrix
    T[:3, 3] = translation_vector
    return T

# 绕Z轴旋转30度
theta = np.radians(30)
R = np.array([
    [np.cos(theta), -np.sin(theta), 0],
    [np.sin(theta), np.cos(theta), 0],
    [0, 0, 1]
])
t = np.array([1.0, 2.0, 0.5])

T = create_transform_matrix(R, t)
print("变换矩阵:\n", T)
核心要点:坐标系变换的本质就是矩阵乘法。一个点从激光雷达坐标系转到车身坐标系,只需要左乘一个变换矩阵。

我在实际项目中遇到过一个问题:激光雷达和相机的标定结果,坐标系定义搞反了。结果点云投影到图像上,全跑偏了。嗯,这里要注意,一定要搞清楚每个坐标系的轴向定义。

1.3 点云可视化基础

可视化是点云处理中最直观的调试手段。我习惯用Open3D做快速验证,用PCL做深度定制。

Open3D可视化

import open3d as o3d
import numpy as np

# 生成随机点云
points = np.random.rand(1000, 3)
pcd = o3d.geometry.PointCloud()
pcd.points = o3d.utility.Vector3dVector(points)

# 添加颜色
colors = np.random.rand(1000, 3)
pcd.colors = o3d.utility.Vector3dVector(colors)

# 可视化
o3d.visualization.draw_geometries([pcd],
                                  window_name="我的第一个点云",
                                  width=800,
                                  height=600)

PCL可视化

#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>

int main() {
    pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>);
    
    // 填充点云数据
    cloud->width = 1000;
    cloud->height = 1;
    cloud->points.resize(cloud->width * cloud->height);
    
    for (size_t i = 0; i < cloud->points.size(); ++i) {
        cloud->points[i].x = 1024 * rand() / (RAND_MAX + 1.0f);
        cloud->points[i].y = 1024 * rand() / (RAND_MAX + 1.0f);
        cloud->points[i].z = 1024 * rand() / (RAND_MAX + 1.0f);
        cloud->points[i].r = 255;
        cloud->points[i].g = 0;
        cloud->points[i].b = 0;
    }
    
    // 可视化
    pcl::visualization::PCLVisualizer viewer("PCL点云查看器");
    viewer.addPointCloud(cloud, "cloud");
    
    while (!viewer.wasStopped()) {
        viewer.spinOnce();
    }
    
    return 0;
}
经验之谈:Open3D适合快速原型开发,代码量少。PCL适合做工业级应用,功能更全。我一般先用Open3D验证算法思路,再迁移到PCL做产品化。

本章知识体系

下面这张图,是我自己画的本章知识结构。你可以把它当作学习地图,随时回来对照。

点云数据基础 点云数据格式 PCD格式 PLY格式 LAS格式 坐标系与变换 旋转矩阵 平移向量 齐次变换矩阵 点云可视化 Open3D PCL 掌握这些基础,你就能处理90%的点云数据问题

好了,这一章的内容就到这里。记住,点云处理没有捷径,但打好基础能让你少走很多弯路。下一章我们聊聊点云滤波,那是点云预处理的重头戏。

可可精品资料库