00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include <iostream>
00039 using std::cout;
00040 using std::cerr;
00041 #include <vector>
00042 using std::vector;
00043 #include <pcl/keypoints/narf_keypoint.h>
00044 #include <pcl/features/range_image_border_extractor.h>
00045 #include <pcl/pcl_macros.h>
00046 #include <pcl/common/polynomial_calculations.h>
00047 #include <pcl/range_image/range_image.h>
00048
00049
00050
00051 #define USE_OMP 1
00052
00053 namespace pcl {
00054
00055
00057 NarfKeypoint::NarfKeypoint (RangeImageBorderExtractor* range_image_border_extractor, float support_size) :
00058 BaseClass (), interest_image_ (NULL), interest_points_ (NULL)
00059 {
00060 name_ = "NarfKeypoint";
00061 clearData ();
00062 setRangeImageBorderExtractor (range_image_border_extractor);
00063 if (support_size > 0.0f)
00064 parameters_.support_size = support_size;
00065 }
00066
00068 NarfKeypoint::~NarfKeypoint ()
00069 {
00070 clearData ();
00071 }
00072
00074 void
00075 NarfKeypoint::clearData ()
00076 {
00077
00078
00079 for (size_t scale_space_idx = 1; scale_space_idx<range_image_scale_space_.size (); ++scale_space_idx)
00080 delete range_image_scale_space_[scale_space_idx];
00081 range_image_scale_space_.clear ();
00082 for (size_t scale_space_idx = 1; scale_space_idx<border_extractor_scale_space_.size (); ++scale_space_idx)
00083 delete border_extractor_scale_space_[scale_space_idx];
00084 border_extractor_scale_space_.clear ();
00085 for (size_t scale_space_idx = 1; scale_space_idx<interest_image_scale_space_.size (); ++scale_space_idx)
00086 delete interest_image_scale_space_[scale_space_idx];
00087 interest_image_scale_space_.clear();
00088 is_interest_point_image_.clear ();
00089 delete[] interest_image_; interest_image_=NULL;
00090 delete interest_points_; interest_points_=NULL;
00091 }
00092
00094 void
00095 NarfKeypoint::setRangeImageBorderExtractor (RangeImageBorderExtractor* range_image_border_extractor)
00096 {
00097 clearData ();
00098 range_image_border_extractor_ = range_image_border_extractor;
00099 }
00100
00102 void
00103 NarfKeypoint::setRangeImage (const RangeImage* range_image)
00104 {
00105 clearData ();
00106 range_image_border_extractor_->setRangeImage (range_image);
00107 }
00108
00110 void
00111 NarfKeypoint::calculateScaleSpace ()
00112 {
00113
00114
00115 if (range_image_border_extractor_ == NULL || !range_image_border_extractor_->hasRangeImage () ||
00116 !border_extractor_scale_space_.empty ())
00117 return;
00118 border_extractor_scale_space_.push_back (range_image_border_extractor_);
00119 range_image_scale_space_.push_back ((RangeImage*)&range_image_border_extractor_->getRangeImage ());
00120 while ((int)range_image_scale_space_.back ()->width > parameters_.optimal_range_image_patch_size ||
00121 (int)range_image_scale_space_.back ()->height > parameters_.optimal_range_image_patch_size)
00122 {
00123 range_image_scale_space_.push_back (getRangeImage().getNew());
00124
00125 range_image_scale_space_[range_image_scale_space_.size ()-2]->getHalfImage (*range_image_scale_space_.back ());
00126 border_extractor_scale_space_.push_back (new RangeImageBorderExtractor);
00127 border_extractor_scale_space_.back ()->getParameters () = range_image_border_extractor_->getParameters ();
00128 border_extractor_scale_space_.back ()->setRangeImage (range_image_scale_space_.back ());
00129 border_extractor_scale_space_.back ()->getSurfaceChangeScores();
00130 }
00131
00132 }
00133
00134 #define USE_BEAM_AVERAGE 1
00135
00136 namespace {
00137 inline void nkdGetScores (float distance_factor, int pixel_distance, float surface_change_score,
00138 float optimal_distance, float& negative_score, float& positive_score)
00139 {
00140
00141 negative_score = 1.0f - surface_change_score * (std::max) (1.0f - distance_factor/optimal_distance, 0.0f);
00142 negative_score = powf (negative_score, 2);
00143
00144
00145
00146
00147 positive_score = surface_change_score * (1.0f-fabsf (distance_factor-optimal_distance));
00148
00149 }
00150 void translateDirection180To360 (Eigen::Vector2f& direction_vector)
00151 {
00152
00153
00154
00155
00156
00157
00158 float cos_a = direction_vector[0],
00159 cos_2a = 2*cos_a*cos_a - 1.0f,
00160 sin_a = direction_vector[1],
00161 sin_2a = 2.0f*sin_a*cos_a;
00162 direction_vector[0] = cos_2a;
00163 direction_vector[1] = sin_2a;
00164 }
00165 void translateDirection360To180 (Eigen::Vector2f& direction_vector)
00166 {
00167
00168 float cos_2a = direction_vector[0],
00169 cos_a = sqrtf (0.5f* (cos_2a+1.0f)),
00170 sin_2a = direction_vector[1],
00171 sin_a = sin_2a / (2.0f*cos_a);
00172 direction_vector[0] = cos_a;
00173 direction_vector[1] = sin_a;
00174 }
00175 inline Eigen::Vector2f nkdGetDirectionVector (const Eigen::Vector3f& direction, const Eigen::Affine3f& rotation)
00176 {
00177
00178
00179
00180
00181 Eigen::Vector3f rotated_direction = rotation*direction;
00182 Eigen::Vector2f direction_vector (rotated_direction[0], rotated_direction[1]);
00183 direction_vector.normalize ();
00184 if (direction_vector[0]<0.0f)
00185 direction_vector *= -1.0f;
00186
00187
00188 # if USE_BEAM_AVERAGE
00189 translateDirection180To360 (direction_vector);
00190 # endif
00191
00192
00193 return direction_vector;
00194 }
00195 inline float nkdGetDirectionAngle (const Eigen::Vector3f& direction, const Eigen::Affine3f& rotation)
00196 {
00197 Eigen::Vector3f rotated_direction = rotation*direction;
00198 Eigen::Vector2f direction_vector (rotated_direction[0], rotated_direction[1]);
00199 direction_vector.normalize ();
00200 float angle = 0.5f*normAngle (2.0f*acosf (direction_vector[0]));
00201
00202 return angle;
00203 }
00204
00205 inline void propagateInvalidBeams (int new_radius, std::vector<bool>& old_beams, std::vector<bool>& new_beams)
00206 {
00207 new_beams.clear ();
00208 new_beams.resize (std::max (8*new_radius,1), false);
00209 if (new_radius >= 2)
00210 {
00211 float mapping_factor = 1.0f+ (1.0f/ (new_radius-1));
00212 for (size_t old_idx=0; old_idx<old_beams.size (); ++old_idx)
00213 {
00214 if (old_beams[old_idx])
00215 {
00216 int middle_idx = lrint (mapping_factor*old_idx);
00217
00218 for (int idx_offset=-1; idx_offset<=1; ++idx_offset)
00219 {
00220 if (idx_offset != 0)
00221 {
00222 int old_neighbor_idx = old_idx+idx_offset;
00223 if (old_neighbor_idx<0)
00224 old_neighbor_idx += old_beams.size ();
00225 if (old_neighbor_idx>= (int)old_beams.size ())
00226 old_neighbor_idx -= old_beams.size ();
00227 if (!old_beams[old_neighbor_idx])
00228 continue;
00229 }
00230 int new_idx = middle_idx+idx_offset;
00231 if (new_idx<0)
00232 new_idx += new_beams.size ();
00233 if (new_idx>= (int)new_beams.size ())
00234 new_idx -= new_beams.size ();
00235 new_beams[new_idx] = true;
00236
00237 }
00238 }
00239 }
00240
00241 }
00242
00243
00244
00245 }
00246
00247 inline bool
00248 isBetterInterestPoint (const InterestPoint& p1, const InterestPoint& p2)
00249 {
00250 return p1.strength > p2.strength;
00251 }
00252
00253 }
00254
00255 void NarfKeypoint::calculateInterestImage ()
00256 {
00257
00258
00259 if (interest_image_!=NULL)
00260 return;
00261
00262 if (parameters_.support_size <= 0.0f)
00263 {
00264 cerr << __PRETTY_FUNCTION__<<": parameters_.support_size is not set!\n";
00265 return;
00266 }
00267 if (range_image_border_extractor_==NULL)
00268 {
00269 cerr << __PRETTY_FUNCTION__<<": range_image_border_extractor_ is not set!\n";
00270 return;
00271 }
00272
00273 float search_radius = 0.5*parameters_.support_size,
00274 radius_squared = search_radius*search_radius,
00275 radius_reciprocal = 1.0f/search_radius;
00276
00277 calculateScaleSpace ();
00278
00279 std::vector<float> start_usage_ranges;
00280 start_usage_ranges.resize (range_image_scale_space_.size());
00281 start_usage_ranges[int(range_image_scale_space_.size())-1] = 0.0f;
00282 for (int scale_idx = int(range_image_scale_space_.size())-2; scale_idx >= 0; --scale_idx)
00283 start_usage_ranges[scale_idx] = parameters_.support_size / tanf(parameters_.optimal_range_image_patch_size *
00284 range_image_scale_space_[scale_idx+1]->getAngularResolution());
00285 interest_image_scale_space_.clear();
00286 interest_image_scale_space_.resize(range_image_scale_space_.size(), NULL);
00287 for (int scale_idx = int(range_image_scale_space_.size())-1; scale_idx >= 0; --scale_idx)
00288 {
00289 const RangeImage& range_image = *range_image_scale_space_[scale_idx];
00290 RangeImageBorderExtractor& border_extractor = *border_extractor_scale_space_[scale_idx];
00291 const ::pcl::PointCloud<BorderDescription>& border_descriptions = border_extractor.getBorderDescriptions ();
00292 const float* surface_change_scores = border_extractor.getSurfaceChangeScores ();
00293 const Eigen::Vector3f* surface_change_directions = border_extractor.getSurfaceChangeDirections ();
00294 float start_usage_range = start_usage_ranges[scale_idx];
00295
00296
00297 int width = range_image.width,
00298 height = range_image.height,
00299 array_size = width*height;
00300
00301 float* interest_image = new float[array_size];
00302 interest_image_scale_space_[scale_idx] = interest_image;
00303 for (int i=0; i<array_size; ++i)
00304 interest_image[i] = 1.0f;
00305
00306 int angle_histogram_size = 18;
00307 float* angle_histograms = new float[angle_histogram_size * array_size];
00308 memset (angle_histograms, 0, angle_histogram_size*array_size*sizeof (*angle_histograms));
00309
00310 vector<bool> invalid_beams, old_invalid_beams;
00311
00312
00313 for (int y=0; y<height; ++y)
00314 {
00315 for (int x=0; x<width; ++x)
00316 {
00317
00318 int index = y*width + x;
00319 if (!range_image.isValid (x, y))
00320 {
00321 interest_image[index] = 0.0f;
00322 continue;
00323 }
00324
00325 const PointWithRange& point = range_image.getPoint (index);
00326
00327 if (point.range+search_radius < start_usage_range)
00328 continue;
00329
00330 const BorderTraits& border_traits = border_descriptions.points[index].traits;
00331 if (border_traits[BORDER_TRAIT__SHADOW_BORDER] || border_traits[BORDER_TRAIT__VEIL_POINT])
00332 continue;
00333
00334 float surface_change_score = surface_change_scores[index];
00335 if (surface_change_score < parameters_.min_surface_change_score)
00336 continue;
00337
00338 const Eigen::Vector3f& surface_change_direction = surface_change_directions[index];
00339
00340 invalid_beams.clear ();
00341 old_invalid_beams.clear ();
00342 for (int radius=0, stop=false; !stop; ++radius)
00343 {
00344 std::swap (invalid_beams, old_invalid_beams);
00345 propagateInvalidBeams (radius, old_invalid_beams, invalid_beams);
00346
00347
00348
00349
00350
00351
00352
00353 int x2=x-radius-1, y2=y-radius;
00354 stop = true;
00355 for (int i=0; (radius==0&&i==0) || i<8*radius; ++i)
00356 {
00357 if (i<=2*radius) ++x2; else if (i<=4*radius) ++y2; else if (i<=6*radius) --x2; else --y2;
00358 if (invalid_beams[i] || !range_image.isValid (x2, y2))
00359 continue;
00360 int neighbor_index = y2*width+x2;
00361
00362 const PointWithRange& neighbor = range_image.getPoint (neighbor_index);
00363
00364 if (neighbor.range < start_usage_range)
00365 continue;
00366
00367 const BorderTraits& neighbor_border_traits = border_descriptions.points[neighbor_index].traits;
00368 if (neighbor_border_traits[BORDER_TRAIT__SHADOW_BORDER] || neighbor_border_traits[BORDER_TRAIT__VEIL_POINT])
00369 {
00370 invalid_beams[i] = true;
00371 continue;
00372 }
00373
00374 float distance_squared = squaredEuclideanDistance (point, neighbor);
00375 if (distance_squared>radius_squared)
00376 {
00377 invalid_beams[i] = true;
00378 continue;
00379 }
00380 stop = false;
00381
00382 float* angle_histogram = angle_histograms+angle_histogram_size*neighbor_index;
00383 float distance_factor = radius_reciprocal*sqrtf (distance_squared);
00384 float positive_score, current_negative_score;
00385 nkdGetScores (distance_factor, radius, surface_change_score,
00386 parameters_.optimal_distance_to_high_surface_change,
00387 current_negative_score, positive_score);
00388
00389 Eigen::Affine3f rotation_to_viewer_coordinate_system;
00390 range_image.getRotationToViewerCoordinateFrame (neighbor.getVector3fMap (),
00391 rotation_to_viewer_coordinate_system);
00392 float angle = nkdGetDirectionAngle (surface_change_direction, rotation_to_viewer_coordinate_system);
00393 int histogram_cell = (std::min) (angle_histogram_size-1,
00394 (int)lrint (floorf ( (angle+deg2rad (90.0f))/deg2rad (180.0f) * angle_histogram_size)));
00395 angle_histogram[histogram_cell] = (std::max) (angle_histogram[histogram_cell], positive_score);
00396 float& negative_score = interest_image[neighbor_index];
00397 negative_score = (std::min) (negative_score, current_negative_score);
00398 }
00399
00400
00401
00402
00403
00404
00405 }
00406 }
00407 }
00408
00409
00410
00411 for (int y=0; y<height; ++y)
00412 {
00413 for (int x=0; x<width; ++x)
00414 {
00415 if (!range_image.isValid (x, y))
00416 continue;
00417 int index = y*width + x;
00418 float& interest_value = interest_image[index];
00419 const PointWithRange& point = range_image.getPoint(index);
00420 if (point.range < start_usage_range)
00421 {
00422 const RangeImage& half_range_image = *range_image_scale_space_[scale_idx+1];
00423 float* half_interest_image = interest_image_scale_space_[scale_idx+1];
00424 int half_x = std::min(x/2, int(half_range_image.width)-1),
00425 half_y = std::min(y/2, int(half_range_image.height)-1);
00426 interest_value = half_interest_image[half_y*half_range_image.width + half_x];
00427 continue;
00428 }
00429 float* angle_histogram = angle_histograms+angle_histogram_size*index;
00430 float angle_change_value = 0.0f;
00431 for (int histogram_cell1=0; histogram_cell1<angle_histogram_size-1; ++histogram_cell1)
00432 {
00433 if (angle_histogram[histogram_cell1]==0.0f)
00434 continue;
00435 for (int histogram_cell2=histogram_cell1+1; histogram_cell2<angle_histogram_size; ++histogram_cell2)
00436 {
00437 if (angle_histogram[histogram_cell2]==0.0f)
00438 continue;
00439
00440 float normalized_angle_diff = 2.0f*float (histogram_cell2-histogram_cell1)/float (angle_histogram_size);
00441 normalized_angle_diff = (normalized_angle_diff <= 1.0f ? normalized_angle_diff : 2.0f-normalized_angle_diff);
00442
00443
00444 angle_change_value = std::max (angle_histogram[histogram_cell1] * angle_histogram[histogram_cell2] *
00445 normalized_angle_diff, angle_change_value);
00446 }
00447 }
00448 angle_change_value = sqrtf (angle_change_value);
00449
00450 interest_value *= angle_change_value;
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464 }
00465 }
00466 delete[] angle_histograms;
00467 }
00468
00469 interest_image_ = interest_image_scale_space_[0];
00470
00471 # if USE_OMP
00472
00473 # endif
00474 }
00475
00476 void NarfKeypoint::calculateInterestPoints ()
00477 {
00478
00479
00480
00481 if (interest_points_ != NULL)
00482 {
00483
00484 return;
00485 }
00486 calculateInterestImage ();
00487
00488
00489 interest_points_ = new ::pcl::PointCloud<InterestPoint>;
00490
00491 float max_distance_squared = powf (0.3f*parameters_.support_size, 2);
00492
00493
00494
00495
00496
00497
00498 const RangeImage& range_image = range_image_border_extractor_->getRangeImage ();
00499 const ::pcl::PointCloud<BorderDescription>& border_descriptions =
00500 range_image_border_extractor_->getBorderDescriptions ();
00501 int width = range_image.width,
00502 height = range_image.height,
00503 size = width*height;
00504 is_interest_point_image_.clear ();
00505 is_interest_point_image_.resize (size, false);
00506
00507 typedef double RealForPolynomial;
00508 PolynomialCalculationsT<RealForPolynomial> polynomial_calculations;
00509 BivariatePolynomialT<RealForPolynomial> polynomial (2);
00510 std::vector<Eigen::Matrix<RealForPolynomial, 3, 1> > sample_points;
00511 std::vector<RealForPolynomial> x_values, y_values;
00512 std::vector<int> types;
00513 std::vector<bool> invalid_beams, old_invalid_beams;
00514
00515 std::vector<InterestPoint> tmp_interest_points;
00516 for (int y=0; y<height; ++y)
00517 {
00518 for (int x=0; x<width; ++x)
00519 {
00520 int index = y*width + x;
00521 float interest_value = interest_image_[index];
00522 if (interest_value < parameters_.min_interest_value)
00523 continue;
00524 const PointWithRange& point = range_image.getPoint (index);
00525 bool is_maximum = true;
00526 for (int y2=y-2; y2<=y+2&&is_maximum&¶meters_.do_non_maximum_suppression; ++y2)
00527 {
00528 for (int x2=x-2; x2<=x+2; ++x2)
00529 {
00530 if (!range_image.isInImage (x2,y2))
00531 continue;
00532 int index2 = y2*width + x2;
00533 float interest_value2 = interest_image_[index2];
00534 if (interest_value2 <= interest_value)
00535 continue;
00536 is_maximum = false;
00537 break;
00538 }
00539 }
00540 if (!is_maximum)
00541 continue;
00542
00543 PointWithRange keypoint_3d = point;
00544 int keypoint_x_int=x, keypoint_y_int=y;
00545
00546 int no_of_polynomial_approximations_per_point = parameters_.no_of_polynomial_approximations_per_point;
00547 if (!parameters_.do_non_maximum_suppression)
00548 no_of_polynomial_approximations_per_point = 0;
00549
00550 for (int poly_step=0; poly_step<no_of_polynomial_approximations_per_point; ++poly_step)
00551 {
00552 sample_points.clear ();
00553 invalid_beams.clear ();
00554 old_invalid_beams.clear ();
00555 for (int radius=0, stop=false; !stop; ++radius)
00556 {
00557 std::swap (invalid_beams, old_invalid_beams);
00558 propagateInvalidBeams (radius, old_invalid_beams, invalid_beams);
00559 int x2=keypoint_x_int-radius-1, y2=keypoint_y_int-radius;
00560 stop = true;
00561 for (int i=0; (radius==0&&i==0) || i<8*radius; ++i)
00562 {
00563 if (i<=2*radius) ++x2; else if (i<=4*radius) ++y2; else if (i<=6*radius) --x2; else --y2;
00564 if (invalid_beams[i] || !range_image.isValid (x2, y2))
00565 continue;
00566 int index2 = y2*width + x2;
00567 const BorderTraits& neighbor_border_traits = border_descriptions.points[index2].traits;
00568 if (neighbor_border_traits[BORDER_TRAIT__SHADOW_BORDER] || neighbor_border_traits[BORDER_TRAIT__VEIL_POINT])
00569 {
00570 invalid_beams[i] = true;
00571 continue;
00572 }
00573 const PointWithRange& neighbor = range_image.getPoint (index2);
00574 float distance_squared = squaredEuclideanDistance (point, neighbor);
00575 if (distance_squared>max_distance_squared)
00576 {
00577 invalid_beams[i] = true;
00578 continue;
00579 }
00580 stop = false;
00581
00582 float interest_value2 = interest_image_[index2];
00583 sample_points.push_back (Eigen::Vector3d (x2-keypoint_x_int, y2-keypoint_y_int, interest_value2));
00584 }
00585 }
00586 if (!polynomial_calculations.bivariatePolynomialApproximation (sample_points, 2, polynomial))
00587 {
00588
00589 continue;
00590 }
00591 polynomial.findCriticalPoints (x_values, y_values, types);
00592
00593
00594
00595
00596
00597
00598
00599
00600 if (!types.empty () && types[0]==0)
00601 {
00602
00603
00604 float keypoint_x = x_values[0]+keypoint_x_int,
00605 keypoint_y = y_values[0]+keypoint_y_int;
00606
00607
00608 keypoint_x_int = lrint (keypoint_x);
00609 keypoint_y_int = lrint (keypoint_y);
00610
00611
00612 range_image.calculate3DPoint (keypoint_x, keypoint_y, keypoint_3d);
00613 if (!pcl_isfinite (keypoint_3d.range))
00614 {
00615 keypoint_3d = point;
00616 break;
00617 }
00618 }
00619 else
00620 {
00621 break;
00622 }
00623 }
00624
00625
00626 InterestPoint interest_point;
00627 interest_point.getVector3fMap () = keypoint_3d.getVector3fMap ();
00628
00629 interest_point.strength = interest_value;
00630
00631 interest_point.strength = interest_value;
00632 tmp_interest_points.push_back (interest_point);
00633
00634
00635
00636
00637
00638 }
00639 }
00640
00641 std::sort (tmp_interest_points.begin (), tmp_interest_points.end (), isBetterInterestPoint);
00642
00643 float min_distance_squared = powf (parameters_.min_distance_between_interest_points*parameters_.support_size, 2);
00644 for (size_t int_point_idx=0; int_point_idx<tmp_interest_points.size (); ++int_point_idx)
00645 {
00646 const InterestPoint& interest_point = tmp_interest_points[int_point_idx];
00647
00648
00649 bool better_point_too_close = false;
00650 for (size_t int_point_idx2=0; int_point_idx2<interest_points_->points.size (); ++int_point_idx2)
00651 {
00652 const InterestPoint& interest_point2 = interest_points_->points[int_point_idx2];
00653 float distance_squared = (interest_point.getVector3fMap ()-interest_point2.getVector3fMap ()).squaredNorm ();
00654 if (distance_squared < min_distance_squared)
00655 {
00656 better_point_too_close = true;
00657 break;
00658 }
00659 }
00660 if (better_point_too_close)
00661 continue;
00662 interest_points_->points.push_back (interest_point);
00663 int image_x, image_y;
00664 range_image.getImagePoint (interest_point.getVector3fMap (), image_x, image_y);
00665 if (range_image.isValid (image_x, image_y))
00666 is_interest_point_image_[image_y*width + image_x] = true;
00667 }
00668 interest_points_->width = interest_points_->points.size ();
00669 interest_points_->height = 1;
00670 interest_points_->is_dense = true;
00671
00672 #if 0
00673
00674 float min_distance_squared = powf (parameters_.min_distance_between_interest_points*parameters_.support_size, 2),
00675 distance_for_additional_points = parameters_.distance_for_additional_points*parameters_.support_size,
00676 distance_for_additional_points_squared = distance_for_additional_points*distance_for_additional_points;
00677 is_interest_point_image_.clear ();
00678 is_interest_point_image_.resize (size, true);
00679
00680 std::multimap<float, Eigen::Vector2i> ordered_points;
00681 for (int y=0; y<height; ++y)
00682 {
00683 for (int x=0; x<width; ++x)
00684 {
00685 int index = y*width + x;
00686 float interest_value = interest_image_[index];
00687 if (interest_value <= parameters_.min_interest_value || !range_image.isValid (index))
00688 {
00689 is_interest_point_image_[index] = false;
00690 continue;
00691 }
00692 ordered_points.insert (std::make_pair (interest_value, Eigen::Vector2i (x,y)));
00693 }
00694 }
00695
00696 vector<int> neighbor_indices;
00697 vector<int> interest_point_indices;
00698 for (std::multimap<float, Eigen::Vector2i>::const_reverse_iterator it=ordered_points.rbegin ();
00699 it!=ordered_points.rend (); ++it)
00700 {
00701 int x=it->second[0], y=it->second[1], index = y*width + x;
00702 if (!is_interest_point_image_[index])
00703 continue;
00704 const PointWithRange& point = range_image.getPoint (index);
00705 InterestPoint interest_point;
00706 interest_point.x=point.x; interest_point.y=point.y; interest_point.z=point.z;
00707 interest_point.strength = interest_image_[index];
00708
00709 bool is_maxmimum = true;
00710 bool stop = false;
00711 neighbor_indices.clear ();
00712 for (int radius=1; !stop; ++radius)
00713 {
00714 int x2=x-radius-1, y2=y-radius;
00715 stop = true;
00716 for (int i=0; i<8*radius; ++i)
00717 {
00718 if (i<=2*radius) ++x2; else if (i<=4*radius) ++y2; else if (i<=6*radius) --x2; else --y2;
00719 int neighbor_index = y2*width+x2;
00720 if (!range_image.isValid (x2, y2))
00721 continue;
00722 const PointWithRange& neighbor = range_image.getPoint (neighbor_index);
00723 if (radius>=parameters_.min_pixel_distance_between_interest_points &&
00724 squaredEuclideanDistance (point, neighbor)>min_distance_squared)
00725 {
00726 continue;
00727 }
00728 stop = false;
00729 neighbor_indices.push_back (neighbor_index);
00730 if (interest_image_[neighbor_index] > interest_point.strength)
00731 is_maxmimum = false;
00732 }
00733 }
00734 if (!parameters_.do_non_maximum_suppression || is_maxmimum)
00735 {
00736 interest_point_indices.push_back (index);
00737 for (unsigned int i=0; i<neighbor_indices.size (); ++i)
00738 is_interest_point_image_[neighbor_indices[i]] = false;
00739 }
00740 else
00741 {
00742 is_interest_point_image_[index] = false;
00743 }
00744 }
00745
00746 for (unsigned int i=0; i<interest_point_indices.size (); ++i)
00747 {
00748 int index = interest_point_indices[i];
00749 const PointWithRange& point = range_image.getPoint (index);
00750 interest_points_->points.push_back (InterestPoint ());
00751 interest_points_->points.back ().getVector3fMap () = point.getVector3fMap ();
00752 interest_points_->points.back ().strength = interest_image_[index];
00753 if (distance_for_additional_points_squared > 0.0f)
00754 {
00755 float y=index/range_image.width, x=index-y*range_image.width;
00756 bool still_in_range = true;
00757 for (int radius=1; still_in_range; ++radius)
00758 {
00759 int x2=x-radius-1, y2=y-radius;
00760 still_in_range = false;
00761 for (int i=0; i<8*radius; ++i)
00762 {
00763 if (i<=2*radius) ++x2; else if (i<=4*radius) ++y2; else if (i<=6*radius) --x2; else --y2;
00764 if (!range_image.isValid (x2, y2))
00765 continue;
00766 int neighbor_index = y2*width+x2;
00767 const PointWithRange& neighbor = range_image.getPoint (neighbor_index);
00768 if (squaredEuclideanDistance (point, neighbor) > distance_for_additional_points_squared)
00769 continue;
00770 still_in_range = true;
00771 float neighbor_interest_value = interest_image_[neighbor_index];
00772 if (neighbor_interest_value > 0.5f*parameters_.min_interest_value)
00773 {
00774
00775 is_interest_point_image_[neighbor_index] = true;
00776 interest_points_->points.push_back (InterestPoint ());
00777 interest_points_->points.back ().getVector3fMap () = neighbor.getVector3fMap ();
00778 interest_points_->points.back ().strength = interest_image_[neighbor_index];
00779 }
00780 }
00781 }
00782 }
00783 }
00784 #endif
00785 }
00786
00787 const RangeImage& NarfKeypoint::getRangeImage ()
00788 {
00789 return range_image_border_extractor_->getRangeImage ();
00790 }
00791
00792 void NarfKeypoint::detectKeypoints (NarfKeypoint::PointCloudOut& output)
00793 {
00794
00795
00796 output.points.clear ();
00797
00798 if (indices_)
00799 {
00800 std::cerr << __PRETTY_FUNCTION__
00801 << ": Sorry, usage of indices for the extraction is not supported for NARF interest points (yet).\n\n";
00802 return;
00803 }
00804
00805 if (range_image_border_extractor_ == NULL)
00806 {
00807 std::cerr << __PRETTY_FUNCTION__
00808 << ": RangeImageBorderExtractor member is not set. "
00809 << "Sorry, this is needed for the NARF keypoint extraction.\n\n";
00810 return;
00811 }
00812
00813 if (!range_image_border_extractor_->hasRangeImage ())
00814 {
00815 std::cerr << __PRETTY_FUNCTION__
00816 << ": RangeImage is not set. Sorry, the NARF keypoint extraction works on range images, "
00817 "not on normal point clouds.\n\n"
00818 << " Use setRangeImage (...).\n\n";
00819 return;
00820 }
00821
00822 calculateInterestPoints ();
00823
00824 int size = getRangeImage ().width * getRangeImage ().height;
00825
00826 for (int index=0; index<size; ++index)
00827 {
00828 if (!is_interest_point_image_[index])
00829 continue;
00830 output.points.push_back (index);
00831 }
00832 }
00833
00834 void NarfKeypoint::compute (NarfKeypoint::PointCloudOut& output)
00835 {
00836 detectKeypoints (output);
00837 }
00838
00839
00840
00841
00843
00844
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877 }