第2章:PCL库入门:安装、配置与第一个滤波程序
说实话,很多初学者一上来就被PCL的编译折腾得够呛。我当年第一次装PCL,光编译就花了整整一个下午。嗯,今天咱们就把这事捋清楚,让你少走弯路。
2.1 PCL是什么?
PCL,全称Point Cloud Library,点云库。说白了,它就是点云处理界的OpenCV。你想对点云做什么操作,滤波、分割、配准、识别,它基本都提供了现成的工具。
我个人习惯把PCL看作一个工具箱。里面装着各种扳手、螺丝刀——也就是各种算法模块。你不需要自己造轮子,直接拿来用就行。
核心模块一览:
- Filters:滤波模块,去除噪声、下采样
- Features:特征提取,比如法向量、FPFH
- Segmentation:分割模块,地面分割、聚类
- Registration:配准模块,ICP算法就在这
- Visualization:可视化模块,看点云用的
2.2 安装PCL——别再踩这些坑了
安装PCL,不同平台差别挺大。我分别说说Windows和Ubuntu下的做法。
Windows下安装(推荐vcpkg方式)
我以前用官方安装包,结果各种依赖缺失。后来改用vcpkg,真香。你想想看,一条命令搞定所有依赖,多省心。
# 先安装vcpkg(如果还没装)
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
.\bootstrap-vcpkg.bat
# 安装PCL(64位版本)
.\vcpkg install pcl:x64-windows
# 集成到Visual Studio
.\vcpkg integrate install
安装完成后,在VS里新建项目,直接#include <pcl/...>就能用。注意选x64平台,别用x86——我见过有人在这卡了半天。
Ubuntu下安装
Ubuntu就简单多了。但要注意版本问题。Ubuntu 18.04默认装的是PCL 1.8,20.04是1.10。如果你需要最新版,得从源码编译。
# 一行命令搞定(Ubuntu 20.04)
sudo apt install libpcl-dev pcl-tools
# 验证安装
pcl_viewer --help # 能显示帮助信息就说明装好了
我曾经踩过的坑:
Ubuntu下用apt安装PCL后,编译自己的程序时提示找不到pcl_visualizer。后来发现是没装vtk的依赖。解决办法:sudo apt install libvtk7-dev。嗯,这个坑我替你们踩过了。
2.3 核心数据结构:PointCloud和PointXYZ
PCL里最核心的数据结构就两个:PointCloud和PointXYZ。你想想看,点云不就是一堆点的集合吗?PointXYZ代表单个点,PointCloud代表整片点云。
PointXYZ——一个点的样子
一个三维点,包含x、y、z三个坐标。就这么简单。但PCL还提供了其他点类型,比如带颜色的PointXYZRGB,带法向量的PointNormal。
// 创建一个点
pcl::PointXYZ point;
point.x = 1.0f;
point.y = 2.0f;
point.z = 3.0f;
// 或者用初始化列表
pcl::PointXYZ point2(1.0f, 2.0f, 3.0f);
PointCloud——点云的容器
PointCloud本质上是一个vector,里面存了一堆点。它还额外保存了点云的宽度、高度、是否有序等信息。
// 创建一个点云对象
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
// 设置点云属性
cloud->width = 100; // 点的数量
cloud->height = 1; // 1表示无序点云
cloud->points.resize(cloud->width * cloud->height);
// 填充点云数据
for (size_t i = 0; i < cloud->points.size(); ++i) {
cloud->points[i].x = static_cast<float>(i);
cloud->points[i].y = static_cast<float>(i * 2);
cloud->points[i].z = 0.0f;
}
小技巧:
用PointCloud::Ptr(智能指针)来管理点云对象。这样你传参的时候不用复制整个点云,只传指针就行。我在项目中处理百万级点云时,这个习惯帮我省了不少内存。
2.4 第一个滤波程序——直通滤波
好了,理论说完了,咱们来写第一个滤波程序。直通滤波(PassThrough)是最简单的滤波方式——你设定一个范围,范围内的点留下,范围外的去掉。
为什么要用直通滤波?举个例子:你扫描了一个房间,只想看地面附近(z=0附近)的点。用直通滤波,设定z轴范围[-0.1, 0.1],地面就出来了。
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/filters/passthrough.h>
int main() {
// 1. 加载点云
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>);
if (pcl::io::loadPCDFile<pcl::PointXYZ>("input.pcd", *cloud) == -1) {
PCL_ERROR("Couldn't read file input.pcd\n");
return -1;
}
std::cout << "原始点云点数: " << cloud->points.size() << std::endl;
// 2. 创建直通滤波器对象
pcl::PassThrough<pcl::PointXYZ> pass;
pass.setInputCloud(cloud); // 设置输入点云
pass.setFilterFieldName("z"); // 设置滤波字段(z轴)
pass.setFilterLimits(0.0, 1.0); // 设置范围:保留z在0到1之间的点
// pass.setFilterLimitsNegative(true); // 如果设为true,则保留范围外的点
// 3. 执行滤波
pass.filter(*cloud_filtered);
// 4. 输出结果
std::cout << "滤波后点云点数: " << cloud_filtered->points.size() << std::endl;
// 5. 保存结果
pcl::io::savePCDFileASCII("output.pcd", *cloud_filtered);
return 0;
}
这段代码的逻辑很清晰:加载点云 → 设置滤波器 → 执行滤波 → 保存结果。你想想看,是不是跟用筛子筛面粉一个道理?
编译命令(CMakeLists.txt):
cmake_minimum_required(VERSION 3.10)
project(passthrough_filter)
find_package(PCL 1.8 REQUIRED)
include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})
add_executable(passthrough_filter passthrough_filter.cpp)
target_link_libraries(passthrough_filter ${PCL_LIBRARIES})
2.5 本章知识体系
下面这张图帮你理清本章的知识脉络。我画图的时候习惯把核心概念放在中间,外围是具体操作和注意事项。
我的建议:
学PCL别贪多。先把安装环境搞定,然后跑通第一个滤波程序。能跑通,你就已经入门了。剩下的,遇到什么需求再学什么模块。我当年就是这么过来的。
好了,这一章的内容就到这。安装配置搞定了,核心数据结构也了解了,第一个滤波程序也跑通了。接下来你就可以自己试试不同的滤波参数,看看效果有什么变化。实践出真知嘛。