区域生长算法:(聚类)
将具有相似性的点云集合起来构成区域。首先对每个需要分割的区域找出一个种子点作为生长的起点,然后将种子点周围邻域中与种子有相同或相似性质的点合并到种子像素所在的区域中。而新的点继续作为种子向四周生长,直到再没有满足条件的像素可以包括进来,一个区域就生长而成了。
我把它理解为往水里扔石子后水波向周围扩散一样当扩散到一定的区域后水波就会停止。
算法流程:
1. 计算法线normal和曲率curvatures,依据曲率升序排序;
2. 选择曲率最低的为初始种子点,种子周围的临近点和种子点云相比较;
3. 法线的方向是否足够相近(法线夹角足够rpy),法线夹角阈值;
4. 曲率是否足够小(表面处在同一个弯曲程度),区域差值阈值;
5. 如果满足2,3则该点可用做种子点;
6. 如果只满足2,则归类而不做种子。
代码所使用的点云文件:
链接:https://pan.baidu.com/s/1WZ_BJs2kGNEZQUsN-aMwVQ
提取码:6666
#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>
#include <pcl/filters/statistical_outlier_removal.h>
#include <iostream>
#include <vector>
#include <pcl/filters/voxel_grid.h>
#include <pcl/visualization/pcl_visualizer.h>
#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>);
if (io::loadPCDFile("D:\\pclcode\\pcl_segmentation\\region_growing_segmentation2\\source\\scan_003.pcd", *cloud) == -1) {
PCL_ERROR("read false");
}
//降采样
VoxelGrid<PoinT> vox;
PointCloud<PoinT>::Ptr vox_cloud(new PointCloud<PoinT>);
vox.setInputCloud(cloud);
vox.setLeafSize(0.25, 0.25, 0.25);
vox.filter(*vox_cloud);//执行滤波,并将结果保存在vox_cloud中
//去噪声
StatisticalOutlierRemoval<PoinT>sor;
PointCloud<PoinT>::Ptr sor_cloud(new PointCloud<PoinT>);
sor.setInputCloud(vox_cloud);
sor.setMeanK(20);//设置考虑查询点临近个数为20
sor.setStddevMulThresh(0.02);//设置判断是否为离群点的阈值为0.02
sor.filter(*sor_cloud);//执行滤波,并将结果保存在sor_cloud中
//法向量求解
NormalEstimation<PoinT, Normal> ne;//创建法向量对象
search::KdTree<PoinT>::Ptr tree(new search::KdTree<PoinT>);
PointCloud<Normal>::Ptr normal_cloud(new PointCloud<Normal>);
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.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"));
for (int iter = 0; iter < clusters.size(); iter++)
{
//调用方式 将索引汇总
PointCloud<PoinT>::Ptr final_cloud(new PointCloud<PoinT>);
vector<int> inlier = clusters[iter].indices;
//提取每个索引对应得点云并展示
boost::shared_ptr<vector<int>>index = boost::make_shared<vector<int>>(inlier);
ext.setInputCloud(sor_cloud);
ext.setIndices(index);
ext.setNegative(false);
ext.filter(*final_cloud);//执行索引,并将结果保存在final_cloud中
stringstream ss;
ss << "D:\\pclcode\\pcl_segmentation\\region_growing_segmentation2\\source\\" << "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->setPointCloudRenderingProperties(visualization::PCL_VISUALIZER_POINT_SIZE, 2, ss.str());//设置点的大小
}
viewer->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})
0.3 0.3 0.3
0.25 0.25 0.25
点大小为2