From ce94e4a994b9f686f29264abfc04cafb05ffa91e Mon Sep 17 00:00:00 2001 From: Ethan Rublee Date: Wed, 1 Jun 2011 00:25:32 +0000 Subject: [PATCH] Fix # of features in orb. --- modules/features2d/src/orb.cpp | 68 +++++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 22 deletions(-) diff --git a/modules/features2d/src/orb.cpp b/modules/features2d/src/orb.cpp index 6b2acac5e1..125807d227 100644 --- a/modules/features2d/src/orb.cpp +++ b/modules/features2d/src/orb.cpp @@ -202,6 +202,19 @@ inline bool keypointResponseGreater(const cv::KeyPoint& lhs, const cv::KeyPoint& return lhs.response > rhs.response; } +struct KeypointResponseGreaterThanEqual +{ + KeypointResponseGreaterThanEqual(float value) : + value(value) + { + } + inline bool operator()(const cv::KeyPoint& kpt) + { + return kpt.response >= value; + } + float value; +}; + /** Simple function that returns the area in the rectangle x1<=x<=x2, y1<=y<=y2 given an integral image * @param integral_image * @param x1 @@ -249,7 +262,8 @@ template { SumType m_01 = 0, m_10 = 0/*, m_00 = 0*/; - const PatchType* val_center_ptr_plus = &(image.at (cvRound(kpt.pt.y), cvRound(kpt.pt.x))), *val_center_ptr_minus; + const PatchType* val_center_ptr_plus = &(image.at (cvRound(kpt.pt.y), cvRound(kpt.pt.x))), + *val_center_ptr_minus; // Treat the center line differently, v=0 @@ -402,8 +416,8 @@ private: //switch (sz) { //default: - pattern_data = reinterpret_cast (rotated_patterns_[angle_idx].data); - //break; + pattern_data = reinterpret_cast (rotated_patterns_[angle_idx].data); + //break; } int half_kernel = ORB::kKernelWidth / 2; @@ -455,13 +469,15 @@ ORB::ORB(size_t n_features, const CommonParams & detector_params) : params_(detector_params), n_features_(n_features) { // fill the extractors and descriptors for the corresponding scales - int n_desired_features_per_scale = cvRound(n_features / ((1.0 / std::pow(params_.scale_factor_, 2.f * params_.n_levels_) - 1) - / (1.0 / std::pow(params_.scale_factor_, 2) - 1))); + int n_desired_features_per_scale = cvRound( + n_features / ((1.0 / std::pow(params_.scale_factor_, + 2.f * params_.n_levels_) - 1) / (1.0 + / std::pow(params_.scale_factor_, 2) - 1))); n_features_per_level_.resize(detector_params.n_levels_); for (unsigned int level = 0; level < detector_params.n_levels_; level++) { - n_desired_features_per_scale = cvRound(n_desired_features_per_scale / std::pow(params_.scale_factor_, 2)); n_features_per_level_[level] = n_desired_features_per_scale; + n_desired_features_per_scale = cvRound(n_desired_features_per_scale / std::pow(params_.scale_factor_, 2)); } // pre-compute the end of a row in a circular patch @@ -481,7 +497,8 @@ ORB::ORB(size_t n_features, const CommonParams & detector_params) : } /** returns the descriptor size in bytes */ -int ORB::descriptorSize() const { +int ORB::descriptorSize() const +{ return kBytes; } @@ -602,6 +619,25 @@ void ORB::operator()(const cv::Mat &image, const cv::Mat &mask, std::vector& keypoints, size_t n_points) +{ + //this is only necessary if the keypoints size is greater than the number of desired points. + if (keypoints.size() > n_points) + { + //first use nth element to partition the keypoints into the best and worst. + std::nth_element(keypoints.begin(), keypoints.begin() + n_points, keypoints.end(), keypointResponseGreater); + //this is the boundary response, and in the case of FAST may be ambigous + float ambiguous_response = keypoints[n_points - 1].response; + //use std::partition to grab all of the keypoints with the boundary response. + std::vector::const_iterator new_end = + std::partition(keypoints.begin() + n_points, keypoints.end(), + KeypointResponseGreaterThanEqual(ambiguous_response)); + //resize the keypoints, given this new end point. nth_element and partition reordered the points inplace + keypoints.resize(new_end - keypoints.begin()); + } +} + /** Compute the ORB keypoints on an image * @param image_pyramid the image pyramid to compute the features and descriptors on * @param mask_pyramid the masks to apply at every level @@ -629,18 +665,14 @@ void ORB::computeKeyPoints(const std::vector& image_pyramid, const std: // half_patch_size_ for orientation, 4 for Harris unsigned int border_safety = std::max(half_patch_size_, 4); cv::KeyPointsFilter::runByImageBorder(keypoints, image_pyramid[level].size(), border_safety); - // Keep more points than necessary as FAST does not give amazing corners - if (keypoints.size() > 2 * n_features_per_level_[level]) - { - std::nth_element(keypoints.begin(), keypoints.begin() + 2 * n_features_per_level_[level], keypoints.end(), - keypointResponseGreater); - keypoints.resize(2 * n_features_per_level_[level]); - } + cull(keypoints, 2 * n_features_per_level_[level]); // Compute the Harris cornerness (better scoring than FAST) HarrisResponse h(image_pyramid[level]); h(keypoints); + //cull to the final desired level, using the new harris scores. + cull(keypoints, n_features_per_level_[level]); // Set the level of the coordinates for (std::vector::iterator keypoint = keypoints.begin(), keypoint_end = keypoints.end(); keypoint @@ -650,14 +682,6 @@ void ORB::computeKeyPoints(const std::vector& image_pyramid, const std: all_keypoints.insert(all_keypoints.end(), keypoints.begin(), keypoints.end()); } - // Only keep what we need - if (all_keypoints.size() > n_features_) - { - std::nth_element(all_keypoints.begin(), all_keypoints.begin() + n_features_, all_keypoints.end(), - keypointResponseGreater); - all_keypoints.resize(n_features_); - } - // Cluster the keypoints for (std::vector::iterator keypoint = all_keypoints.begin(), keypoint_end = all_keypoints.end(); keypoint != keypoint_end; ++keypoint)