区域生长算法:(聚类)
将具有相似性的点云集合起来构成区域。首先对每个需要分割的区域找出一个种子点作为生长的起点,然后将种子点周围邻域中与种子有相同或相似性质的点合并到种子像素所在的区域中。而新的点继续作为种子向四周生长,直到再没有满足条件的像素可以包括进来,一个区域就生长而成了。
我把它理解为往水里扔石子后水波向周围扩散一样当扩散到一定的区域后水波就会停止。
算法流程:
1. 计算法线normal和曲率curvatures,依据曲率升序排序;
2. 选择曲率最低的为初始种子点,种子周围的临近点和种子点云相比较;
3. 法线的方向是否足够相近(法线夹角足够rpy),法线夹角阈值;
4. 曲率是否足够小(表面处在同一个弯曲程度),区域差值阈值;
5. 如果满足2,3则该点可用做种子点;
6. 如果只满足2,则归类而不做种子。
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL)
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/segmentation/region_growing.h>//区域生长
#include <pcl/features/normal_3d.h>//法线估计特征
#include <pcl/kdtree/kdtree.h>//k维树
#include <pcl/filters/statistical_outlier_removal.h>//统计离群点
#include <iostream>
#include <vector>//容器
#include <pcl/filters/voxel_grid.h>//基于体素的滤波
#include <pcl/visualization/pcl_visualizer.h>//pcl的可视化
#include <pcl/filters/extract_indices.h>
using namespace pcl;
using namespace std;
typedef PointXYZ PoinT;
int *rand_rgb() {//随机产生颜色
int *rgb = new int[3];
rgb[0] = rand() % 255;
rgb[1] = rand() % 255;
rgb[2] = rand() % 255;
return rgb;
}
int main() {
PointCloud<PoinT>::Ptr cloud(new PointCloud<PoinT>);//创建cloud指针
if (io::loadPCDFile("D:\\pclcode\\pcl_segmentation\\region_growing_segmentation3\\source\\table_scene_lms400.pcd", *cloud) == -1) {
PCL_ERROR("read false");
}//读取pcd文件
//降采样
VoxelGrid<PoinT> vox;//创建降采样对象vox
PointCloud<PoinT>::Ptr vox_cloud(new PointCloud<PoinT>);//创建vox_cloud指针
vox.setInputCloud(cloud);//设置输入点云
vox.setLeafSize(0.01, 0.01, 0.01);//设置叶尺寸为cm
vox.filter(*vox_cloud);//执行滤波,并将结果保存在vox_cloud中
//去噪声
StatisticalOutlierRemoval<PoinT>sor;//创建统计滤波对象sor
PointCloud<PoinT>::Ptr sor_cloud(new PointCloud<PoinT>);//创建sor_cloud指针
sor.setInputCloud(vox_cloud);//设置输入点云
sor.setMeanK(20);//设置考虑查询点临近点数为20
sor.setStddevMulThresh(0.02);//设置判断是否为离群点的阈值为0.02
sor.filter(*sor_cloud);
//法向量求解
NormalEstimation<PoinT, Normal> ne;//创建法向量求解对象ne
search::KdTree<PoinT>::Ptr tree(new search::KdTree<PoinT>);
PointCloud<Normal>::Ptr normal_cloud(new PointCloud<Normal>);//创建指针normal_cloud
ne.setInputCloud(sor_cloud);//设置输入点云
ne.setKSearch(20);//设置kdtree搜索距离
ne.setSearchMethod(tree);//设置搜索方式
ne.compute(*normal_cloud);//进行法向量求解
//基于法向量和曲率的区域生长算法
PointCloud<PoinT>::Ptr reg_cloud(new PointCloud<PoinT>);//创建reg_cloud指针
RegionGrowing<PoinT, Normal> reg;//创建区域分割对象reg
reg.setInputCloud(sor_cloud);//设置输入点云
reg.setSearchMethod(tree);//设置所搜索方式
reg.setNumberOfNeighbours(20);//设置搜索的邻域点的个数
reg.setMinClusterSize(50);//最小聚类的点数
reg.setMaxClusterSize(100000);//最大聚类的点数
reg.setSmoothnessThreshold(3.0 / 180 * M_PI);//设置平滑度 法线插值阈值
reg.setCurvatureThreshold(1.0);//设置曲率的阈值
reg.setInputNormals(normal_cloud);//输入的法线
vector<PointIndices>clusters;
reg.extract(clusters);
ExtractIndices<PoinT>ext;
visualization::PCLVisualizer::Ptr viewer(new visualization::PCLVisualizer("Result of RegionGrowing"));//创建一个viewer指针
vector<int>index;
for (int iter = 0; iter < clusters.size(); iter++)
{
//将索引汇总
PointCloud<PoinT>::Ptr final_cloud(new PointCloud<PoinT>);//创建final_cloud指针
vector<int> inlier = clusters[iter].indices;
index.insert(index.end(), inlier.begin(), inlier.end());
//提取每个索引对应得点云并展示
boost::shared_ptr<vector<int>>index1 = boost::make_shared<vector<int>>(inlier);
ext.setInputCloud(sor_cloud);//将上述去噪声后的点云输入
ext.setIndices(index1);
ext.filter(*final_cloud);//执行索引,并将结果保存在final_cloud中
stringstream ss;
ss << "D:\\pclcode\\pcl_segmentation\\region_growing_segmentation3\\sourc\\" << "RegionGrowing_clouds" << iter << ".pcd";
//io::savePCDFileASCII(ss.str(), *copy_cloud);
int *rgb = rand_rgb();//随机生成0-255的颜色值
visualization::PointCloudColorHandlerCustom<PoinT>rgb1(final_cloud, rgb[0], rgb[1], rgb[2]);//提取的平面不同彩色展示
delete[]rgb;
viewer->addPointCloud(final_cloud, rgb1, ss.str());//添加点云
viewer->setBackgroundColor(192, 255, 62); //设置背景颜色
viewer->setPointCloudRenderingProperties(visualization::PCL_VISUALIZER_POINT_SIZE, 1, ss.str());//设置显示点云的大小
}
viewer->spinOnce(1000);//刷新
//将索引取反,获取剩余的点云数据,并展示
PointCloud<PoinT>::Ptr rest_cloud(new PointCloud<PoinT>);//创建rest_cloud指针
boost::shared_ptr<vector<int>>index_final = boost::make_shared<vector<int>>(index);//创建共享指针
ext.setInputCloud(sor_cloud);//设置输入点云
ext.setIndices(index_final);//索引
ext.setNegative(true);//true表示取反
ext.filter(*rest_cloud);//执行索引,并将结果保存在rest_cloud中
visualization::PCLVisualizer::Ptr viewer1(new visualization::PCLVisualizer("rest_clouds"));//创建viewer1指针
viewer1->addPointCloud(rest_cloud, "rest_clous");//添加点云
viewer1->setBackgroundColor(255, 105, 180);//设置背景颜色
viewer1->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 1, 0.07, 0.58, "rest_clous");//设置左窗口点云为绿色
viewer1->setPointCloudRenderingProperties(visualization::PCL_VISUALIZER_POINT_SIZE, 1, "rest_clous");
//io::savePCDFileASCII("C:\\Users\\Administrator\\Desktop\\rest_clouds", *rest_cloud);
viewer1->spin();//刷新
return 0;
}
CmakeLists文件如下:
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
project(region_growing_segmentation2)
find_package(PCL 1.5 REQUIRED)
include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})
add_executable (region_growing_segmentation region_growing_segmentation.cpp)
target_link_libraries (region_growing_segmentation ${PCL_LIBRARIES})