40 #include <pcl/recognition/quantizable_modality.h>
42 #include <pcl/pcl_base.h>
43 #include <pcl/point_cloud.h>
45 #include <pcl/recognition/point_types.h>
46 #include <pcl/filters/convolution.h>
56 template <
typename Po
intInT>
106 gradient_magnitude_threshold_ = threshold;
116 gradient_magnitude_threshold_feature_extraction_ = threshold;
125 feature_selection_method_ = method;
132 spreading_size_ = spreading_size;
141 variable_feature_nr_ = enabled;
148 return (filtered_quantized_color_gradients_);
155 return (spreaded_filtered_quantized_color_gradients_);
162 return (color_gradients_);
174 std::vector<QuantizedMultiModFeature> & features)
const override;
184 std::vector<QuantizedMultiModFeature> & features)
const override;
211 computeGaussianKernel (
const std::size_t kernel_size,
const float sigma, std::vector <float> & kernel_values);
243 bool variable_feature_nr_;
252 float gradient_magnitude_threshold_;
254 float gradient_magnitude_threshold_feature_extraction_;
260 std::size_t spreading_size_;
274 template <
typename Po
intInT>
277 : variable_feature_nr_ (false)
279 , feature_selection_method_ (DISTANCE_MAGNITUDE_SCORE)
280 , gradient_magnitude_threshold_ (10.0f)
281 , gradient_magnitude_threshold_feature_extraction_ (55.0f)
282 , spreading_size_ (8)
287 template <
typename Po
intInT>
294 template <
typename Po
intInT>
void
299 const int n = int (kernel_size);
300 const int SMALL_GAUSSIAN_SIZE = 7;
301 static const float small_gaussian_tab[][SMALL_GAUSSIAN_SIZE] =
304 {0.25f, 0.5f, 0.25f},
305 {0.0625f, 0.25f, 0.375f, 0.25f, 0.0625f},
306 {0.03125f, 0.109375f, 0.21875f, 0.28125f, 0.21875f, 0.109375f, 0.03125f}
309 const float* fixed_kernel = n % 2 == 1 && n <= SMALL_GAUSSIAN_SIZE && sigma <= 0 ?
310 small_gaussian_tab[n>>1] :
nullptr;
314 kernel_values.resize (n);
315 float* cf = &(kernel_values[0]);
318 double sigmaX = sigma > 0 ? sigma : ((n-1)*0.5 - 1)*0.3 + 0.8;
319 double scale2X = -0.5/(sigmaX*sigmaX);
322 for(
int i = 0; i < n; i++ )
324 double x = i - (n-1)*0.5;
325 double t = fixed_kernel ? double (fixed_kernel[i]) : std::exp (scale2X*x*x);
332 for (
int i = 0; i < n; i++ )
334 cf[i] = float (cf[i]*sum);
339 template <
typename Po
intInT>
345 const std::size_t kernel_size = 7;
346 std::vector<float> kernel_values;
347 computeGaussianKernel (kernel_size, 0.0f, kernel_values);
351 Eigen::ArrayXf gaussian_kernel(kernel_size);
354 gaussian_kernel << kernel_values[0], kernel_values[1], kernel_values[2], kernel_values[3], kernel_values[4], kernel_values[5], kernel_values[6];
358 const std::uint32_t width = input_->width;
359 const std::uint32_t height = input_->height;
361 rgb_input_->
resize (width*height);
362 rgb_input_->
width = width;
363 rgb_input_->
height = height;
364 rgb_input_->
is_dense = input_->is_dense;
365 for (std::size_t row_index = 0; row_index < height; ++row_index)
367 for (std::size_t col_index = 0; col_index < width; ++col_index)
369 (*rgb_input_) (col_index, row_index).r = (*input_) (col_index, row_index).r;
370 (*rgb_input_) (col_index, row_index).g = (*input_) (col_index, row_index).g;
371 (*rgb_input_) (col_index, row_index).b = (*input_) (col_index, row_index).b;
378 convolution.
convolve (*smoothed_input_);
381 computeMaxColorGradientsSobel (smoothed_input_);
384 quantizeColorGradients ();
387 filterQuantizedColorGradients ();
392 spreaded_filtered_quantized_color_gradients_,
397 template <
typename Po
intInT>
405 spreaded_filtered_quantized_color_gradients_,
410 template <
typename Po
intInT>
413 std::vector<QuantizedMultiModFeature> & features)
const
415 const std::size_t width = mask.
getWidth ();
416 const std::size_t height = mask.
getHeight ();
418 std::list<Candidate> list1;
419 std::list<Candidate> list2;
422 if (feature_selection_method_ == DISTANCE_MAGNITUDE_SCORE)
424 for (std::size_t row_index = 0; row_index < height; ++row_index)
426 for (std::size_t col_index = 0; col_index < width; ++col_index)
428 if (mask (col_index, row_index) != 0)
430 const GradientXY & gradient = color_gradients_ (col_index, row_index);
431 if (gradient.
magnitude > gradient_magnitude_threshold_feature_extraction_
432 && filtered_quantized_color_gradients_ (col_index, row_index) != 0)
435 candidate.gradient = gradient;
436 candidate.
x =
static_cast<int> (col_index);
437 candidate.y =
static_cast<int> (row_index);
439 list1.push_back (candidate);
447 if (variable_feature_nr_)
449 list2.push_back (*(list1.begin ()));
451 bool feature_selection_finished =
false;
452 while (!feature_selection_finished)
454 float best_score = 0.0f;
455 typename std::list<Candidate>::iterator best_iter = list1.end ();
456 for (
typename std::list<Candidate>::iterator iter1 = list1.begin (); iter1 != list1.end (); ++iter1)
459 float smallest_distance = std::numeric_limits<float>::max ();
460 for (
typename std::list<Candidate>::iterator iter2 = list2.begin (); iter2 != list2.end (); ++iter2)
462 const float dx =
static_cast<float> (iter1->x) -
static_cast<float> (iter2->x);
463 const float dy =
static_cast<float> (iter1->y) -
static_cast<float> (iter2->y);
465 const float distance = dx*dx + dy*dy;
473 const float score = smallest_distance * iter1->gradient.magnitude;
475 if (score > best_score)
483 float min_min_sqr_distance = std::numeric_limits<float>::max ();
484 float max_min_sqr_distance = 0;
485 for (
typename std::list<Candidate>::iterator iter2 = list2.begin (); iter2 != list2.end (); ++iter2)
487 float min_sqr_distance = std::numeric_limits<float>::max ();
488 for (
typename std::list<Candidate>::iterator iter3 = list2.begin (); iter3 != list2.end (); ++iter3)
493 const float dx =
static_cast<float> (iter2->x) -
static_cast<float> (iter3->x);
494 const float dy =
static_cast<float> (iter2->y) -
static_cast<float> (iter3->y);
496 const float sqr_distance = dx*dx + dy*dy;
498 if (sqr_distance < min_sqr_distance)
500 min_sqr_distance = sqr_distance;
509 const float dx =
static_cast<float> (iter2->x) -
static_cast<float> (best_iter->x);
510 const float dy =
static_cast<float> (iter2->y) -
static_cast<float> (best_iter->y);
512 const float sqr_distance = dx*dx + dy*dy;
514 if (sqr_distance < min_sqr_distance)
516 min_sqr_distance = sqr_distance;
520 if (min_sqr_distance < min_min_sqr_distance)
521 min_min_sqr_distance = min_sqr_distance;
522 if (min_sqr_distance > max_min_sqr_distance)
523 max_min_sqr_distance = min_sqr_distance;
528 if (best_iter != list1.end ())
534 if (min_min_sqr_distance < 50)
536 feature_selection_finished =
true;
540 list2.push_back (*best_iter);
546 if (list1.size () <= nr_features)
548 for (
typename std::list<Candidate>::iterator iter1 = list1.begin (); iter1 != list1.end (); ++iter1)
552 feature.
x = iter1->x;
553 feature.
y = iter1->y;
555 feature.
quantized_value = filtered_quantized_color_gradients_ (iter1->x, iter1->y);
557 features.push_back (feature);
562 list2.push_back (*(list1.begin ()));
563 while (list2.size () != nr_features)
565 float best_score = 0.0f;
566 typename std::list<Candidate>::iterator best_iter = list1.end ();
567 for (
typename std::list<Candidate>::iterator iter1 = list1.begin (); iter1 != list1.end (); ++iter1)
570 float smallest_distance = std::numeric_limits<float>::max ();
571 for (
typename std::list<Candidate>::iterator iter2 = list2.begin (); iter2 != list2.end (); ++iter2)
573 const float dx =
static_cast<float> (iter1->x) -
static_cast<float> (iter2->x);
574 const float dy =
static_cast<float> (iter1->y) -
static_cast<float> (iter2->y);
576 const float distance = dx*dx + dy*dy;
584 const float score = smallest_distance * iter1->gradient.magnitude;
586 if (score > best_score)
593 if (best_iter != list1.end ())
595 list2.push_back (*best_iter);
604 else if (feature_selection_method_ == MASK_BORDER_HIGH_GRADIENTS || feature_selection_method_ == MASK_BORDER_EQUALLY)
607 erode (mask, eroded_mask);
609 auto diff_mask = MaskMap::getDifferenceMask (mask, eroded_mask);
611 for (std::size_t row_index = 0; row_index < height; ++row_index)
613 for (std::size_t col_index = 0; col_index < width; ++col_index)
615 if (diff_mask (col_index, row_index) != 0)
617 const GradientXY & gradient = color_gradients_ (col_index, row_index);
618 if ((feature_selection_method_ == MASK_BORDER_EQUALLY || gradient.
magnitude > gradient_magnitude_threshold_feature_extraction_)
619 && filtered_quantized_color_gradients_ (col_index, row_index) != 0)
622 candidate.gradient = gradient;
623 candidate.
x =
static_cast<int> (col_index);
624 candidate.y =
static_cast<int> (row_index);
626 list1.push_back (candidate);
634 if (list1.size () <= nr_features)
636 for (
typename std::list<Candidate>::iterator iter1 = list1.begin (); iter1 != list1.end (); ++iter1)
640 feature.
x = iter1->x;
641 feature.
y = iter1->y;
643 feature.
quantized_value = filtered_quantized_color_gradients_ (iter1->x, iter1->y);
645 features.push_back (feature);
650 std::size_t
distance = list1.size () / nr_features + 1;
651 while (list2.size () != nr_features)
654 for (
typename std::list<Candidate>::iterator iter1 = list1.begin (); iter1 != list1.end (); ++iter1)
656 bool candidate_accepted =
true;
658 for (
typename std::list<Candidate>::iterator iter2 = list2.begin (); iter2 != list2.end (); ++iter2)
660 const int dx = iter1->x - iter2->x;
661 const int dy = iter1->y - iter2->y;
662 const unsigned int tmp_distance = dx*dx + dy*dy;
665 if (tmp_distance < sqr_distance)
667 candidate_accepted =
false;
672 if (candidate_accepted)
673 list2.push_back (*iter1);
675 if (list2.size () == nr_features)
682 for (
typename std::list<Candidate>::iterator iter2 = list2.begin (); iter2 != list2.end (); ++iter2)
686 feature.
x = iter2->x;
687 feature.
y = iter2->y;
689 feature.
quantized_value = filtered_quantized_color_gradients_ (iter2->x, iter2->y);
691 features.push_back (feature);
696 template <
typename Po
intInT>
void
699 std::vector<QuantizedMultiModFeature> & features)
const
701 const std::size_t width = mask.
getWidth ();
702 const std::size_t height = mask.
getHeight ();
704 std::list<Candidate> list1;
705 std::list<Candidate> list2;
708 for (std::size_t row_index = 0; row_index < height; ++row_index)
710 for (std::size_t col_index = 0; col_index < width; ++col_index)
712 if (mask (col_index, row_index) != 0)
714 const GradientXY & gradient = color_gradients_ (col_index, row_index);
715 if (gradient.
magnitude > gradient_magnitude_threshold_feature_extraction_
716 && filtered_quantized_color_gradients_ (col_index, row_index) != 0)
719 candidate.gradient = gradient;
720 candidate.
x =
static_cast<int> (col_index);
721 candidate.y =
static_cast<int> (row_index);
723 list1.push_back (candidate);
731 for (
typename std::list<Candidate>::iterator iter1 = list1.begin (); iter1 != list1.end (); ++iter1)
735 feature.
x = iter1->x;
736 feature.
y = iter1->y;
738 feature.
quantized_value = filtered_quantized_color_gradients_ (iter1->x, iter1->y);
740 features.push_back (feature);
745 template <
typename Po
intInT>
750 const int width = cloud->
width;
751 const int height = cloud->
height;
753 color_gradients_.resize (width*height);
754 color_gradients_.width = width;
755 color_gradients_.height = height;
757 const float pi = tan (1.0f) * 2;
758 for (
int row_index = 0; row_index < height-2; ++row_index)
760 for (
int col_index = 0; col_index < width-2; ++col_index)
762 const int index0 = row_index*width+col_index;
763 const int index_c = row_index*width+col_index+2;
764 const int index_r = (row_index+2)*width+col_index;
768 const unsigned char r0 = (*cloud)[index0].r;
769 const unsigned char g0 = (*cloud)[index0].g;
770 const unsigned char b0 = (*cloud)[index0].b;
772 const unsigned char r_c = (*cloud)[index_c].r;
773 const unsigned char g_c = (*cloud)[index_c].g;
774 const unsigned char b_c = (*cloud)[index_c].b;
776 const unsigned char r_r = (*cloud)[index_r].r;
777 const unsigned char g_r = (*cloud)[index_r].g;
778 const unsigned char b_r = (*cloud)[index_r].b;
780 const float r_dx =
static_cast<float> (r_c) -
static_cast<float> (r0);
781 const float g_dx =
static_cast<float> (g_c) -
static_cast<float> (g0);
782 const float b_dx =
static_cast<float> (b_c) -
static_cast<float> (b0);
784 const float r_dy =
static_cast<float> (r_r) -
static_cast<float> (r0);
785 const float g_dy =
static_cast<float> (g_r) -
static_cast<float> (g0);
786 const float b_dy =
static_cast<float> (b_r) -
static_cast<float> (b0);
788 const float sqr_mag_r = r_dx*r_dx + r_dy*r_dy;
789 const float sqr_mag_g = g_dx*g_dx + g_dy*g_dy;
790 const float sqr_mag_b = b_dx*b_dx + b_dy*b_dy;
792 if (sqr_mag_r > sqr_mag_g && sqr_mag_r > sqr_mag_b)
796 gradient.
angle = std::atan2 (r_dy, r_dx) * 180.0f / pi;
797 gradient.
x =
static_cast<float> (col_index);
798 gradient.
y =
static_cast<float> (row_index);
800 color_gradients_ (col_index+1, row_index+1) = gradient;
802 else if (sqr_mag_g > sqr_mag_b)
806 gradient.
angle = std::atan2 (g_dy, g_dx) * 180.0f / pi;
807 gradient.
x =
static_cast<float> (col_index);
808 gradient.
y =
static_cast<float> (row_index);
810 color_gradients_ (col_index+1, row_index+1) = gradient;
816 gradient.
angle = std::atan2 (b_dy, b_dx) * 180.0f / pi;
817 gradient.
x =
static_cast<float> (col_index);
818 gradient.
y =
static_cast<float> (row_index);
820 color_gradients_ (col_index+1, row_index+1) = gradient;
823 assert (color_gradients_ (col_index+1, row_index+1).angle >= -180 &&
824 color_gradients_ (col_index+1, row_index+1).angle <= 180);
832 template <
typename Po
intInT>
837 const int width = cloud->
width;
838 const int height = cloud->
height;
840 color_gradients_.resize (width*height);
841 color_gradients_.width = width;
842 color_gradients_.height = height;
844 const float pi = tanf (1.0f) * 2.0f;
845 for (
int row_index = 1; row_index < height-1; ++row_index)
847 for (
int col_index = 1; col_index < width-1; ++col_index)
849 const int r7 =
static_cast<int> ((*cloud)[(row_index-1)*width + (col_index-1)].r);
850 const int g7 =
static_cast<int> ((*cloud)[(row_index-1)*width + (col_index-1)].g);
851 const int b7 =
static_cast<int> ((*cloud)[(row_index-1)*width + (col_index-1)].b);
852 const int r8 =
static_cast<int> ((*cloud)[(row_index-1)*width + (col_index)].r);
853 const int g8 =
static_cast<int> ((*cloud)[(row_index-1)*width + (col_index)].g);
854 const int b8 =
static_cast<int> ((*cloud)[(row_index-1)*width + (col_index)].b);
855 const int r9 =
static_cast<int> ((*cloud)[(row_index-1)*width + (col_index+1)].r);
856 const int g9 =
static_cast<int> ((*cloud)[(row_index-1)*width + (col_index+1)].g);
857 const int b9 =
static_cast<int> ((*cloud)[(row_index-1)*width + (col_index+1)].b);
858 const int r4 =
static_cast<int> ((*cloud)[(row_index)*width + (col_index-1)].r);
859 const int g4 =
static_cast<int> ((*cloud)[(row_index)*width + (col_index-1)].g);
860 const int b4 =
static_cast<int> ((*cloud)[(row_index)*width + (col_index-1)].b);
861 const int r6 =
static_cast<int> ((*cloud)[(row_index)*width + (col_index+1)].r);
862 const int g6 =
static_cast<int> ((*cloud)[(row_index)*width + (col_index+1)].g);
863 const int b6 =
static_cast<int> ((*cloud)[(row_index)*width + (col_index+1)].b);
864 const int r1 =
static_cast<int> ((*cloud)[(row_index+1)*width + (col_index-1)].r);
865 const int g1 =
static_cast<int> ((*cloud)[(row_index+1)*width + (col_index-1)].g);
866 const int b1 =
static_cast<int> ((*cloud)[(row_index+1)*width + (col_index-1)].b);
867 const int r2 =
static_cast<int> ((*cloud)[(row_index+1)*width + (col_index)].r);
868 const int g2 =
static_cast<int> ((*cloud)[(row_index+1)*width + (col_index)].g);
869 const int b2 =
static_cast<int> ((*cloud)[(row_index+1)*width + (col_index)].b);
870 const int r3 =
static_cast<int> ((*cloud)[(row_index+1)*width + (col_index+1)].r);
871 const int g3 =
static_cast<int> ((*cloud)[(row_index+1)*width + (col_index+1)].g);
872 const int b3 =
static_cast<int> ((*cloud)[(row_index+1)*width + (col_index+1)].b);
897 const int r_dx = r9 + 2*r6 + r3 - (r7 + 2*r4 + r1);
898 const int r_dy = r1 + 2*r2 + r3 - (r7 + 2*r8 + r9);
899 const int g_dx = g9 + 2*g6 + g3 - (g7 + 2*g4 + g1);
900 const int g_dy = g1 + 2*g2 + g3 - (g7 + 2*g8 + g9);
901 const int b_dx = b9 + 2*b6 + b3 - (b7 + 2*b4 + b1);
902 const int b_dy = b1 + 2*b2 + b3 - (b7 + 2*b8 + b9);
904 const int sqr_mag_r = r_dx*r_dx + r_dy*r_dy;
905 const int sqr_mag_g = g_dx*g_dx + g_dy*g_dy;
906 const int sqr_mag_b = b_dx*b_dx + b_dy*b_dy;
908 if (sqr_mag_r > sqr_mag_g && sqr_mag_r > sqr_mag_b)
911 gradient.
magnitude = std::sqrt (
static_cast<float> (sqr_mag_r));
912 gradient.
angle = std::atan2 (
static_cast<float> (r_dy),
static_cast<float> (r_dx)) * 180.0f / pi;
913 if (gradient.
angle < -180.0f) gradient.
angle += 360.0f;
914 if (gradient.
angle >= 180.0f) gradient.
angle -= 360.0f;
915 gradient.
x =
static_cast<float> (col_index);
916 gradient.
y =
static_cast<float> (row_index);
918 color_gradients_ (col_index, row_index) = gradient;
920 else if (sqr_mag_g > sqr_mag_b)
923 gradient.
magnitude = std::sqrt (
static_cast<float> (sqr_mag_g));
924 gradient.
angle = std::atan2 (
static_cast<float> (g_dy),
static_cast<float> (g_dx)) * 180.0f / pi;
925 if (gradient.
angle < -180.0f) gradient.
angle += 360.0f;
926 if (gradient.
angle >= 180.0f) gradient.
angle -= 360.0f;
927 gradient.
x =
static_cast<float> (col_index);
928 gradient.
y =
static_cast<float> (row_index);
930 color_gradients_ (col_index, row_index) = gradient;
935 gradient.
magnitude = std::sqrt (
static_cast<float> (sqr_mag_b));
936 gradient.
angle = std::atan2 (
static_cast<float> (b_dy),
static_cast<float> (b_dx)) * 180.0f / pi;
937 if (gradient.
angle < -180.0f) gradient.
angle += 360.0f;
938 if (gradient.
angle >= 180.0f) gradient.
angle -= 360.0f;
939 gradient.
x =
static_cast<float> (col_index);
940 gradient.
y =
static_cast<float> (row_index);
942 color_gradients_ (col_index, row_index) = gradient;
945 assert (color_gradients_ (col_index, row_index).angle >= -180 &&
946 color_gradients_ (col_index, row_index).angle <= 180);
954 template <
typename Po
intInT>
971 const std::size_t width = input_->width;
972 const std::size_t height = input_->height;
974 quantized_color_gradients_.resize (width, height);
976 const float angleScale = 16.0f/360.0f;
980 for (std::size_t row_index = 0; row_index < height; ++row_index)
982 for (std::size_t col_index = 0; col_index < width; ++col_index)
984 if (color_gradients_ (col_index, row_index).magnitude < gradient_magnitude_threshold_)
986 quantized_color_gradients_ (col_index, row_index) = 0;
990 const float angle = 11.25f + color_gradients_ (col_index, row_index).angle + 180.0f;
991 const int quantized_value = (
static_cast<int> (angle * angleScale)) & 7;
992 quantized_color_gradients_ (col_index, row_index) =
static_cast<unsigned char> (quantized_value + 1);
1017 template <
typename Po
intInT>
1022 const std::size_t width = input_->width;
1023 const std::size_t height = input_->height;
1025 filtered_quantized_color_gradients_.resize (width, height);
1028 for (std::size_t row_index = 1; row_index < height-1; ++row_index)
1030 for (std::size_t col_index = 1; col_index < width-1; ++col_index)
1032 unsigned char histogram[9] = {0,0,0,0,0,0,0,0,0};
1035 const unsigned char * data_ptr = quantized_color_gradients_.getData () + (row_index-1)*width+col_index-1;
1036 assert (data_ptr[0] < 9 && data_ptr[1] < 9 && data_ptr[2] < 9);
1037 ++histogram[data_ptr[0]];
1038 ++histogram[data_ptr[1]];
1039 ++histogram[data_ptr[2]];
1042 const unsigned char * data_ptr = quantized_color_gradients_.getData () + row_index*width+col_index-1;
1043 assert (data_ptr[0] < 9 && data_ptr[1] < 9 && data_ptr[2] < 9);
1044 ++histogram[data_ptr[0]];
1045 ++histogram[data_ptr[1]];
1046 ++histogram[data_ptr[2]];
1049 const unsigned char * data_ptr = quantized_color_gradients_.getData () + (row_index+1)*width+col_index-1;
1050 assert (data_ptr[0] < 9 && data_ptr[1] < 9 && data_ptr[2] < 9);
1051 ++histogram[data_ptr[0]];
1052 ++histogram[data_ptr[1]];
1053 ++histogram[data_ptr[2]];
1056 unsigned char max_hist_value = 0;
1057 int max_hist_index = -1;
1068 if (max_hist_value < histogram[1]) {max_hist_index = 0; max_hist_value = histogram[1];}
1069 if (max_hist_value < histogram[2]) {max_hist_index = 1; max_hist_value = histogram[2];}
1070 if (max_hist_value < histogram[3]) {max_hist_index = 2; max_hist_value = histogram[3];}
1071 if (max_hist_value < histogram[4]) {max_hist_index = 3; max_hist_value = histogram[4];}
1072 if (max_hist_value < histogram[5]) {max_hist_index = 4; max_hist_value = histogram[5];}
1073 if (max_hist_value < histogram[6]) {max_hist_index = 5; max_hist_value = histogram[6];}
1074 if (max_hist_value < histogram[7]) {max_hist_index = 6; max_hist_value = histogram[7];}
1075 if (max_hist_value < histogram[8]) {max_hist_index = 7; max_hist_value = histogram[8];}
1077 if (max_hist_index != -1 && max_hist_value >= 5)
1078 filtered_quantized_color_gradients_ (col_index, row_index) =
static_cast<unsigned char> (0x1 << max_hist_index);
1080 filtered_quantized_color_gradients_ (col_index, row_index) = 0;
1087 template <
typename Po
intInT>
1093 const std::size_t width = mask_in.
getWidth ();
1094 const std::size_t height = mask_in.
getHeight ();
1096 mask_out.
resize (width, height);
1098 for (std::size_t row_index = 1; row_index < height-1; ++row_index)
1100 for (std::size_t col_index = 1; col_index < width-1; ++col_index)
1102 if (mask_in (col_index, row_index-1) == 0 ||
1103 mask_in (col_index-1, row_index) == 0 ||
1104 mask_in (col_index+1, row_index) == 0 ||
1105 mask_in (col_index, row_index+1) == 0)
1107 mask_out (col_index, row_index) = 0;
1111 mask_out (col_index, row_index) = 255;