第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做产品化。
本章知识体系
下面这张图,是我自己画的本章知识结构。你可以把它当作学习地图,随时回来对照。
好了,这一章的内容就到这里。记住,点云处理没有捷径,但打好基础能让你少走很多弯路。下一章我们聊聊点云滤波,那是点云预处理的重头戏。