记录翻译一下pcl中的例子
实现的“法线差”功能,用于基于比例的无组织点云分割。
例子
官网的可视化图片流程
C++
代码流程:
- 设置输入点云相关参数。图片左上
- 设置两个半径求取法相量点云,使用DoN根据两个不同半径的法向量生成DoN点云。图片右上
- 更加DoN点云,设置曲率阈值进行滤波,获取符合要求的点云。图片右下
- 根据欧式距离对滤波后的点云进行聚类处理。图片左下
#include <string>
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/search/organized.h>
#include <pcl/search/kdtree.h>
#include <pcl/features/normal_3d_omp.h>
#include <pcl/filters/conditional_removal.h>
#include <pcl/segmentation/extract_clusters.h>
#include <pcl/features/don.h>
using namespace pcl;
int
main (int argc, char *argv[])
{
///The smallest scale to use in the DoN filter.
double scale1;
///The largest scale to use in the DoN filter.
double scale2;
///The minimum DoN magnitude to threshold by
double threshold;
///segment scene into clusters with given distance tolerance using euclidean clustering
double segradius;
if (argc < 6)
{
std::cerr << "usage: " << argv[0] << " inputfile smallscale largescale threshold segradius" << std::endl;
exit (EXIT_FAILURE);
}
/// the file to read from.
std::string infile = argv[1];
/// small scale
std::istringstream (argv[2]) >> scale1;
/// large scale
std::istringstream (argv[3]) >> scale2;
std::istringstream (argv[4]) >> threshold; // threshold for DoN magnitude
std::istringstream (argv[5]) >> segradius; // threshold for radius segmentation
// Load cloud in blob format
pcl::PCLPointCloud2 blob;
pcl::io::loadPCDFile (infile.c_str (), blob);
pcl::PointCloud<PointXYZRGB>::Ptr cloud (new pcl::PointCloud<PointXYZRGB>);
pcl::fromPCLPointCloud2 (blob, *cloud);
// Create a search tree, use KDTreee for non-organized data.
// 构建搜索树
pcl::search::Search<PointXYZRGB>::Ptr tree;
if (cloud->isOrganized ())
{
tree.reset (new pcl::search::OrganizedNeighbor<PointXYZRGB> ());
}
else
{
tree.reset (new pcl::search::KdTree<PointXYZRGB> (false));
}
// Set the input pointcloud for the search tree
tree->setInputCloud (cloud);
if (scale1 >= scale2)
{
std::cerr << "Error: Large scale must be > small scale!" << std::endl;
exit (EXIT_FAILURE);
}
// Compute normals using both small and large scales at each point
pcl::NormalEstimationOMP<PointXYZRGB, PointNormal> ne;
ne.setInputCloud (cloud);
ne.setSearchMethod (tree);
/**
* NOTE: setting viewpoint is very important, so that we can ensure
* normals are all pointed in the same direction!
*/
// 设置法向量的观测方向
ne.setViewPoint (std::numeric_limits<float>::max (), std::numeric_limits<float>::max (), std::numeric_limits<float>::max ());
// calculate normals with the small scale
std::cout << "Calculating normals for scale..." << scale1 << std::endl;
//半径较小的点云的法向量
pcl::PointCloud<PointNormal>::Ptr normals_small_scale (new pcl::PointCloud<PointNormal>);
ne.setRadiusSearch (scale1);
ne.compute (*normals_small_scale);
// calculate normals with the large scale
std::cout << "Calculating normals for scale..." << scale2 << std::endl;
//半径较大的点云的法向量
pcl::PointCloud<PointNormal>::Ptr normals_large_scale (new pcl::PointCloud<PointNormal>);
ne.setRadiusSearch (scale2);
ne.compute (*normals_large_scale);
// Create output cloud for DoN results
PointCloud<PointNormal>::Ptr doncloud (new pcl::PointCloud<PointNormal>);
copyPointCloud (*cloud, *doncloud);
std::cout << "Calculating DoN... " << std::endl;
// Create DoN operator
pcl::DifferenceOfNormalsEstimation<PointXYZRGB, PointNormal, PointNormal> don;
don.setInputCloud (cloud);
don.setNormalScaleLarge (normals_large_scale);
don.setNormalScaleSmall (normals_small_scale);
if (!don.initCompute ())
{
std::cerr << "Error: Could not initialize DoN feature operator" << std::endl;
exit (EXIT_FAILURE);
}
// Compute DoN
don.computeFeature (*doncloud);//计算点云法向量变化程度保存到doncloud
// Save DoN features
pcl::PCDWriter writer;
writer.write<pcl::PointNormal> ("don.pcd", *doncloud, false);
// Filter by magnitude
std::cout << "Filtering out DoN mag <= " << threshold << "..." << std::endl;
// Build the condition for filtering
// 构建条件滤波器
pcl::ConditionOr<PointNormal>::Ptr range_cond(new pcl::ConditionOr<PointNormal>());// 设置滤波条件 或 or
range_cond->addComparison (pcl::FieldComparison<PointNormal>::ConstPtr(new pcl::FieldComparison<PointNormal> ("curvature", pcl::ComparisonOps::GT, threshold)));//保留大于阈值的点
// Build the filter
pcl::ConditionalRemoval<PointNormal> condrem;
condrem.setCondition (range_cond);
condrem.setInputCloud (doncloud);
// 保存滤波结果
pcl::PointCloud<PointNormal>::Ptr doncloud_filtered (new pcl::PointCloud<PointNormal>);
// Apply filter
condrem.filter (*doncloud_filtered);
doncloud = doncloud_filtered;
// Save filtered output
std::cout << "Filtered Pointcloud: " << doncloud->size () << " data points." << std::endl;
writer.write<pcl::PointNormal> ("don_filtered.pcd", *doncloud, false);
// Filter by magnitude
std::cout << "Clustering using EuclideanClusterExtraction with tolerance <= " << segradius << "..." << std::endl;
// 用于聚类的kd-tree
pcl::search::KdTree<PointNormal>::Ptr segtree (new pcl::search::KdTree<PointNormal>);
segtree->setInputCloud (doncloud);
// 聚类分成了几块不同的点云的点云的index
std::vector<pcl::PointIndices> cluster_indices;
// 欧几里得聚类
pcl::EuclideanClusterExtraction<PointNormal> ec;
ec.setClusterTolerance (segradius);
ec.setMinClusterSize (50);
ec.setMaxClusterSize (100000);
ec.setSearchMethod (segtree);
ec.setInputCloud (doncloud);
ec.extract (cluster_indices);
int j = 0;
for (const auto& cluster : cluster_indices)
{
pcl::PointCloud<PointNormal>::Ptr cloud_cluster_don (new pcl::PointCloud<PointNormal>);
for (const auto& idx : cluster.indices)
{
cloud_cluster_don->points.push_back ((*doncloud)[idx]);
}
cloud_cluster_don->width = cloud_cluster_don->size ();
cloud_cluster_don->height = 1;
cloud_cluster_don->is_dense = true;
//Save cluster
// 保存聚类结果
std::cout << "PointCloud representing the Cluster: " << cloud_cluster_don->size () << " data points." << std::endl;
std::stringstream ss;
ss << "don_cluster_" << j << ".pcd";
writer.write<pcl::PointNormal> (ss.str (), *cloud_cluster_don, false);
++j;
}
}
//条件
pcl::ConditionOr<PointNormal> // 条件或 ||
pcl::ConditionAnd<PointNormal> // 条件与 &&
//比较器
pcl::ComparisonOps::GT // >
pcl::ComparisonOps::GE // >=
pcl::ComparisonOps::LT // <
pcl::ComparisonOps::LE // <=
pcl::ComparisonOps::EQ // ==
cmakelist
# 最低的cmakelist版本
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
# 项目名称
project(don_segmentation
# 寻找pcl库
find_package(PCL 1.7 REQUIRED)
# 包含文件路径
include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})
# 可执行文件
add_executable (don_segmentation don_segmentation.cpp)
# 链接库
target_link_libraries (don_segmentation ${PCL_LIBRARIES})
参考
- https://pcl.readthedocs.io/projects/tutorials/en/latest/don_segmentation.html
- https://pcl.readthedocs.io/projects/tutorials/en/latest/conditional_removal.html
- https://pcl.readthedocs.io/en/latest/cluster_extraction.html