Point Cloud Library (PCL) 1.15.1-dev
Loading...
Searching...
No Matches
region_growing_rgb.hpp
1/*
2 * Software License Agreement (BSD License)
3 *
4 * Point Cloud Library (PCL) - www.pointclouds.org
5 *
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer in the documentation and/or other materials provided
17 * with the distribution.
18 * * Neither the name of the copyright holder(s) nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * Author : Sergey Ushakov
36 * Email : mine_all_mine@bk.ru
37 *
38 */
39
40#ifndef PCL_SEGMENTATION_REGION_GROWING_RGB_HPP_
41#define PCL_SEGMENTATION_REGION_GROWING_RGB_HPP_
42
43#include <pcl/console/print.h> // for PCL_ERROR
44#include <pcl/segmentation/region_growing_rgb.h>
45#include <pcl/search/search.h>
46#include <pcl/search/auto.h> // for pcl::search::autoSelectMethod
47
48#include <queue>
49
50//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
51template <typename PointT, typename NormalT>
53 point_distances_ (0),
54 segment_neighbours_ (0),
55 segment_distances_ (0),
56 segment_labels_ (0)
57{
58 normal_flag_ = false;
59 curvature_flag_ = false;
60 residual_flag_ = false;
62}
63
64//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
65template <typename PointT, typename NormalT>
67{
68 point_distances_.clear ();
69 segment_neighbours_.clear ();
70 segment_distances_.clear ();
71 segment_labels_.clear ();
72}
73
74//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
75template <typename PointT, typename NormalT> float
77{
78 return (powf (color_p2p_threshold_, 0.5f));
79}
80
81//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
82template <typename PointT, typename NormalT> void
84{
85 color_p2p_threshold_ = thresh * thresh;
86}
87
88//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
89template <typename PointT, typename NormalT> float
91{
92 return (powf (color_r2r_threshold_, 0.5f));
93}
94
95//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
96template <typename PointT, typename NormalT> void
98{
99 color_r2r_threshold_ = thresh * thresh;
100}
101
102//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
103template <typename PointT, typename NormalT> float
105{
106 return (powf (distance_threshold_, 0.5f));
107}
108
109//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
110template <typename PointT, typename NormalT> void
112{
113 distance_threshold_ = thresh * thresh;
114}
115
116//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
117template <typename PointT, typename NormalT> unsigned int
119{
120 return (region_neighbour_number_);
121}
122
123//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
124template <typename PointT, typename NormalT> void
126{
127 region_neighbour_number_ = nghbr_number;
128}
129
130//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
131template <typename PointT, typename NormalT> bool
133{
134 return (normal_flag_);
135}
136
137//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
138template <typename PointT, typename NormalT> void
140{
141 normal_flag_ = value;
142}
143
144//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
145template <typename PointT, typename NormalT> void
147{
148 curvature_flag_ = value;
149}
150
151//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
152template <typename PointT, typename NormalT> void
154{
155 residual_flag_ = value;
156}
157
158//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
159template <typename PointT, typename NormalT> void
160pcl::RegionGrowingRGB<PointT, NormalT>::extract (std::vector <pcl::PointIndices>& clusters)
161{
162 clusters_.clear ();
163 clusters.clear ();
164 point_neighbours_.clear ();
165 point_labels_.clear ();
166 num_pts_in_segment_.clear ();
167 point_distances_.clear ();
168 segment_neighbours_.clear ();
169 segment_distances_.clear ();
170 segment_labels_.clear ();
171 number_of_segments_ = 0;
172
173 bool segmentation_is_possible = initCompute ();
174 if ( !segmentation_is_possible )
175 {
176 deinitCompute ();
177 return;
178 }
179
180 segmentation_is_possible = prepareForSegmentation ();
181 if ( !segmentation_is_possible )
182 {
183 deinitCompute ();
184 return;
185 }
186
187 findPointNeighbours ();
188 applySmoothRegionGrowingAlgorithm ();
190
191 findSegmentNeighbours ();
192 applyRegionMergingAlgorithm ();
193
194 auto cluster_iter = clusters_.begin ();
195 while (cluster_iter != clusters_.end ())
196 {
197 if (cluster_iter->indices.size () < min_pts_per_cluster_ ||
198 cluster_iter->indices.size () > max_pts_per_cluster_)
199 {
200 cluster_iter = clusters_.erase (cluster_iter);
201 }
202 else
203 ++cluster_iter;
204 }
205
206 clusters.reserve (clusters_.size ());
207 std::copy (clusters_.cbegin (), clusters_.cend (), std::back_inserter (clusters));
208
209 deinitCompute ();
210}
211
212//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
213template <typename PointT, typename NormalT> bool
215{
216 // if user forgot to pass point cloud or if it is empty
217 if ( input_->points.empty () )
218 return (false);
219
220 // if normal/smoothness test is on then we need to check if all needed variables and parameters
221 // were correctly initialized
222 if (normal_flag_)
223 {
224 // if user forgot to pass normals or the sizes of point and normal cloud are different
225 if ( !normals_ || input_->size () != normals_->size () )
226 return (false);
227 }
228
229 // if residual test is on then we need to check if all needed parameters were correctly initialized
230 if (residual_flag_)
231 {
232 if (residual_threshold_ <= 0.0f)
233 return (false);
234 }
235
236 // if curvature test is on ...
237 // if (curvature_flag_)
238 // {
239 // in this case we do not need to check anything that related to it
240 // so we simply commented it
241 // }
242
243 // here we check the parameters related to color-based segmentation
244 if ( region_neighbour_number_ == 0 || color_p2p_threshold_ < 0.0f || color_r2r_threshold_ < 0.0f || distance_threshold_ < 0.0f )
245 return (false);
246
247 // from here we check those parameters that are always valuable
248 if (neighbour_number_ == 0)
249 return (false);
250
251 if (indices_)
252 {
253 if (indices_->empty ())
254 PCL_ERROR ("[pcl::RegionGrowingRGB::prepareForSegmentation] Empty given indices!\n");
255 if (!search_)
256 search_.reset (pcl::search::autoSelectMethod<PointT>(input_, indices_, true, pcl::search::Purpose::many_knn_search));
257 else
258 search_->setInputCloud (input_, indices_);
259 }
260 else
261 {
262 if (!search_)
263 search_.reset (pcl::search::autoSelectMethod<PointT>(input_, true, pcl::search::Purpose::many_knn_search));
264 else
265 search_->setInputCloud (input_);
266 }
267
268 return (true);
269}
270
271//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
272template <typename PointT, typename NormalT> void
274{
275 pcl::Indices neighbours;
276 std::vector<float> distances;
277
278 point_neighbours_.resize (input_->size (), neighbours);
279 point_distances_.resize (input_->size (), distances);
280
281 for (const auto& point_index: (*indices_))
282 {
283 neighbours.clear ();
284 distances.clear ();
285 search_->nearestKSearch ((*input_)[point_index], region_neighbour_number_, neighbours, distances);
286 point_neighbours_[point_index].swap (neighbours);
287 point_distances_[point_index].swap (distances);
288 }
289}
290
291//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
292template <typename PointT, typename NormalT> void
294{
295 pcl::Indices neighbours;
296 std::vector<float> distances;
297 segment_neighbours_.resize (number_of_segments_, neighbours);
298 segment_distances_.resize (number_of_segments_, distances);
299
300 for (int i_seg = 0; i_seg < number_of_segments_; i_seg++)
301 {
302 pcl::Indices nghbrs;
303 std::vector<float> dist;
304 findRegionsKNN (i_seg, region_neighbour_number_, nghbrs, dist);
305 segment_neighbours_[i_seg].swap (nghbrs);
306 segment_distances_[i_seg].swap (dist);
307 }
308}
309
310//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
311template <typename PointT,typename NormalT> void
313{
314 std::vector<float> distances;
315 float max_dist = std::numeric_limits<float>::max ();
316 distances.resize (clusters_.size (), max_dist);
317
318 const auto number_of_points = num_pts_in_segment_[index];
319 //loop through every point in this segment and check neighbours
320 for (pcl::uindex_t i_point = 0; i_point < number_of_points; i_point++)
321 {
322 const auto point_index = clusters_[index].indices[i_point];
323 const auto number_of_neighbours = point_neighbours_[point_index].size ();
324 //loop through every neighbour of the current point, find out to which segment it belongs
325 //and if it belongs to neighbouring segment and is close enough then remember segment and its distance
326 for (std::size_t i_nghbr = 0; i_nghbr < number_of_neighbours; i_nghbr++)
327 {
328 // find segment
329 const pcl::index_t segment_index = point_labels_[ point_neighbours_[point_index][i_nghbr] ];
330
331 if ( segment_index != index )
332 {
333 // try to push it to the queue
334 if (distances[segment_index] > point_distances_[point_index][i_nghbr])
335 distances[segment_index] = point_distances_[point_index][i_nghbr];
336 }
337 }
338 }// next point
339
340 std::priority_queue<std::pair<float, int> > segment_neighbours;
341 for (int i_seg = 0; i_seg < number_of_segments_; i_seg++)
342 {
343 if (distances[i_seg] < max_dist)
344 {
345 segment_neighbours.emplace (distances[i_seg], i_seg);
346 if (segment_neighbours.size () > nghbr_number)
347 segment_neighbours.pop ();
348 }
349 }
350
351 const std::size_t size = std::min<std::size_t> (segment_neighbours.size (), static_cast<std::size_t>(nghbr_number));
352 nghbrs.resize (size, 0);
353 dist.resize (size, 0);
354 pcl::uindex_t counter = 0;
355 while ( !segment_neighbours.empty () && counter < nghbr_number )
356 {
357 dist[counter] = segment_neighbours.top ().first;
358 nghbrs[counter] = segment_neighbours.top ().second;
359 segment_neighbours.pop ();
360 counter++;
361 }
362}
363
364//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
365template <typename PointT, typename NormalT> void
367{
368 // calculate color of each segment
369 std::vector< std::vector<unsigned int> > segment_color;
370 std::vector<unsigned int> color;
371 color.resize (3, 0);
372 segment_color.resize (number_of_segments_, color);
373
374 for (const auto& point_index : (*indices_))
375 {
376 int segment_index = point_labels_[point_index];
377 segment_color[segment_index][0] += (*input_)[point_index].r;
378 segment_color[segment_index][1] += (*input_)[point_index].g;
379 segment_color[segment_index][2] += (*input_)[point_index].b;
380 }
381 for (int i_seg = 0; i_seg < number_of_segments_; i_seg++)
382 {
383 segment_color[i_seg][0] = static_cast<unsigned int> (static_cast<float> (segment_color[i_seg][0]) / static_cast<float> (num_pts_in_segment_[i_seg]));
384 segment_color[i_seg][1] = static_cast<unsigned int> (static_cast<float> (segment_color[i_seg][1]) / static_cast<float> (num_pts_in_segment_[i_seg]));
385 segment_color[i_seg][2] = static_cast<unsigned int> (static_cast<float> (segment_color[i_seg][2]) / static_cast<float> (num_pts_in_segment_[i_seg]));
386 }
387
388 // now it is time to find out if there are segments with a similar color
389 // and merge them together
390 std::vector<unsigned int> num_pts_in_homogeneous_region;
391 std::vector<int> num_seg_in_homogeneous_region;
392
393 segment_labels_.resize (number_of_segments_, -1);
394
395 float dist_thresh = distance_threshold_;
396 int homogeneous_region_number = 0;
397 for (int i_seg = 0; i_seg < number_of_segments_; i_seg++)
398 {
399 int curr_homogeneous_region = 0;
400 if (segment_labels_[i_seg] == -1)
401 {
402 segment_labels_[i_seg] = homogeneous_region_number;
403 curr_homogeneous_region = homogeneous_region_number;
404 num_pts_in_homogeneous_region.push_back (num_pts_in_segment_[i_seg]);
405 num_seg_in_homogeneous_region.push_back (1);
406 homogeneous_region_number++;
407 }
408 else
409 curr_homogeneous_region = segment_labels_[i_seg];
410
411 unsigned int i_nghbr = 0;
412 while ( i_nghbr < region_neighbour_number_ && i_nghbr < segment_neighbours_[i_seg].size () )
413 {
414 int index = segment_neighbours_[i_seg][i_nghbr];
415 if (segment_distances_[i_seg][i_nghbr] > dist_thresh)
416 {
417 i_nghbr++;
418 continue;
419 }
420 if ( segment_labels_[index] == -1 )
421 {
422 float difference = calculateColorimetricalDifference (segment_color[i_seg], segment_color[index]);
423 if (difference < color_r2r_threshold_)
424 {
425 segment_labels_[index] = curr_homogeneous_region;
426 num_pts_in_homogeneous_region[curr_homogeneous_region] += num_pts_in_segment_[index];
427 num_seg_in_homogeneous_region[curr_homogeneous_region] += 1;
428 }
429 }
430 i_nghbr++;
431 }// next neighbour
432 }// next segment
433
434 segment_color.clear ();
435 color.clear ();
436
437 std::vector< std::vector<int> > final_segments;
438 std::vector<int> region;
439 final_segments.resize (homogeneous_region_number, region);
440 for (int i_reg = 0; i_reg < homogeneous_region_number; i_reg++)
441 {
442 final_segments[i_reg].resize (num_seg_in_homogeneous_region[i_reg], 0);
443 }
444
445 std::vector<int> counter;
446 counter.resize (homogeneous_region_number, 0);
447 for (int i_seg = 0; i_seg < number_of_segments_; i_seg++)
448 {
449 int index = segment_labels_[i_seg];
450 final_segments[ index ][ counter[index] ] = i_seg;
451 counter[index] += 1;
452 }
453
454 std::vector< std::vector< std::pair<float, pcl::index_t> > > region_neighbours;
455 findRegionNeighbours (region_neighbours, final_segments);
456
457 int final_segment_number = homogeneous_region_number;
458 for (int i_reg = 0; i_reg < homogeneous_region_number; i_reg++)
459 {
460 if (num_pts_in_homogeneous_region[i_reg] < min_pts_per_cluster_)
461 {
462 if ( region_neighbours[i_reg].empty () )
463 continue;
464 int nearest_neighbour = region_neighbours[i_reg][0].second;
465 if ( region_neighbours[i_reg][0].first == std::numeric_limits<float>::max () )
466 continue;
467 int reg_index = segment_labels_[nearest_neighbour];
468 int num_seg_in_reg = num_seg_in_homogeneous_region[i_reg];
469 for (int i_seg = 0; i_seg < num_seg_in_reg; i_seg++)
470 {
471 int segment_index = final_segments[i_reg][i_seg];
472 final_segments[reg_index].push_back (segment_index);
473 segment_labels_[segment_index] = reg_index;
474 }
475 final_segments[i_reg].clear ();
476 num_pts_in_homogeneous_region[reg_index] += num_pts_in_homogeneous_region[i_reg];
477 num_pts_in_homogeneous_region[i_reg] = 0;
478 num_seg_in_homogeneous_region[reg_index] += num_seg_in_homogeneous_region[i_reg];
479 num_seg_in_homogeneous_region[i_reg] = 0;
480 final_segment_number -= 1;
481
482 const auto filtered_region_neighbours_reg_index_end = std::remove_if (
483 region_neighbours[reg_index].begin (),
484 region_neighbours[reg_index].end (),
485 [this, reg_index] (const auto& nghbr) { return segment_labels_[ nghbr.second ] == reg_index; });
486 const auto filtered_region_neighbours_reg_index_size = std::distance (
487 region_neighbours[reg_index].begin (), filtered_region_neighbours_reg_index_end);
488 region_neighbours[reg_index].resize (filtered_region_neighbours_reg_index_size);
489
490 for (const auto& nghbr : region_neighbours[i_reg])
491 {
492 if ( segment_labels_[ nghbr.second ] != reg_index )
493 {
494 region_neighbours[reg_index].push_back (nghbr);
495 }
496 }
497 region_neighbours[i_reg].clear ();
498 std::inplace_merge (
499 region_neighbours[reg_index].begin (),
500 std::next (region_neighbours[reg_index].begin (), filtered_region_neighbours_reg_index_size),
501 region_neighbours[reg_index].end (),
503 }
504 }
505
506 assembleRegions (num_pts_in_homogeneous_region, static_cast<int> (num_pts_in_homogeneous_region.size ()));
507
508 number_of_segments_ = final_segment_number;
509}
510
511//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
512template <typename PointT, typename NormalT> float
513pcl::RegionGrowingRGB<PointT, NormalT>::calculateColorimetricalDifference (std::vector<unsigned int>& first_color, std::vector<unsigned int>& second_color) const
514{
515 float difference = 0.0f;
516 difference += static_cast<float>((first_color[0] - second_color[0]) * (first_color[0] - second_color[0]));
517 difference += static_cast<float>((first_color[1] - second_color[1]) * (first_color[1] - second_color[1]));
518 difference += static_cast<float>((first_color[2] - second_color[2]) * (first_color[2] - second_color[2]));
519 return (difference);
520}
521
522//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
523template <typename PointT, typename NormalT> void
524pcl::RegionGrowingRGB<PointT, NormalT>::findRegionNeighbours (std::vector< std::vector< std::pair<float, pcl::index_t> > >& neighbours_out, std::vector< std::vector<int> >& regions_in)
525{
526 int region_number = static_cast<int> (regions_in.size ());
527 neighbours_out.clear ();
528 neighbours_out.resize (region_number);
529
530 for (int i_reg = 0; i_reg < region_number; i_reg++)
531 {
532 neighbours_out[i_reg].reserve (regions_in[i_reg].size () * region_neighbour_number_);
533 for (const auto& curr_segment : regions_in[i_reg])
534 {
535 const std::size_t nghbr_number = segment_neighbours_[curr_segment].size ();
536 std::pair<float, pcl::index_t> pair;
537 for (std::size_t i_nghbr = 0; i_nghbr < nghbr_number; i_nghbr++)
538 {
539 const auto segment_index = segment_neighbours_[curr_segment][i_nghbr];
540 if ( segment_distances_[curr_segment][i_nghbr] == std::numeric_limits<float>::max () )
541 continue;
542 if (segment_labels_[segment_index] != i_reg)
543 {
544 pair.first = segment_distances_[curr_segment][i_nghbr];
545 pair.second = segment_index;
546 neighbours_out[i_reg].push_back (pair);
547 }
548 }// next neighbour
549 }// next segment
550 std::sort (neighbours_out[i_reg].begin (), neighbours_out[i_reg].end (), comparePair);
551 }// next homogeneous region
552}
553
554//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
555template <typename PointT, typename NormalT> void
556pcl::RegionGrowingRGB<PointT, NormalT>::assembleRegions (std::vector<unsigned int>& num_pts_in_region, int num_regions)
557{
558 clusters_.clear ();
559 pcl::PointIndices segment;
560 clusters_.resize (num_regions, segment);
561 for (int i_seg = 0; i_seg < num_regions; i_seg++)
562 {
563 clusters_[i_seg].indices.resize (num_pts_in_region[i_seg]);
564 }
565
566 std::vector<int> counter;
567 counter.resize (num_regions, 0);
568 for (const auto& point_index : (*indices_))
569 {
570 int index = point_labels_[point_index];
571 index = segment_labels_[index];
572 clusters_[index].indices[ counter[index] ] = point_index;
573 counter[index] += 1;
574 }
575
576 // now we need to erase empty regions
577 if (clusters_.empty ())
578 return;
579
580 std::vector<pcl::PointIndices>::iterator itr1, itr2;
581 itr1 = clusters_.begin ();
582 itr2 = clusters_.end () - 1;
583
584 while (itr1 < itr2)
585 {
586 while (!(itr1->indices.empty ()) && itr1 < itr2)
587 ++itr1;
588 while ( itr2->indices.empty () && itr1 < itr2)
589 --itr2;
590
591 if (itr1 != itr2)
592 itr1->indices.swap (itr2->indices);
593 }
594
595 if (itr2->indices.empty ())
596 clusters_.erase (itr2, clusters_.end ());
597}
598
599//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
600template <typename PointT, typename NormalT> bool
602{
603 is_a_seed = true;
604
605 // check the color difference
606 std::vector<unsigned int> point_color;
607 point_color.resize (3, 0);
608 std::vector<unsigned int> nghbr_color;
609 nghbr_color.resize (3, 0);
610 point_color[0] = (*input_)[point].r;
611 point_color[1] = (*input_)[point].g;
612 point_color[2] = (*input_)[point].b;
613 nghbr_color[0] = (*input_)[nghbr].r;
614 nghbr_color[1] = (*input_)[nghbr].g;
615 nghbr_color[2] = (*input_)[nghbr].b;
616 float difference = calculateColorimetricalDifference (point_color, nghbr_color);
617 if (difference > color_p2p_threshold_)
618 return (false);
619
620 float cosine_threshold = std::cos (theta_threshold_);
621
622 // check the angle between normals if needed
623 if (normal_flag_)
624 {
625 float data[4];
626 data[0] = (*input_)[point].data[0];
627 data[1] = (*input_)[point].data[1];
628 data[2] = (*input_)[point].data[2];
629 data[3] = (*input_)[point].data[3];
630
631 Eigen::Map<Eigen::Vector3f> initial_point (static_cast<float*> (data));
632 Eigen::Map<Eigen::Vector3f> initial_normal (static_cast<float*> ((*normals_)[point].normal));
633 if (smooth_mode_flag_ == true)
634 {
635 Eigen::Map<Eigen::Vector3f> nghbr_normal (static_cast<float*> ((*normals_)[nghbr].normal));
636 float dot_product = std::abs (nghbr_normal.dot (initial_normal));
637 if (dot_product < cosine_threshold)
638 return (false);
639 }
640 else
641 {
642 Eigen::Map<Eigen::Vector3f> nghbr_normal (static_cast<float*> ((*normals_)[nghbr].normal));
643 Eigen::Map<Eigen::Vector3f> initial_seed_normal (static_cast<float*> ((*normals_)[initial_seed].normal));
644 float dot_product = std::abs (nghbr_normal.dot (initial_seed_normal));
645 if (dot_product < cosine_threshold)
646 return (false);
647 }
648 }
649
650 // check the curvature if needed
651 if (curvature_flag_ && (*normals_)[nghbr].curvature > curvature_threshold_)
652 is_a_seed = false;
653
654 // check the residual if needed
655 if (residual_flag_)
656 {
657 float data_p[4];
658 data_p[0] = (*input_)[point].data[0];
659 data_p[1] = (*input_)[point].data[1];
660 data_p[2] = (*input_)[point].data[2];
661 data_p[3] = (*input_)[point].data[3];
662 float data_n[4];
663 data_n[0] = (*input_)[nghbr].data[0];
664 data_n[1] = (*input_)[nghbr].data[1];
665 data_n[2] = (*input_)[nghbr].data[2];
666 data_n[3] = (*input_)[nghbr].data[3];
667 Eigen::Map<Eigen::Vector3f> nghbr_point (static_cast<float*> (data_n));
668 Eigen::Map<Eigen::Vector3f> initial_point (static_cast<float*> (data_p));
669 Eigen::Map<Eigen::Vector3f> initial_normal (static_cast<float*> ((*normals_)[point].normal));
670 float residual = std::abs (initial_normal.dot (initial_point - nghbr_point));
671 if (residual > residual_threshold_)
672 is_a_seed = false;
673 }
674
675 return (true);
676}
677
678//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
679template <typename PointT, typename NormalT> void
681{
682 cluster.indices.clear ();
683
684 bool segmentation_is_possible = initCompute ();
685 if ( !segmentation_is_possible )
686 {
687 deinitCompute ();
688 return;
689 }
690
691 // first of all we need to find out if this point belongs to cloud
692 bool point_was_found = false;
693 for (const auto& point : (*indices_))
694 if (point == index)
695 {
696 point_was_found = true;
697 break;
698 }
699
700 if (point_was_found)
701 {
702 if (clusters_.empty ())
703 {
704 clusters_.clear ();
705 point_neighbours_.clear ();
706 point_labels_.clear ();
707 num_pts_in_segment_.clear ();
708 point_distances_.clear ();
709 segment_neighbours_.clear ();
710 segment_distances_.clear ();
711 segment_labels_.clear ();
712 number_of_segments_ = 0;
713
714 segmentation_is_possible = prepareForSegmentation ();
715 if ( !segmentation_is_possible )
716 {
717 deinitCompute ();
718 return;
719 }
720
721 findPointNeighbours ();
722 applySmoothRegionGrowingAlgorithm ();
724
725 findSegmentNeighbours ();
726 applyRegionMergingAlgorithm ();
727 }
728 // if we have already made the segmentation, then find the segment
729 // to which this point belongs
730 for (const auto& i_segment : clusters_)
731 {
732 const auto it = std::find (i_segment.indices.cbegin (), i_segment.indices.cend (), index);
733 if (it != i_segment.indices.cend())
734 {
735 // if segment was found
736 cluster.indices.clear ();
737 cluster.indices.reserve (i_segment.indices.size ());
738 std::copy (i_segment.indices.begin (), i_segment.indices.end (), std::back_inserter (cluster.indices));
739 break;
740 }
741 }// next segment
742 }// end if point was found
743
744 deinitCompute ();
745}
746
747#endif // PCL_SEGMENTATION_REGION_GROWING_RGB_HPP_
bool curvature_flag_
If set to true then curvature test will be done during segmentation.
bool normal_flag_
If set to true then normal/smoothness test will be done during segmentation.
bool residual_flag_
If set to true then residual test will be done during segmentation.
pcl::uindex_t min_pts_per_cluster_
Stores the minimum number of points that a cluster needs to contain in order to be considered valid.
void assembleRegions()
This function simply assembles the regions from list of point labels.
void getSegmentFromPoint(index_t index, pcl::PointIndices &cluster) override
For a given point this function builds a segment to which it belongs and returns this segment.
void setDistanceThreshold(float thresh)
Allows to set distance threshold.
void setRegionColorThreshold(float thresh)
This method specifies the threshold value for color test between the regions.
float getPointColorThreshold() const
Returns the color threshold value used for testing if points belong to the same region.
bool prepareForSegmentation() override
This method simply checks if it is possible to execute the segmentation algorithm with the current se...
void findRegionNeighbours(std::vector< std::vector< std::pair< float, pcl::index_t > > > &neighbours_out, std::vector< std::vector< int > > &regions_in)
This method assembles the array containing neighbours of each homogeneous region.
void applyRegionMergingAlgorithm()
This function implements the merging algorithm described in the article "Color-based segmentation of ...
unsigned int getNumberOfRegionNeighbours() const
Returns the number of nearest neighbours used for searching K nearest segments.
void setCurvatureTestFlag(bool value) override
Allows to turn on/off the curvature test.
void extract(std::vector< pcl::PointIndices > &clusters) override
This method launches the segmentation algorithm and returns the clusters that were obtained during th...
void setNormalTestFlag(bool value)
Allows to turn on/off the smoothness test.
void setNumberOfRegionNeighbours(unsigned int nghbr_number)
This method allows to set the number of neighbours that is used for finding neighbouring segments.
float calculateColorimetricalDifference(std::vector< unsigned int > &first_color, std::vector< unsigned int > &second_color) const
This method calculates the colorimetrical difference between two points.
float getDistanceThreshold() const
Returns the distance threshold.
bool getNormalTestFlag() const
Returns the flag that signalize if the smoothness test is turned on/off.
void findRegionsKNN(pcl::index_t index, pcl::uindex_t nghbr_number, Indices &nghbrs, std::vector< float > &dist)
This method finds K nearest neighbours of the given segment.
RegionGrowingRGB()
Constructor that sets default values for member variables.
void setResidualTestFlag(bool value) override
Allows to turn on/off the residual test.
~RegionGrowingRGB() override
Destructor that frees memory.
void findPointNeighbours() override
This method finds KNN for each point and saves them to the array because the algorithm needs to find ...
float getRegionColorThreshold() const
Returns the color threshold value used for testing if regions can be merged.
void findSegmentNeighbours()
This method simply calls the findRegionsKNN for each segment and saves the results for later use.
void setPointColorThreshold(float thresh)
This method specifies the threshold value for color test between the points.
bool validatePoint(index_t initial_seed, index_t point, index_t nghbr, bool &is_a_seed) const override
This function is checking if the point with index 'nghbr' belongs to the segment.
@ many_knn_search
The search method will mainly be used for nearestKSearch where k is larger than 1.
detail::int_type_t< detail::index_type_size, false > uindex_t
Type used for an unsigned index in PCL.
Definition types.h:120
bool comparePair(std::pair< float, int > i, std::pair< float, int > j)
This function is used as a comparator for sorting.
detail::int_type_t< detail::index_type_size, detail::index_type_signed > index_t
Type used for an index in PCL.
Definition types.h:112
IndicesAllocator<> Indices
Type used for indices in PCL.
Definition types.h:133