第一章 点云数据采集
第二章 点云滤波
第三章 点云降采样
关键点提取关键的一些点,旨在减少数据量;而特征提取旨在为每个点提供一个可用于后续任务的描述。
通常点云特征与关键点结合使用。
每一个点的位置都有垂直于点表面的的矢量,但是这种方式比较耗时。
PCL
#include
#include
#include
#include
#include
int main() {
// 1. Load Point Cloud from PCD file
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>());
pcl::io::loadPCDFile("second_radius_cloud.pcd", *cloud);
// 2. Setup the normal estimation
pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> normal_estimation;
normal_estimation.setInputCloud(cloud);
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
normal_estimation.setSearchMethod(tree);
normal_estimation.setRadiusSearch(30);
// 3. Compute the normals
pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>());
normal_estimation.compute(*normals);
// 4. Visualization
pcl::visualization::PCLVisualizer viewer("Normals Viewer");
viewer.setBackgroundColor(0, 0, 0);
viewer.addPointCloud<pcl::PointXYZ>(cloud, "cloud");
viewer.addPointCloudNormals<pcl::PointXYZ, pcl::Normal>(cloud, normals, 10, 50, "normals");
viewer.initCameraParameters();
viewer.saveScreenshot("screenshot.png");
viewer.spin();
return 0;
}
每一个点的位置都有垂直于点表面的的矢量,但是这种方式比较耗时。
PCL
在这里可视化了shot的前三个维度。
#include
#include
#include
#include
#include
int main() {
// Load Point Cloud from PCD file
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>());
pcl::io::loadPCDFile("second_radius_cloud.pcd", *cloud);
// Compute Normals
pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> normal_estimation;
pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>());
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
normal_estimation.setInputCloud(cloud);
normal_estimation.setSearchMethod(tree);
normal_estimation.setRadiusSearch(30);
normal_estimation.compute(*normals);
// Compute SHOT descriptors
pcl::SHOTEstimation<pcl::PointXYZ, pcl::Normal, pcl::SHOT352> shot;
pcl::PointCloud<pcl::SHOT352>::Ptr shot_descriptors(new pcl::PointCloud<pcl::SHOT352>());
shot.setInputCloud(cloud);
shot.setInputNormals(normals);
shot.setRadiusSearch(3);
shot.compute(*shot_descriptors);
// Convert SHOT values to colors
pcl::PointCloud<pcl::PointXYZRGB>::Ptr colored_cloud(new pcl::PointCloud<pcl::PointXYZRGB>());
colored_cloud->resize(cloud->size());
for (size_t i = 0; i < cloud->size(); ++i) {
pcl::PointXYZRGB point;
point.x = (*cloud)[i].x;
point.y = (*cloud)[i].y;
point.z = (*cloud)[i].z;
// Use the first three dimensions of the SHOT descriptor to color the point
point.r = static_cast<uint8_t>(255 * std::min(1.0f, shot_descriptors->points[i].descriptor[0]));
point.g = static_cast<uint8_t>(255 * std::min(1.0f, shot_descriptors->points[i].descriptor[1]));
point.b = static_cast<uint8_t>(255 * std::min(1.0f, shot_descriptors->points[i].descriptor[2]));
colored_cloud->points[i] = point;
}
// Visualization
pcl::visualization::PCLVisualizer viewer("SHOT Features Viewer");
viewer.setBackgroundColor(0, 0, 0);
viewer.addPointCloud<pcl::PointXYZRGB>(colored_cloud, "colored cloud"););
viewer.spin();
return 0;
}
PFH通过参数化查询点与邻域点之间的空间差异,并形成一个多维直方图对点的k邻域几何属性进行描述。直方图所在的高维超空间为特征表示提供了一个可度量的信息空间,对点云对应曲面的6维姿态来说它具有不变性,并且在不同的采样密度或邻域的噪音等级下具有鲁棒性。点特征直方图(PFH)表示法是基于点与其k邻域之间的关系以及它们的估计法线,简言之,它考虑估计法线方向之间所有的相互作用,试图捕获最好的样本表面变化情况,以描述样本的几何特征。
PCL
#include
#include
#include
#include
#include
#include
int main() {
// 1. Load Point Cloud from PCD file
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>());
pcl::io::loadPCDFile("second_radius_cloud.pcd", *cloud);
// 2. Compute the normals
pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> normal_estimation;
normal_estimation.setInputCloud(cloud);
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
normal_estimation.setSearchMethod(tree);
normal_estimation.setRadiusSearch(30);
pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>());
normal_estimation.compute(*normals);
// 3. Compute PFH descriptors
pcl::PFHEstimation<pcl::PointXYZ, pcl::Normal, pcl::PFHSignature125> pfh_estimation;
pfh_estimation.setInputCloud(cloud);
pfh_estimation.setInputNormals(normals);
pfh_estimation.setSearchMethod(tree);
pfh_estimation.setRadiusSearch(80);
pcl::PointCloud<pcl::PFHSignature125>::Ptr pfhs(new pcl::PointCloud<pcl::PFHSignature125>());
pfh_estimation.compute(*pfhs);
// 4. Convert PFH values to colors for visualization
pcl::PointCloud<pcl::PointXYZRGB>::Ptr colored_cloud(new pcl::PointCloud<pcl::PointXYZRGB>());
colored_cloud->resize(cloud->size());
for (size_t i = 0; i < cloud->size(); ++i) {
pcl::PointXYZRGB point;
point.x = (*cloud)[i].x;
point.y = (*cloud)[i].y;
point.z = (*cloud)[i].z;
// Use the first dimension of the PFH descriptor to color the point
point.r = static_cast<uint8_t>(255 * std::min(1.0f, pfhs->points[i].histogram[0] / 100.0f));
point.g = 0;
point.b = 0;
colored_cloud->points[i] = point;
}
// 5. Visualization
pcl::visualization::PCLVisualizer viewer("PFH Visualization");
viewer.setBackgroundColor(0, 0, 0);
viewer.addPointCloud<pcl::PointXYZRGB>(colored_cloud, "colored cloud");
viewer.spin();
return 0;
}
快速点特征直方图(Fast Point Feature Histograms, FPFH)是PFH计算方式的简化形式。它的思想在于分别计算查询点的k邻域中每一个点的简化点特征直方图(Simplified Point Feature Histogram,SPFH),再通过一个公式将所有的SPFH加权成最后的快速点特征直方图。FPFH把算法的计算复杂度降低到了O(nk) ,但是任然保留了PFH大部分的识别特性。
PCL
#include
#include
#include
#include
#include
#include
int main() {
// 1. Load Point Cloud from PCD file
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>());
pcl::io::loadPCDFile("second_radius_cloud.pcd", *cloud);
// 2. Compute the normals
pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> normal_estimation;
normal_estimation.setInputCloud(cloud);
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
normal_estimation.setSearchMethod(tree);
normal_estimation.setRadiusSearch(300);
pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>());
normal_estimation.compute(*normals);
// 3. Compute FPFH descriptors
pcl::FPFHEstimation<pcl::PointXYZ, pcl::Normal, pcl::FPFHSignature33> fpfh_estimation;
fpfh_estimation.setInputCloud(cloud);
fpfh_estimation.setInputNormals(normals);
fpfh_estimation.setSearchMethod(tree);
fpfh_estimation.setRadiusSearch(500);
pcl::PointCloud<pcl::FPFHSignature33>::Ptr fpfhs(new pcl::PointCloud<pcl::FPFHSignature33>());
fpfh_estimation.compute(*fpfhs);
// 4. Convert FPFH values to colors for visualization
pcl::PointCloud<pcl::PointXYZRGB>::Ptr colored_cloud(new pcl::PointCloud<pcl::PointXYZRGB>());
colored_cloud->resize(cloud->size());
for (size_t i = 0; i < cloud->size(); ++i) {
pcl::PointXYZRGB point;
point.x = (*cloud)[i].x;
point.y = (*cloud)[i].y;
point.z = (*cloud)[i].z;
// Use the first dimension of the FPFH descriptor to color the point
point.r = static_cast<uint8_t>(255 * std::min(1.0f, fpfhs->points[i].histogram[0] / 100.0f));
point.g = 0;
point.b = 0;
colored_cloud->points[i] = point;
}
// 5. Visualization
boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("FPFH Visualization"));
viewer->setBackgroundColor(0, 0, 0);
viewer->addPointCloud<pcl::PointXYZRGB>(colored_cloud, "colored cloud");
viewer->spin();
return 0;
}
FPFH有很好的速度和辨别能力,VFH在此基础上添加视点方差,同时保持尺度不变性。
PCL
#include
#include
#include
#include
#include
#include
int main() {
// 1. Load Point Cloud from PCD file
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>());
pcl::io::loadPCDFile("second_radius_cloud.pcd", *cloud);
// 2. Compute the normals
pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> normal_estimation;
normal_estimation.setInputCloud(cloud);
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
normal_estimation.setSearchMethod(tree);
normal_estimation.setRadiusSearch(30);
pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>());
normal_estimation.compute(*normals);
// 3. Compute VFH descriptors
pcl::VFHEstimation<pcl::PointXYZ, pcl::Normal, pcl::VFHSignature308> vfh_estimation;
vfh_estimation.setInputCloud(cloud);
vfh_estimation.setInputNormals(normals);
vfh_estimation.setSearchMethod(tree);
pcl::PointCloud<pcl::VFHSignature308>::Ptr vfhs(new pcl::PointCloud<pcl::VFHSignature308>());
vfh_estimation.compute(*vfhs);
// 4. Visualization
boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("VFH Visualization"));
viewer->setBackgroundColor(0, 0, 0);
viewer->addPointCloud<pcl::PointXYZ>(cloud, "cloud");
// Display some VFH dimensions as text
for (size_t i = 0; i < 5; ++i) {
std::stringstream ss;
ss << "VFH value at dim " << i << ": " << vfhs->points[0].histogram[i];
viewer->addText(ss.str(), 10, 20 + i * 20, 20, 1.0, 1.0, 1.0, "vfh_val" + std::to_string(i));
}
viewer->spin();
return 0;
}