{
public:
/** The patch sizes that can be used (only one right now) */
- enum PatchSize
- {
- PATCH_LEARNED_31 = 31
- };
-
struct CommonParams
{
- static const unsigned int DEFAULT_N_LEVELS = 3;
- static const float DEFAULT_SCALE_FACTOR = 1.2;
- static const unsigned int DEFAULT_FIRST_LEVEL = 0;
- static const PatchSize DEFAULT_PATCH_SIZE = PATCH_LEARNED_31;
+ enum { DEFAULT_N_LEVELS = 3, DEFAULT_FIRST_LEVEL = 0};
/** default constructor */
- CommonParams(float scale_factor = DEFAULT_SCALE_FACTOR, unsigned int n_levels = DEFAULT_N_LEVELS,
- unsigned int first_level = DEFAULT_FIRST_LEVEL, PatchSize patch_size = DEFAULT_PATCH_SIZE);
+ CommonParams(float scale_factor = 1.2f, unsigned int n_levels = DEFAULT_N_LEVELS,
+ int edge_threshold = 31, unsigned int first_level = DEFAULT_FIRST_LEVEL);
void read(const FileNode& fn);
void write(FileStorage& fs) const;
* if 1, that means we will also look at the image scale_factor_ times bigger
*/
unsigned int first_level_;
- /** The size of the patch that will be used for orientation and comparisons */
- PatchSize patch_size_;
+ /** How far from the boundary the points should be */
+ int edge_threshold_;
};
// c:function::default constructor
struct CV_EXPORTS CommonParams
{
- enum { DEFAULT_N_LEVELS = 3, DEFAULT_FIRST_LEVEL = 0, DEFAULT_PATCH_SIZE = 31 };
+ enum { DEFAULT_N_LEVELS = 3, DEFAULT_FIRST_LEVEL = 0};
/** default constructor */
- CommonParams(float scale_factor = 1.2f, unsigned int n_levels = DEFAULT_N_LEVELS,
- unsigned int first_level = DEFAULT_FIRST_LEVEL, int patch_size = DEFAULT_PATCH_SIZE) :
+ CommonParams(float scale_factor = 1.2f, unsigned int n_levels = DEFAULT_N_LEVELS, int edge_threshold = 31,
+ unsigned int first_level = DEFAULT_FIRST_LEVEL) :
scale_factor_(scale_factor), n_levels_(n_levels), first_level_(first_level >= n_levels ? 0 : first_level),
- patch_size_(patch_size)
+ edge_threshold_(edge_threshold)
{
+ // No other patch size is supported right now
+ patch_size_ = 31;
}
void read(const FileNode& fn);
void write(FileStorage& fs) const;
* if 1, that means we will also look at the image scale_factor_ times bigger
*/
unsigned int first_level_;
+ /** How far from the boundary the points should be */
+ int edge_threshold_;
+
+ friend class ORB;
+ protected:
/** The size of the patch that will be used for orientation and comparisons */
int patch_size_;
};
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)));
+ float factor = 1.0 / params_.scale_factor_ / params_.scale_factor_;
+ int n_desired_features_per_scale = cvRound(n_features / ((std::pow(factor, params_.n_levels_) - 1) / (factor - 1)));
n_features_per_level_.resize(detector_params.n_levels_);
for (unsigned int level = 0; level < detector_params.n_levels_; level++)
{
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));
+ n_desired_features_per_scale = cvRound(n_desired_features_per_scale * factor);
}
+ // Make sure we forget about what is too close to the boundary
+ params_.edge_threshold_ = std::max(params_.edge_threshold_, params_.patch_size_ + kKernelWidth / 2 + 2);
+
// pre-compute the end of a row in a circular patch
half_patch_size_ = params_.patch_size_ / 2;
u_max_.resize(half_patch_size_ + 1);
}
// Pre-compute the keypoints (we keep the best over all scales, so this has to be done beforehand
- std::vector<std::vector<cv::KeyPoint> > all_keypoints;
+ std::vector < std::vector<cv::KeyPoint> > all_keypoints;
if (do_keypoints)
+ // Get keypoints, those will be far enough from the border that no check will be required for the descriptor
computeKeyPoints(image_pyramid, mask_pyramid, all_keypoints);
else
{
- // Cluster the input keypoints
+ // Remove keypoints very close to the border
+ cv::KeyPointsFilter::runByImageBorder(keypoints_in_out, image.size(), params_.edge_threshold_);
+
+ // Cluster the input keypoints depending on the level they were computed at
all_keypoints.resize(params_.n_levels_);
for (std::vector<cv::KeyPoint>::iterator keypoint = keypoints_in_out.begin(), keypoint_end = keypoints_in_out.end(); keypoint
!= keypoint_end; ++keypoint)
std::vector<cv::KeyPoint> all_keypoints;
all_keypoints.reserve(2 * n_features_);
+ // half_patch_size_ for orientation, 4 for Harris
+ unsigned int edge_threshold = std::max(std::max(half_patch_size_, 4), params_.edge_threshold_);
+
for (unsigned int level = 0; level < params_.n_levels_; ++level)
{
all_keypoints_out[level].reserve(n_features_per_level_[level]);
fd.detect(image_pyramid[level], keypoints, mask_pyramid[level]);
// Remove keypoints very close to the border
- // 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);
+ cv::KeyPointsFilter::runByImageBorder(keypoints, image_pyramid[level].size(), edge_threshold);
+
// Keep more points than necessary as FAST does not give amazing corners
cull(keypoints, 2 * n_features_per_level_[level]);
if (image.type() != CV_8UC1)
cv::cvtColor(image, gray_image, CV_BGR2GRAY);
- int border_safety = params_.patch_size_ + kKernelWidth / 2 + 2;
- //Remove keypoints very close to the border
- cv::KeyPointsFilter::runByImageBorder(keypoints, image.size(), border_safety);
-
// Get the patterns to apply
OrbPatterns* patterns = patterns_[level];