[CC]区域生长算法——点云分割
基于CC写的插件,利用PCL中算法实现:
1 void qLxPluginPCL::doRegionGrowing() 2 { 3 assert(m_app); 4 if (!m_app) 5 return; 6 7 const ccHObject::Container& selectedEntities = m_app->getSelectedEntities(); 8 size_t selNum = selectedEntities.size(); 9 if (selNum!=1) 10 { 11 m_app->dispToConsole("Please select two cloud!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); 12 return; 13 } 14 15 ccHObject* ent = selectedEntities[0]; 16 assert(ent); 17 if (!ent || !ent->isA(CC_TYPES::POINT_CLOUD)) 18 { 19 m_app->dispToConsole("Select a real point cloud!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); 20 return; 21 } 22 ccPointCloud* m_cloud = static_cast<ccPointCloud*>(ent); 23 pcl::PointCloud<PointXYZ>::Ptr pcl_t_cloud (new pcl::PointCloud<PointXYZ>); 24 ConvertccPointcloud_to_pclPointCloud(*m_cloud,*pcl_t_cloud); 25 26 pcl::search::Search<pcl::PointXYZ>::Ptr tree = boost::shared_ptr<pcl::search::Search<pcl::PointXYZ> > (new pcl::search::KdTree<pcl::PointXYZ>); 27 pcl::PointCloud <pcl::Normal>::Ptr normals (new pcl::PointCloud <pcl::Normal>); 28 pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> normal_estimator; 29 normal_estimator.setSearchMethod (tree); 30 normal_estimator.setInputCloud (pcl_t_cloud); 31 normal_estimator.setKSearch (50); 32 normal_estimator.compute (*normals); 33 34 pcl::IndicesPtr indices (new std::vector <int>); 35 pcl::PassThrough<pcl::PointXYZ> pass; 36 pass.setInputCloud (pcl_t_cloud); 37 pass.setFilterFieldName ("z"); 38 pass.setFilterLimits (0.0, 1.0); 39 pass.filter (*indices); 40 41 pcl::RegionGrowing<pcl::PointXYZ, pcl::Normal> reg; 42 reg.setMinClusterSize (50); 43 reg.setMaxClusterSize (1000000); 44 reg.setSearchMethod (tree); 45 reg.setNumberOfNeighbours (30); 46 reg.setInputCloud (pcl_t_cloud); 47 //reg.setIndices (indices); 48 reg.setInputNormals (normals); 49 reg.setSmoothnessThreshold (3.0 / 180.0 * M_PI); 50 reg.setCurvatureThreshold (1.0); 51 52 std::vector <pcl::PointIndices> clusters; 53 reg.extract (clusters); 54 55 pcl::PointCloud <pcl::PointXYZRGB>::Ptr colored_cloud = reg.getColoredCloud (); 56 int pointCount=colored_cloud->size(); 57 ccPointCloud* ccCloud =new ccPointCloud(); 58 if (!ccCloud->reserve(static_cast<unsigned>(pointCount))) 59 return ; 60 ccCloud->enableScalarField(); 61 ccCloud->setName(QString("RegionGrowing")); 62 ccCloud->showColors(true); 63 64 ccCloud->setPointSize(1); 65 for (size_t i = 0; i < pointCount; ++i) 66 { 67 CCVector3 P(colored_cloud->at(i).x,colored_cloud->at(i).y,colored_cloud->at(i).z); 68 ccCloud->addPoint(P); 69 70 } 71 72 std::vector< pcl::PointIndices >::iterator i_segment; 73 srand (static_cast<unsigned int> (time (0))); 74 std::vector<unsigned char> colors; 75 for (size_t i_segment = 0; i_segment < clusters.size (); i_segment++) 76 { 77 colors.push_back (static_cast<unsigned char> (rand () % 256)); 78 colors.push_back (static_cast<unsigned char> (rand () % 256)); 79 colors.push_back (static_cast<unsigned char> (rand () % 256)); 80 } 81 82 if (ccCloud->resizeTheRGBTable(true)) 83 { 84 int next_color = 0; 85 for (i_segment = clusters.begin (); i_segment != clusters.end (); i_segment++) 86 { 87 std::vector<int>::iterator i_point; 88 for (i_point = i_segment->indices.begin (); i_point != i_segment->indices.end (); i_point++) 89 { 90 int index; 91 index = *i_point; 92 ccColor::Rgb rgb=ccColor::Rgb( colors[3 * next_color],colors[3 * next_color + 1],colors[3 * next_color + 2]); 93 ccCloud->setPointColor(index,rgb.rgb); 94 } 95 next_color++; 96 } 97 } 98 ccHObject* group = 0; 99 if (!group) 100 group = new ccHObject(QString("RegionGrowing(%1)").arg(ent->getName())); 101 group->addChild(ccCloud); 102 group->setVisible(true); 103 m_app->addToDB(group); 104 }
具体实现参考RegionGrowing类:
1 template <typename PointT, typename NormalT> void 2 pcl::RegionGrowing<PointT, NormalT>::extract (std::vector <pcl::PointIndices>& clusters) 3 { 4 clusters_.clear (); 5 clusters.clear (); 6 point_neighbours_.clear (); 7 point_labels_.clear (); 8 num_pts_in_segment_.clear (); 9 number_of_segments_ = 0; 10 11 bool segmentation_is_possible = initCompute (); 12 if ( !segmentation_is_possible ) 13 { 14 deinitCompute (); 15 return; 16 } 17 18 segmentation_is_possible = prepareForSegmentation (); 19 if ( !segmentation_is_possible ) 20 { 21 deinitCompute (); 22 return; 23 } 24 25 findPointNeighbours (); 26 applySmoothRegionGrowingAlgorithm (); 27 assembleRegions (); 28 29 clusters.resize (clusters_.size ()); 30 std::vector<pcl::PointIndices>::iterator cluster_iter_input = clusters.begin (); 31 for (std::vector<pcl::PointIndices>::const_iterator cluster_iter = clusters_.begin (); cluster_iter != clusters_.end (); cluster_iter++) 32 { 33 if ((static_cast<int> (cluster_iter->indices.size ()) >= min_pts_per_cluster_) && 34 (static_cast<int> (cluster_iter->indices.size ()) <= max_pts_per_cluster_)) 35 { 36 *cluster_iter_input = *cluster_iter; 37 cluster_iter_input++; 38 } 39 } 40 41 clusters_ = std::vector<pcl::PointIndices> (clusters.begin (), cluster_iter_input); 42 clusters.resize(clusters_.size()); 43 44 deinitCompute (); 45 }
算法实现的关键多了一步种子点选取的过程,需要根据某一种属性排序。
1 template <typename PointT, typename NormalT> void 2 pcl::RegionGrowing<PointT, NormalT>::applySmoothRegionGrowingAlgorithm () 3 { 4 int num_of_pts = static_cast<int> (indices_->size ()); 5 point_labels_.resize (input_->points.size (), -1); 6 7 std::vector< std::pair<float, int> > point_residual; 8 std::pair<float, int> pair; 9 point_residual.resize (num_of_pts, pair); 10 11 if (normal_flag_ == true) 12 { 13 for (int i_point = 0; i_point < num_of_pts; i_point++) 14 { 15 int point_index = (*indices_)[i_point]; 16 point_residual[i_point].first = normals_->points[point_index].curvature; 17 point_residual[i_point].second = point_index; 18 } 19 std::sort (point_residual.begin (), point_residual.end (), comparePair); 20 } 21 else 22 { 23 for (int i_point = 0; i_point < num_of_pts; i_point++) 24 { 25 int point_index = (*indices_)[i_point]; 26 point_residual[i_point].first = 0; 27 point_residual[i_point].second = point_index; 28 } 29 } 30 int seed_counter = 0; 31 int seed = point_residual[seed_counter].second; 32 33 int segmented_pts_num = 0; 34 int number_of_segments = 0; 35 while (segmented_pts_num < num_of_pts) 36 { 37 int pts_in_segment; 38 pts_in_segment = growRegion (seed, number_of_segments); 39 segmented_pts_num += pts_in_segment; 40 num_pts_in_segment_.push_back (pts_in_segment); 41 number_of_segments++; 42 43 //find next point that is not segmented yet 44 for (int i_seed = seed_counter + 1; i_seed < num_of_pts; i_seed++) 45 { 46 int index = point_residual[i_seed].second; 47 if (point_labels_[index] == -1) 48 { 49 seed = index; 50 break; 51 } 52 } 53 } 54 }
区域生长的主要流程:
1 template <typename PointT, typename NormalT> int 2 pcl::RegionGrowing<PointT, NormalT>::growRegion (int initial_seed, int segment_number) 3 { 4 std::queue<int> seeds; 5 seeds.push (initial_seed); 6 point_labels_[initial_seed] = segment_number;//第几个生长的区域 7 8 int num_pts_in_segment = 1; 9 10 while (!seeds.empty ()) 11 { 12 int curr_seed; 13 curr_seed = seeds.front (); 14 seeds.pop (); 15 16 size_t i_nghbr = 0; 17 while ( i_nghbr < neighbour_number_ && i_nghbr < point_neighbours_[curr_seed].size () ) 18 { 19 int index = point_neighbours_[curr_seed][i_nghbr]; 20 if (point_labels_[index] != -1)//未标记 21 { 22 i_nghbr++; 23 continue; 24 } 25 26 bool is_a_seed = false; 27 //判断近邻是否属于当前的标记类,是否可以作为新的种子点 28 bool belongs_to_segment = validatePoint (initial_seed, curr_seed, index, is_a_seed); 29 30 if (belongs_to_segment == false) 31 { 32 i_nghbr++; 33 continue; 34 } 35 36 point_labels_[index] = segment_number;//当前近邻属于标记类 37 num_pts_in_segment++; 38 39 if (is_a_seed) 40 { 41 seeds.push (index);//加入新的种子点 42 } 43 44 i_nghbr++; 45 }// next neighbour 46 }// next seed 47 48 return (num_pts_in_segment); 49 }
作者:太一吾鱼水
文章未经说明均属原创,学习笔记可能有大段的引用,一般会注明参考文献。
欢迎大家留言交流,转载请注明出处。