[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 }

 

posted @ 2016-09-29 15:02  太一吾鱼水  阅读(6923)  评论(0编辑  收藏  举报