From 1a5fcd715d6649dfe8cc8bd065c106a572414331 Mon Sep 17 00:00:00 2001 From: Ievgen Khvedchenia Date: Fri, 9 May 2014 18:46:00 +0300 Subject: [PATCH] Refactor of KAZE and AKAZE: 1) Clean-up from the unused code 2) Remove of SURF extraction method 3) Enabled threading for KAZE extraction 4) Exposed new properties for runtime configuration --- .../features2d/include/opencv2/features2d.hpp | 25 +- modules/features2d/src/akaze.cpp | 68 +- modules/features2d/src/akaze/AKAZEConfig.h | 33 +- .../features2d/src/akaze/AKAZEFeatures.cpp | 285 +----- modules/features2d/src/features2d_init.cpp | 2 + modules/features2d/src/kaze.cpp | 19 +- modules/features2d/src/kaze/KAZEConfig.h | 141 ++- modules/features2d/src/kaze/KAZEFeatures.cpp | 928 +++++------------- modules/features2d/src/kaze/KAZEFeatures.h | 111 +-- modules/features2d/test/test_keypoints.cpp | 14 +- 10 files changed, 481 insertions(+), 1145 deletions(-) diff --git a/modules/features2d/include/opencv2/features2d.hpp b/modules/features2d/include/opencv2/features2d.hpp index b6f9e44490..f3ff13aaad 100644 --- a/modules/features2d/include/opencv2/features2d.hpp +++ b/modules/features2d/include/opencv2/features2d.hpp @@ -893,7 +893,15 @@ KAZE implementation class CV_EXPORTS_W KAZE : public Feature2D { public: - CV_WRAP explicit KAZE(bool _extended = false); + + /// AKAZE Descriptor Type + enum DESCRIPTOR_TYPE { + DESCRIPTOR_MSURF = 1, + DESCRIPTOR_GSURF = 2 + }; + + CV_WRAP KAZE(); + CV_WRAP explicit KAZE(DESCRIPTOR_TYPE type, bool _extended, bool _upright); virtual ~KAZE(); @@ -917,7 +925,9 @@ protected: void detectImpl(InputArray image, std::vector& keypoints, InputArray mask) const; void computeImpl(InputArray image, std::vector& keypoints, OutputArray descriptors) const; + CV_PROP int descriptor; CV_PROP bool extended; + CV_PROP bool upright; }; /*! @@ -926,7 +936,16 @@ AKAZE implementation class CV_EXPORTS_W AKAZE : public Feature2D { public: - CV_WRAP explicit AKAZE(int _descriptor = 5, int _descriptor_size = 0, int _descriptor_channels = 3); + /// AKAZE Descriptor Type + enum DESCRIPTOR_TYPE { + DESCRIPTOR_KAZE_UPRIGHT = 2, ///< Upright descriptors, not invariant to rotation + DESCRIPTOR_KAZE = 3, + DESCRIPTOR_MLDB_UPRIGHT = 4, ///< Upright descriptors, not invariant to rotation + DESCRIPTOR_MLDB = 5 + }; + + CV_WRAP AKAZE(); + CV_WRAP explicit AKAZE(DESCRIPTOR_TYPE _descriptor, int _descriptor_size = 0, int _descriptor_channels = 3); virtual ~AKAZE(); @@ -951,8 +970,8 @@ protected: void computeImpl(InputArray image, std::vector& keypoints, OutputArray descriptors) const; void detectImpl(InputArray image, std::vector& keypoints, InputArray mask = noArray()) const; - CV_PROP int descriptor_channels; CV_PROP int descriptor; + CV_PROP int descriptor_channels; CV_PROP int descriptor_size; }; diff --git a/modules/features2d/src/akaze.cpp b/modules/features2d/src/akaze.cpp index c5e2134dff..0c0df7c1d9 100644 --- a/modules/features2d/src/akaze.cpp +++ b/modules/features2d/src/akaze.cpp @@ -53,10 +53,16 @@ http://www.robesafe.com/personal/pablo.alcantarilla/papers/Alcantarilla13bmvc.pd namespace cv { + AKAZE::AKAZE() + : descriptor(DESCRIPTOR_MLDB) + , descriptor_channels(3) + , descriptor_size(0) + { + } - AKAZE::AKAZE(int _descriptor, int _descriptor_size, int _descriptor_channels) - : descriptor_channels(_descriptor_channels) - , descriptor(_descriptor) + AKAZE::AKAZE(DESCRIPTOR_TYPE _descriptor, int _descriptor_size, int _descriptor_channels) + : descriptor(_descriptor) + , descriptor_channels(_descriptor_channels) , descriptor_size(_descriptor_size) { @@ -70,12 +76,14 @@ namespace cv // returns the descriptor size in bytes int AKAZE::descriptorSize() const { - if (descriptor < MLDB_UPRIGHT) + switch (descriptor) { + case cv::AKAZE::DESCRIPTOR_KAZE: + case cv::AKAZE::DESCRIPTOR_KAZE_UPRIGHT: return 64; - } - else - { + + case cv::AKAZE::DESCRIPTOR_MLDB: + case cv::AKAZE::DESCRIPTOR_MLDB_UPRIGHT: // We use the full length binary descriptor -> 486 bits if (descriptor_size == 0) { @@ -87,32 +95,45 @@ namespace cv // We use the random bit selection length binary descriptor return (int)ceil(descriptor_size / 8.); } + + default: + return -1; } } // returns the descriptor type int AKAZE::descriptorType() const { - if (descriptor < MLDB_UPRIGHT) + switch (descriptor) { - return CV_32F; - } - else - { - return CV_8U; + case cv::AKAZE::DESCRIPTOR_KAZE: + case cv::AKAZE::DESCRIPTOR_KAZE_UPRIGHT: + return CV_32F; + + case cv::AKAZE::DESCRIPTOR_MLDB: + case cv::AKAZE::DESCRIPTOR_MLDB_UPRIGHT: + return CV_8U; + + default: + return -1; } } // returns the default norm type int AKAZE::defaultNorm() const { - if (descriptor < MLDB_UPRIGHT) + switch (descriptor) { - return NORM_L2; - } - else - { - return NORM_HAMMING; + case cv::AKAZE::DESCRIPTOR_KAZE: + case cv::AKAZE::DESCRIPTOR_KAZE_UPRIGHT: + return cv::NORM_L2; + + case cv::AKAZE::DESCRIPTOR_MLDB: + case cv::AKAZE::DESCRIPTOR_MLDB_UPRIGHT: + return cv::NORM_HAMMING; + + default: + return -1; } } @@ -132,6 +153,9 @@ namespace cv cv::Mat& desc = descriptors.getMatRef(); AKAZEOptions options; + options.descriptor = static_cast(descriptor); + options.descriptor_channels = descriptor_channels; + options.descriptor_size = descriptor_size; options.img_width = img.cols; options.img_height = img.rows; @@ -164,6 +188,9 @@ namespace cv img.convertTo(img1_32, CV_32F, 1.0 / 255.0, 0); AKAZEOptions options; + options.descriptor = static_cast(descriptor); + options.descriptor_channels = descriptor_channels; + options.descriptor_size = descriptor_size; options.img_width = img.cols; options.img_height = img.rows; @@ -189,6 +216,9 @@ namespace cv cv::Mat& desc = descriptors.getMatRef(); AKAZEOptions options; + options.descriptor = static_cast(descriptor); + options.descriptor_channels = descriptor_channels; + options.descriptor_size = descriptor_size; options.img_width = img.cols; options.img_height = img.rows; diff --git a/modules/features2d/src/akaze/AKAZEConfig.h b/modules/features2d/src/akaze/AKAZEConfig.h index acf165bf98..1c1203f574 100644 --- a/modules/features2d/src/akaze/AKAZEConfig.h +++ b/modules/features2d/src/akaze/AKAZEConfig.h @@ -10,6 +10,7 @@ /* ************************************************************************* */ // OpenCV #include "precomp.hpp" +#include /* ************************************************************************* */ /// Lookup table for 2d gaussian (sigma = 2.5) where (0,0) is top left and (6,6) is bottom right @@ -23,30 +24,18 @@ const float gauss25[7][7] = { { 0.00142946f, 0.00131956f, 0.00103800f, 0.00069579f, 0.00039744f, 0.00019346f, 0.00008024f } }; -/* ************************************************************************* */ -/// AKAZE Descriptor Type -enum DESCRIPTOR_TYPE { - SURF_UPRIGHT = 0, ///< Upright descriptors, not invariant to rotation - SURF = 1, - MSURF_UPRIGHT = 2, ///< Upright descriptors, not invariant to rotation - MSURF = 3, - MLDB_UPRIGHT = 4, ///< Upright descriptors, not invariant to rotation - MLDB = 5 -}; - -/* ************************************************************************* */ -/// AKAZE Diffusivities -enum DIFFUSIVITY_TYPE { - PM_G1 = 0, - PM_G2 = 1, - WEICKERT = 2, - CHARBONNIER = 3 -}; - /* ************************************************************************* */ /// AKAZE configuration options structure struct AKAZEOptions { + /// AKAZE Diffusivities + enum DIFFUSIVITY_TYPE { + PM_G1 = 0, + PM_G2 = 1, + WEICKERT = 2, + CHARBONNIER = 3 + }; + AKAZEOptions() : omax(4) , nsublevels(4) @@ -60,7 +49,7 @@ struct AKAZEOptions { , dthreshold(0.001f) , min_dthreshold(0.00001f) - , descriptor(MLDB) + , descriptor(cv::AKAZE::DESCRIPTOR_MLDB) , descriptor_size(0) , descriptor_channels(3) , descriptor_pattern_size(10) @@ -83,7 +72,7 @@ struct AKAZEOptions { float dthreshold; ///< Detector response threshold to accept point float min_dthreshold; ///< Minimum detector threshold to accept a point - DESCRIPTOR_TYPE descriptor; ///< Type of descriptor + cv::AKAZE::DESCRIPTOR_TYPE descriptor; ///< Type of descriptor int descriptor_size; ///< Size of the descriptor in bits. 0->Full size int descriptor_channels; ///< Number of channels in the descriptor (1, 2, 3) int descriptor_pattern_size; ///< Actual patch size is 2*pattern_size*point.scale diff --git a/modules/features2d/src/akaze/AKAZEFeatures.cpp b/modules/features2d/src/akaze/AKAZEFeatures.cpp index b1a4ba57d2..e5955b21c2 100644 --- a/modules/features2d/src/akaze/AKAZEFeatures.cpp +++ b/modules/features2d/src/akaze/AKAZEFeatures.cpp @@ -25,7 +25,8 @@ AKAZEFeatures::AKAZEFeatures(const AKAZEOptions& options) : options_(options) { ncycles_ = 0; reordering_ = true; - if (options_.descriptor_size > 0 && options_.descriptor >= MLDB_UPRIGHT) { + if (options_.descriptor_size > 0 && options_.descriptor >= cv::AKAZE::DESCRIPTOR_MLDB_UPRIGHT) + { generateDescriptorSubsample(descriptorSamples_, descriptorBits_, options_.descriptor_size, options_.descriptor_pattern_size, options_.descriptor_channels); } @@ -124,16 +125,16 @@ int AKAZEFeatures::Create_Nonlinear_Scale_Space(const cv::Mat& img) // Compute the conductivity equation switch (options_.diffusivity) { - case PM_G1: + case AKAZEOptions::PM_G1: pm_g1(evolution_[i].Lx, evolution_[i].Ly, evolution_[i].Lflow, options_.kcontrast); break; - case PM_G2: + case AKAZEOptions::PM_G2: pm_g2(evolution_[i].Lx, evolution_[i].Ly, evolution_[i].Lflow, options_.kcontrast); break; - case WEICKERT: + case AKAZEOptions::WEICKERT: weickert_diffusivity(evolution_[i].Lx, evolution_[i].Ly, evolution_[i].Lflow, options_.kcontrast); break; - case CHARBONNIER: + case AKAZEOptions::CHARBONNIER: charbonnier_diffusivity(evolution_[i].Lx, evolution_[i].Ly, evolution_[i].Lflow, options_.kcontrast); break; default: @@ -170,8 +171,8 @@ class MultiscaleDerivativesInvoker : public cv::ParallelLoopBody { public: explicit MultiscaleDerivativesInvoker(std::vector& ev, const AKAZEOptions& opt) - : evolution_(&ev) - , options_(opt) + : evolution_(&ev) + , options_(opt) { } @@ -210,7 +211,7 @@ private: void AKAZEFeatures::Compute_Multiscale_Derivatives(void) { cv::parallel_for_(cv::Range(0, (int)evolution_.size()), - MultiscaleDerivativesInvoker(evolution_, options_)); + MultiscaleDerivativesInvoker(evolution_, options_)); } /* ************************************************************************* */ @@ -255,11 +256,10 @@ void AKAZEFeatures::Find_Scale_Space_Extrema(std::vector& kpts) vector kpts_aux; // Set maximum size - if (options_.descriptor == SURF_UPRIGHT || options_.descriptor == SURF || - options_.descriptor == MLDB_UPRIGHT || options_.descriptor == MLDB) { + if (options_.descriptor == cv::AKAZE::DESCRIPTOR_MLDB_UPRIGHT || options_.descriptor == cv::AKAZE::DESCRIPTOR_MLDB) { smax = 10.0f*sqrtf(2.0f); } - else if (options_.descriptor == MSURF_UPRIGHT || options_.descriptor == MSURF) { + else if (options_.descriptor == cv::AKAZE::DESCRIPTOR_KAZE_UPRIGHT || options_.descriptor == cv::AKAZE::DESCRIPTOR_KAZE) { smax = 12.0f*sqrtf(2.0f); } @@ -574,15 +574,15 @@ class Upright_MLDB_Descriptor_Subset_Invoker : public cv::ParallelLoopBody { public: Upright_MLDB_Descriptor_Subset_Invoker(std::vector& kpts, - cv::Mat& desc, - std::vector& evolution, - AKAZEOptions& options, - cv::Mat descriptorSamples, - cv::Mat descriptorBits) - : keypoints_(&kpts) - , descriptors_(&desc) - , evolution_(&evolution) - , options_(&options) + cv::Mat& desc, + std::vector& evolution, + AKAZEOptions& options, + cv::Mat descriptorSamples, + cv::Mat descriptorBits) + : keypoints_(&kpts) + , descriptors_(&desc) + , evolution_(&evolution) + , options_(&options) , descriptorSamples_(descriptorSamples) , descriptorBits_(descriptorBits) { @@ -641,15 +641,15 @@ class MLDB_Descriptor_Subset_Invoker : public cv::ParallelLoopBody { public: MLDB_Descriptor_Subset_Invoker(std::vector& kpts, - cv::Mat& desc, - std::vector& evolution, - AKAZEOptions& options, - cv::Mat descriptorSamples, - cv::Mat descriptorBits) - : keypoints_(&kpts) - , descriptors_(&desc) - , evolution_(&evolution) - , options_(&options) + cv::Mat& desc, + std::vector& evolution, + AKAZEOptions& options, + cv::Mat descriptorSamples, + cv::Mat descriptorBits) + : keypoints_(&kpts) + , descriptors_(&desc) + , evolution_(&evolution) + , options_(&options) , descriptorSamples_(descriptorSamples) , descriptorBits_(descriptorBits) { @@ -684,7 +684,7 @@ private: void AKAZEFeatures::Compute_Descriptors(std::vector& kpts, cv::Mat& desc) { // Allocate memory for the matrix with the descriptors - if (options_.descriptor < MLDB_UPRIGHT) { + if (options_.descriptor < cv::AKAZE::DESCRIPTOR_MLDB_UPRIGHT) { desc = cv::Mat::zeros((int)kpts.size(), 64, CV_32FC1); } else { @@ -699,29 +699,19 @@ void AKAZEFeatures::Compute_Descriptors(std::vector& kpts, cv::Mat } } - switch (options_.descriptor) { - - case SURF_UPRIGHT: // Upright descriptors, not invariant to rotation + switch (options_.descriptor) { - cv::parallel_for_(cv::Range(0, (int)kpts.size()), SURF_Descriptor_Upright_64_Invoker(kpts, desc, evolution_)); - } - break; - case SURF: - { - cv::parallel_for_(cv::Range(0, (int)kpts.size()), SURF_Descriptor_64_Invoker(kpts, desc, evolution_)); - } - break; - case MSURF_UPRIGHT: // Upright descriptors, not invariant to rotation + case cv::AKAZE::DESCRIPTOR_KAZE_UPRIGHT: // Upright descriptors, not invariant to rotation { cv::parallel_for_(cv::Range(0, (int)kpts.size()), MSURF_Upright_Descriptor_64_Invoker(kpts, desc, evolution_)); } break; - case MSURF: + case cv::AKAZE::DESCRIPTOR_KAZE: { cv::parallel_for_(cv::Range(0, (int)kpts.size()), MSURF_Descriptor_64_Invoker(kpts, desc, evolution_)); } break; - case MLDB_UPRIGHT: // Upright descriptors, not invariant to rotation + case cv::AKAZE::DESCRIPTOR_MLDB_UPRIGHT: // Upright descriptors, not invariant to rotation { if (options_.descriptor_size == 0) cv::parallel_for_(cv::Range(0, (int)kpts.size()), Upright_MLDB_Full_Descriptor_Invoker(kpts, desc, evolution_, options_)); @@ -729,7 +719,7 @@ void AKAZEFeatures::Compute_Descriptors(std::vector& kpts, cv::Mat cv::parallel_for_(cv::Range(0, (int)kpts.size()), Upright_MLDB_Descriptor_Subset_Invoker(kpts, desc, evolution_, options_, descriptorSamples_, descriptorBits_)); } break; - case MLDB: + case cv::AKAZE::DESCRIPTOR_MLDB: { if (options_.descriptor_size == 0) cv::parallel_for_(cv::Range(0, (int)kpts.size()), MLDB_Full_Descriptor_Invoker(kpts, desc, evolution_, options_)); @@ -783,7 +773,7 @@ void AKAZEFeatures::Compute_Main_Orientation(cv::KeyPoint& kpt, const std::vecto // Loop slides pi/3 window around feature point for (ang1 = 0; ang1 < (float)(2.0 * CV_PI); ang1 += 0.15f) { - ang2 = (ang1 + (float)(CV_PI / 3.0) > (float)(2.0*CV_PI) ? ang1 - (float)(5.0*CV_PI / 3.0) : ang1 + (float)(CV_PI / 3.0)); + ang2 = (ang1 + (float)(CV_PI / 3.0) >(float)(2.0*CV_PI) ? ang1 - (float)(5.0*CV_PI / 3.0) : ang1 + (float)(CV_PI / 3.0)); sumX = sumY = 0.f; for (size_t k = 0; k < Ang.size(); ++k) { @@ -812,195 +802,6 @@ void AKAZEFeatures::Compute_Main_Orientation(cv::KeyPoint& kpt, const std::vecto } } -/* ************************************************************************* */ -/** - * @brief This method computes the upright descriptor of the provided keypoint - * @param kpt Input keypoint - * @note Rectangular grid of 20 s x 20 s. Descriptor Length 64. No additional - * Gaussian weighting is performed. The descriptor is inspired from Bay et al., - * Speeded Up Robust Features, ECCV, 2006 - */ -void SURF_Descriptor_Upright_64_Invoker::Get_SURF_Descriptor_Upright_64(const cv::KeyPoint& kpt, float *desc) const { - - float dx = 0.0, dy = 0.0, mdx = 0.0, mdy = 0.0; - float rx = 0.0, ry = 0.0, len = 0.0, xf = 0.0, yf = 0.0; - float sample_x = 0.0, sample_y = 0.0; - float fx = 0.0, fy = 0.0, ratio = 0.0, res1 = 0.0, res2 = 0.0, res3 = 0.0, res4 = 0.0; - int x1 = 0, y1 = 0, x2 = 0, y2 = 0, sample_step = 0, pattern_size = 0, dcount = 0; - int scale = 0, dsize = 0, level = 0; - - const std::vector& evolution = *evolution_; - - // Set the descriptor size and the sample and pattern sizes - dsize = 64; - sample_step = 5; - pattern_size = 10; - - // Get the information from the keypoint - ratio = (float)(1 << kpt.octave); - scale = fRound(0.5f*kpt.size / ratio); - level = kpt.class_id; - yf = kpt.pt.y / ratio; - xf = kpt.pt.x / ratio; - - // Calculate descriptor for this interest point - for (int i = -pattern_size; i < pattern_size; i += sample_step) { - for (int j = -pattern_size; j < pattern_size; j += sample_step) { - dx = dy = mdx = mdy = 0.0; - - for (int k = i; k < i + sample_step; k++) { - for (int l = j; l < j + sample_step; l++) { - // Get the coordinates of the sample point on the rotated axis - sample_y = yf + l*scale; - sample_x = xf + k*scale; - - y1 = (int)(sample_y - 0.5f); - x1 = (int)(sample_x - 0.5f); - - y2 = (int)(sample_y + 0.5f); - x2 = (int)(sample_x + 0.5f); - - fx = sample_x - x1; - fy = sample_y - y1; - - res1 = *(evolution[level].Lx.ptr(y1)+x1); - res2 = *(evolution[level].Lx.ptr(y1)+x2); - res3 = *(evolution[level].Lx.ptr(y2)+x1); - res4 = *(evolution[level].Lx.ptr(y2)+x2); - rx = (1.0f - fx)*(1.0f - fy)*res1 + fx*(1.0f - fy)*res2 + (1.0f - fx)*fy*res3 + fx*fy*res4; - - res1 = *(evolution[level].Ly.ptr(y1)+x1); - res2 = *(evolution[level].Ly.ptr(y1)+x2); - res3 = *(evolution[level].Ly.ptr(y2)+x1); - res4 = *(evolution[level].Ly.ptr(y2)+x2); - ry = (1.0f - fx)*(1.0f - fy)*res1 + fx*(1.0f - fy)*res2 + (1.0f - fx)*fy*res3 + fx*fy*res4; - - // Sum the derivatives to the cumulative descriptor - dx += rx; - dy += ry; - mdx += fabs(rx); - mdy += fabs(ry); - } - } - - // Add the values to the descriptor vector - desc[dcount++] = dx; - desc[dcount++] = dy; - desc[dcount++] = mdx; - desc[dcount++] = mdy; - - // Store the current length^2 of the vector - len += dx*dx + dy*dy + mdx*mdx + mdy*mdy; - } - } - - // convert to unit vector - len = sqrt(len); - - for (int i = 0; i < dsize; i++) { - desc[i] /= len; - } -} - -/* ************************************************************************* */ -/** - * @brief This method computes the descriptor of the provided keypoint given the - * main orientation - * @param kpt Input keypoint - * @param desc Descriptor vector - * @note Rectangular grid of 20 s x 20 s. Descriptor Length 64. No additional - * Gaussian weighting is performed. The descriptor is inspired from Bay et al., - * Speeded Up Robust Features, ECCV, 2006 - */ -void SURF_Descriptor_64_Invoker::Get_SURF_Descriptor_64(const cv::KeyPoint& kpt, float *desc) const { - - float dx = 0.0, dy = 0.0, mdx = 0.0, mdy = 0.0; - float rx = 0.0, ry = 0.0, rrx = 0.0, rry = 0.0, len = 0.0, xf = 0.0, yf = 0.0; - float sample_x = 0.0, sample_y = 0.0, co = 0.0, si = 0.0, angle = 0.0; - float fx = 0.0, fy = 0.0, ratio = 0.0, res1 = 0.0, res2 = 0.0, res3 = 0.0, res4 = 0.0; - int x1 = 0, y1 = 0, x2 = 0, y2 = 0, sample_step = 0, pattern_size = 0, dcount = 0; - int scale = 0, dsize = 0, level = 0; - - // Set the descriptor size and the sample and pattern sizes - dsize = 64; - sample_step = 5; - pattern_size = 10; - - const std::vector& evolution = *evolution_; - - // Get the information from the keypoint - ratio = (float)(1 << kpt.octave); - scale = fRound(0.5f*kpt.size / ratio); - angle = kpt.angle; - level = kpt.class_id; - yf = kpt.pt.y / ratio; - xf = kpt.pt.x / ratio; - co = cos(angle); - si = sin(angle); - - // Calculate descriptor for this interest point - for (int i = -pattern_size; i < pattern_size; i += sample_step) { - for (int j = -pattern_size; j < pattern_size; j += sample_step) { - dx = dy = mdx = mdy = 0.0; - - for (int k = i; k < i + sample_step; k++) { - for (int l = j; l < j + sample_step; l++) { - // Get the coordinates of the sample point on the rotated axis - sample_y = yf + (l*scale*co + k*scale*si); - sample_x = xf + (-l*scale*si + k*scale*co); - - y1 = (int)(sample_y - 0.5f); - x1 = (int)(sample_x - 0.5f); - - y2 = (int)(sample_y + 0.5f); - x2 = (int)(sample_x + 0.5f); - - fx = sample_x - x1; - fy = sample_y - y1; - - res1 = *(evolution[level].Lx.ptr(y1)+x1); - res2 = *(evolution[level].Lx.ptr(y1)+x2); - res3 = *(evolution[level].Lx.ptr(y2)+x1); - res4 = *(evolution[level].Lx.ptr(y2)+x2); - rx = (1.0f - fx)*(1.0f - fy)*res1 + fx*(1.0f - fy)*res2 + (1.0f - fx)*fy*res3 + fx*fy*res4; - - res1 = *(evolution[level].Ly.ptr(y1)+x1); - res2 = *(evolution[level].Ly.ptr(y1)+x2); - res3 = *(evolution[level].Ly.ptr(y2)+x1); - res4 = *(evolution[level].Ly.ptr(y2)+x2); - ry = (1.0f - fx)*(1.0f - fy)*res1 + fx*(1.0f - fy)*res2 + (1.0f - fx)*fy*res3 + fx*fy*res4; - - // Get the x and y derivatives on the rotated axis - rry = rx*co + ry*si; - rrx = -rx*si + ry*co; - - // Sum the derivatives to the cumulative descriptor - dx += rrx; - dy += rry; - mdx += fabs(rrx); - mdy += fabs(rry); - } - } - - // Add the values to the descriptor vector - desc[dcount++] = dx; - desc[dcount++] = dy; - desc[dcount++] = mdx; - desc[dcount++] = mdy; - - // Store the current length^2 of the vector - len += dx*dx + dy*dy + mdx*mdx + mdy*mdy; - } - } - - // convert to unit vector - len = sqrt(len); - - for (int i = 0; i < dsize; i++) { - desc[i] /= len; - } -} - /* ************************************************************************* */ /** * @brief This method computes the upright descriptor (not rotation invariant) of @@ -1271,8 +1072,8 @@ void Upright_MLDB_Full_Descriptor_Invoker::Get_Upright_MLDB_Full_Descriptor(cons const std::vector& evolution = *evolution_; // Matrices for the M-LDB descriptor - cv::Mat values_1 = cv::Mat::zeros(4, options.descriptor_channels, CV_32FC1); - cv::Mat values_2 = cv::Mat::zeros(9, options.descriptor_channels, CV_32FC1); + cv::Mat values_1 = cv::Mat::zeros(4, options.descriptor_channels, CV_32FC1); + cv::Mat values_2 = cv::Mat::zeros(9, options.descriptor_channels, CV_32FC1); cv::Mat values_3 = cv::Mat::zeros(16, options.descriptor_channels, CV_32FC1); // Get the information from the keypoint @@ -1484,12 +1285,12 @@ void MLDB_Full_Descriptor_Invoker::Get_MLDB_Full_Descriptor(const cv::KeyPoint& int level = 0, nsamples = 0, scale = 0; int dcount1 = 0, dcount2 = 0; - const AKAZEOptions & options = *options_; + const AKAZEOptions & options = *options_; const std::vector& evolution = *evolution_; // Matrices for the M-LDB descriptor - cv::Mat values_1 = cv::Mat::zeros(4, options.descriptor_channels, CV_32FC1); - cv::Mat values_2 = cv::Mat::zeros(9, options.descriptor_channels, CV_32FC1); + cv::Mat values_1 = cv::Mat::zeros(4, options.descriptor_channels, CV_32FC1); + cv::Mat values_2 = cv::Mat::zeros(9, options.descriptor_channels, CV_32FC1); cv::Mat values_3 = cv::Mat::zeros(16, options.descriptor_channels, CV_32FC1); // Get the information from the keypoint @@ -2077,11 +1878,11 @@ inline float get_angle(float x, float y) { } if (x < 0 && y >= 0) { - return static_cast(CV_PI) - atanf(-y / x); + return static_cast(CV_PI)-atanf(-y / x); } if (x < 0 && y < 0) { - return static_cast(CV_PI) + atanf(y / x); + return static_cast(CV_PI)+atanf(y / x); } if (x >= 0 && y < 0) { diff --git a/modules/features2d/src/features2d_init.cpp b/modules/features2d/src/features2d_init.cpp index e3a3b3c363..c0365274de 100644 --- a/modules/features2d/src/features2d_init.cpp +++ b/modules/features2d/src/features2d_init.cpp @@ -126,6 +126,8 @@ CV_INIT_ALGORITHM(GFTTDetector, "Feature2D.GFTT", /////////////////////////////////////////////////////////////////////////////////////////////////////////// CV_INIT_ALGORITHM(KAZE, "Feature2D.KAZE", + obj.info()->addParam(obj, "descriptor", obj.descriptor); + obj.info()->addParam(obj, "upright", obj.upright); obj.info()->addParam(obj, "extended", obj.extended)) /////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/modules/features2d/src/kaze.cpp b/modules/features2d/src/kaze.cpp index 85835d8a18..dbb09a75e1 100644 --- a/modules/features2d/src/kaze.cpp +++ b/modules/features2d/src/kaze.cpp @@ -52,11 +52,20 @@ http://www.robesafe.com/personal/pablo.alcantarilla/papers/Alcantarilla12eccv.pd namespace cv { - KAZE::KAZE(bool _extended /* = false */) - : extended(_extended) + KAZE::KAZE() + : descriptor(DESCRIPTOR_MSURF) + , extended(false) + , upright(false) { } + KAZE::KAZE(DESCRIPTOR_TYPE type, bool _extended, bool _upright) + : descriptor(type) + , extended(_extended) + , upright(_upright) + { + + } KAZE::~KAZE() { @@ -102,7 +111,9 @@ namespace cv KAZEOptions options; options.img_width = img.cols; options.img_height = img.rows; + options.descriptor = static_cast(descriptor); options.extended = extended; + options.upright = upright; KAZEFeatures impl(options); impl.Create_Nonlinear_Scale_Space(img1_32); @@ -135,7 +146,9 @@ namespace cv KAZEOptions options; options.img_width = img.cols; options.img_height = img.rows; + options.descriptor = static_cast(descriptor); options.extended = extended; + options.upright = upright; KAZEFeatures impl(options); impl.Create_Nonlinear_Scale_Space(img1_32); @@ -161,7 +174,9 @@ namespace cv KAZEOptions options; options.img_width = img.cols; options.img_height = img.rows; + options.descriptor = static_cast(descriptor); options.extended = extended; + options.upright = upright; KAZEFeatures impl(options); impl.Create_Nonlinear_Scale_Space(img1_32); diff --git a/modules/features2d/src/kaze/KAZEConfig.h b/modules/features2d/src/kaze/KAZEConfig.h index 94c3aaa4d3..b0e397d538 100644 --- a/modules/features2d/src/kaze/KAZEConfig.h +++ b/modules/features2d/src/kaze/KAZEConfig.h @@ -5,92 +5,81 @@ * @author Pablo F. Alcantarilla */ -#ifndef __OPENCV_FEATURES_2D_KAZE_CONFIG_HPP__ -#define __OPENCV_FEATURES_2D_KAZE_CONFIG_HPP__ - -//****************************************************************************** -//****************************************************************************** +#pragma once // OpenCV Includes #include "precomp.hpp" +#include -//************************************************************************************* -//************************************************************************************* - -// Some defines -#define NMAX_CHAR 400 - -// Some default options -static const float DEFAULT_SCALE_OFFSET = 1.60f; // Base scale offset (sigma units) -static const float DEFAULT_OCTAVE_MAX = 4.0f; // Maximum octave evolution of the image 2^sigma (coarsest scale sigma units) -static const int DEFAULT_NSUBLEVELS = 4; // Default number of sublevels per scale level -static const float DEFAULT_DETECTOR_THRESHOLD = 0.001f; // Detector response threshold to accept point -static const float DEFAULT_MIN_DETECTOR_THRESHOLD = 0.00001f; // Minimum Detector response threshold to accept point -static const int DEFAULT_DESCRIPTOR_MODE = 1; // Descriptor Mode 0->SURF, 1->M-SURF -static const bool DEFAULT_USE_FED = true; // 0->AOS, 1->FED -static const bool DEFAULT_UPRIGHT = false; // Upright descriptors, not invariant to rotation -static const bool DEFAULT_EXTENDED = false; // Extended descriptor, dimension 128 - -// Some important configuration variables -static const float DEFAULT_SIGMA_SMOOTHING_DERIVATIVES = 1.0f; -static const float DEFAULT_KCONTRAST = 0.01f; -static const float KCONTRAST_PERCENTILE = 0.7f; -static const int KCONTRAST_NBINS = 300; -static const bool COMPUTE_KCONTRAST = true; -static const int DEFAULT_DIFFUSIVITY_TYPE = 1; // 0 -> PM G1, 1 -> PM G2, 2 -> Weickert -static const bool USE_CLIPPING_NORMALIZATION = false; -static const float CLIPPING_NORMALIZATION_RATIO = 1.6f; -static const int CLIPPING_NORMALIZATION_NITER = 5; - -//************************************************************************************* //************************************************************************************* struct KAZEOptions { - KAZEOptions() { - // Load the default options - soffset = DEFAULT_SCALE_OFFSET; - omax = static_cast(DEFAULT_OCTAVE_MAX); - nsublevels = DEFAULT_NSUBLEVELS; - dthreshold = DEFAULT_DETECTOR_THRESHOLD; - use_fed = DEFAULT_USE_FED; - upright = DEFAULT_UPRIGHT; - extended = DEFAULT_EXTENDED; - descriptor = DEFAULT_DESCRIPTOR_MODE; - diffusivity = DEFAULT_DIFFUSIVITY_TYPE; - sderivatives = DEFAULT_SIGMA_SMOOTHING_DERIVATIVES; - } + enum DIFFUSIVITY_TYPE { + PM_G1 = 0, + PM_G2 = 1, + WEICKERT = 2 + }; - float soffset; - int omax; - int nsublevels; - int img_width; - int img_height; - int diffusivity; - float sderivatives; - float dthreshold; - bool use_fed; - bool upright; - bool extended; - int descriptor; + KAZEOptions() + : descriptor(cv::KAZE::DESCRIPTOR_MSURF) + , diffusivity(PM_G2) + + , soffset(1.60f) + , omax(4) + , nsublevels(4) + , img_width(0) + , img_height(0) + , sderivatives(1.0f) + , dthreshold(0.001f) + , kcontrast(0.01f) + , kcontrast_percentille(0.7f) + , kcontrast_bins(300) + + , use_fed(true) + , upright(false) + , extended(false) + + , use_clipping_normalilzation(false) + , clipping_normalization_ratio(1.6f) + , clipping_normalization_niter(5) + { + } + + cv::KAZE::DESCRIPTOR_TYPE descriptor; + DIFFUSIVITY_TYPE diffusivity; + + float soffset; + int omax; + int nsublevels; + int img_width; + int img_height; + float sderivatives; + float dthreshold; + float kcontrast; + float kcontrast_percentille; + int kcontrast_bins; + + bool use_fed; + bool upright; + bool extended; + + bool use_clipping_normalilzation; + float clipping_normalization_ratio; + int clipping_normalization_niter; }; struct TEvolution { - cv::Mat Lx, Ly; // First order spatial derivatives - cv::Mat Lxx, Lxy, Lyy; // Second order spatial derivatives - cv::Mat Lflow; // Diffusivity image - cv::Mat Lt; // Evolution image - cv::Mat Lsmooth; // Smoothed image - cv::Mat Lstep; // Evolution step update - cv::Mat Ldet; // Detector response - float etime; // Evolution time - float esigma; // Evolution sigma. For linear diffusion t = sigma^2 / 2 - float octave; // Image octave - float sublevel; // Image sublevel in each octave - int sigma_size; // Integer esigma. For computing the feature detector responses + cv::Mat Lx, Ly; // First order spatial derivatives + cv::Mat Lxx, Lxy, Lyy; // Second order spatial derivatives + cv::Mat Lflow; // Diffusivity image + cv::Mat Lt; // Evolution image + cv::Mat Lsmooth; // Smoothed image + cv::Mat Lstep; // Evolution step update + cv::Mat Ldet; // Detector response + float etime; // Evolution time + float esigma; // Evolution sigma. For linear diffusion t = sigma^2 / 2 + float octave; // Image octave + float sublevel; // Image sublevel in each octave + int sigma_size; // Integer esigma. For computing the feature detector responses }; - -//************************************************************************************* -//************************************************************************************* - -#endif \ No newline at end of file diff --git a/modules/features2d/src/kaze/KAZEFeatures.cpp b/modules/features2d/src/kaze/KAZEFeatures.cpp index 15c003e41e..51e3a930f7 100644 --- a/modules/features2d/src/kaze/KAZEFeatures.cpp +++ b/modules/features2d/src/kaze/KAZEFeatures.cpp @@ -36,31 +36,11 @@ using namespace cv::details::kaze; * @param options KAZE configuration options * @note The constructor allocates memory for the nonlinear scale space */ -KAZEFeatures::KAZEFeatures(KAZEOptions& options) { - - soffset_ = options.soffset; - sderivatives_ = options.sderivatives; - omax_ = options.omax; - nsublevels_ = options.nsublevels; - img_width_ = options.img_width; - img_height_ = options.img_height; - dthreshold_ = options.dthreshold; - diffusivity_ = options.diffusivity; - descriptor_mode_ = options.descriptor; - use_fed_ = options.use_fed; - use_upright_ = options.upright; - use_extended_ = options.extended; - use_normalization = USE_CLIPPING_NORMALIZATION; - - kcontrast_ = DEFAULT_KCONTRAST; +KAZEFeatures::KAZEFeatures(KAZEOptions& _options) + : options(_options) +{ ncycles_ = 0; reordering_ = true; - //tkcontrast_ = 0.0; - //tnlscale_ = 0.0; - //tdetector_ = 0.0; - //tmderivatives_ = 0.0; - //tdresponse_ = 0.0; - //tdescriptor_ = 0.0; // Now allocate memory for the evolution Allocate_Memory_Evolution(); @@ -75,21 +55,21 @@ KAZEFeatures::KAZEFeatures(KAZEOptions& options) { void KAZEFeatures::Allocate_Memory_Evolution(void) { // Allocate the dimension of the matrices for the evolution - for (int i = 0; i <= omax_ - 1; i++) { - for (int j = 0; j <= nsublevels_ - 1; j++) { + for (int i = 0; i <= options.omax - 1; i++) { + for (int j = 0; j <= options.nsublevels - 1; j++) { TEvolution aux; - aux.Lx = cv::Mat::zeros(img_height_, img_width_, CV_32F); - aux.Ly = cv::Mat::zeros(img_height_, img_width_, CV_32F); - aux.Lxx = cv::Mat::zeros(img_height_, img_width_, CV_32F); - aux.Lxy = cv::Mat::zeros(img_height_, img_width_, CV_32F); - aux.Lyy = cv::Mat::zeros(img_height_, img_width_, CV_32F); - aux.Lflow = cv::Mat::zeros(img_height_, img_width_, CV_32F); - aux.Lt = cv::Mat::zeros(img_height_, img_width_, CV_32F); - aux.Lsmooth = cv::Mat::zeros(img_height_, img_width_, CV_32F); - aux.Lstep = cv::Mat::zeros(img_height_, img_width_, CV_32F); - aux.Ldet = cv::Mat::zeros(img_height_, img_width_, CV_32F); - aux.esigma = soffset_*pow((float)2.0f, (float)(j) / (float)(nsublevels_)+i); + aux.Lx = cv::Mat::zeros(options.img_height, options.img_width, CV_32F); + aux.Ly = cv::Mat::zeros(options.img_height, options.img_width, CV_32F); + aux.Lxx = cv::Mat::zeros(options.img_height, options.img_width, CV_32F); + aux.Lxy = cv::Mat::zeros(options.img_height, options.img_width, CV_32F); + aux.Lyy = cv::Mat::zeros(options.img_height, options.img_width, CV_32F); + aux.Lflow = cv::Mat::zeros(options.img_height, options.img_width, CV_32F); + aux.Lt = cv::Mat::zeros(options.img_height, options.img_width, CV_32F); + aux.Lsmooth = cv::Mat::zeros(options.img_height, options.img_width, CV_32F); + aux.Lstep = cv::Mat::zeros(options.img_height, options.img_width, CV_32F); + aux.Ldet = cv::Mat::zeros(options.img_height, options.img_width, CV_32F); + aux.esigma = options.soffset*pow((float)2.0f, (float)(j) / (float)(options.nsublevels)+i); aux.etime = 0.5f*(aux.esigma*aux.esigma); aux.sigma_size = fRound(aux.esigma); aux.octave = (float)i; @@ -99,7 +79,7 @@ void KAZEFeatures::Allocate_Memory_Evolution(void) { } // Allocate memory for the FED number of cycles and time steps - if (use_fed_) { + if (options.use_fed) { for (size_t i = 1; i < evolution_.size(); i++) { int naux = 0; vector tau; @@ -113,16 +93,16 @@ void KAZEFeatures::Allocate_Memory_Evolution(void) { } else { // Allocate memory for the auxiliary variables that are used in the AOS scheme - Ltx_ = Mat::zeros(img_width_, img_height_, CV_32F); - Lty_ = Mat::zeros(img_height_, img_width_, CV_32F); - px_ = Mat::zeros(img_height_, img_width_, CV_32F); - py_ = Mat::zeros(img_height_, img_width_, CV_32F); - ax_ = Mat::zeros(img_height_, img_width_, CV_32F); - ay_ = Mat::zeros(img_height_, img_width_, CV_32F); - bx_ = Mat::zeros(img_height_ - 1, img_width_, CV_32F); - by_ = Mat::zeros(img_height_ - 1, img_width_, CV_32F); - qr_ = Mat::zeros(img_height_ - 1, img_width_, CV_32F); - qc_ = Mat::zeros(img_height_, img_width_ - 1, CV_32F); + Ltx_ = Mat::zeros(options.img_width, options.img_height, CV_32F); // TODO? IS IT A BUG??? + Lty_ = Mat::zeros(options.img_height, options.img_width, CV_32F); + px_ = Mat::zeros(options.img_height, options.img_width, CV_32F); + py_ = Mat::zeros(options.img_height, options.img_width, CV_32F); + ax_ = Mat::zeros(options.img_height, options.img_width, CV_32F); + ay_ = Mat::zeros(options.img_height, options.img_width, CV_32F); + bx_ = Mat::zeros(options.img_height - 1, options.img_width, CV_32F); + by_ = Mat::zeros(options.img_height - 1, options.img_width, CV_32F); + qr_ = Mat::zeros(options.img_height - 1, options.img_width, CV_32F); + qc_ = Mat::zeros(options.img_height, options.img_width - 1, CV_32F); } } @@ -141,35 +121,35 @@ int KAZEFeatures::Create_Nonlinear_Scale_Space(const cv::Mat &img) // Copy the original image to the first level of the evolution img.copyTo(evolution_[0].Lt); - gaussian_2D_convolution(evolution_[0].Lt, evolution_[0].Lt, 0, 0, soffset_); - gaussian_2D_convolution(evolution_[0].Lt, evolution_[0].Lsmooth, 0, 0, sderivatives_); + gaussian_2D_convolution(evolution_[0].Lt, evolution_[0].Lt, 0, 0, options.soffset); + gaussian_2D_convolution(evolution_[0].Lt, evolution_[0].Lsmooth, 0, 0, options.sderivatives); // Firstly compute the kcontrast factor - Compute_KContrast(evolution_[0].Lt, KCONTRAST_PERCENTILE); + Compute_KContrast(evolution_[0].Lt, options.kcontrast_percentille); // Now generate the rest of evolution levels for (size_t i = 1; i < evolution_.size(); i++) { evolution_[i - 1].Lt.copyTo(evolution_[i].Lt); - gaussian_2D_convolution(evolution_[i - 1].Lt, evolution_[i].Lsmooth, 0, 0, sderivatives_); + gaussian_2D_convolution(evolution_[i - 1].Lt, evolution_[i].Lsmooth, 0, 0, options.sderivatives); // Compute the Gaussian derivatives Lx and Ly Scharr(evolution_[i].Lsmooth, evolution_[i].Lx, CV_32F, 1, 0, 1, 0, BORDER_DEFAULT); Scharr(evolution_[i].Lsmooth, evolution_[i].Ly, CV_32F, 0, 1, 1, 0, BORDER_DEFAULT); // Compute the conductivity equation - if (diffusivity_ == 0) { - pm_g1(evolution_[i].Lx, evolution_[i].Ly, evolution_[i].Lflow, kcontrast_); + if (options.diffusivity == KAZEOptions::PM_G1) { + pm_g1(evolution_[i].Lx, evolution_[i].Ly, evolution_[i].Lflow, options.kcontrast); } - else if (diffusivity_ == 1) { - pm_g2(evolution_[i].Lx, evolution_[i].Ly, evolution_[i].Lflow, kcontrast_); + else if (options.diffusivity == KAZEOptions::PM_G2) { + pm_g2(evolution_[i].Lx, evolution_[i].Ly, evolution_[i].Lflow, options.kcontrast); } - else if (diffusivity_ == 2) { - weickert_diffusivity(evolution_[i].Lx, evolution_[i].Ly, evolution_[i].Lflow, kcontrast_); + else if (options.diffusivity == KAZEOptions::WEICKERT) { + weickert_diffusivity(evolution_[i].Lx, evolution_[i].Ly, evolution_[i].Lflow, options.kcontrast); } // Perform FED n inner steps - if (use_fed_) { + if (options.use_fed) { for (int j = 0; j < nsteps_[i - 1]; j++) { nld_step_scalar(evolution_[i].Lt, evolution_[i].Lflow, evolution_[i].Lstep, tsteps_[i - 1][j]); } @@ -194,7 +174,7 @@ int KAZEFeatures::Create_Nonlinear_Scale_Space(const cv::Mat &img) */ void KAZEFeatures::Compute_KContrast(const cv::Mat &img, const float &kpercentile) { - kcontrast_ = compute_k_percentile(img, kpercentile, sderivatives_, KCONTRAST_NBINS, 0, 0); + options.kcontrast = compute_k_percentile(img, kpercentile, options.sderivatives, options.kcontrast_bins, 0, 0); } //************************************************************************************* @@ -239,9 +219,9 @@ void KAZEFeatures::Compute_Detector_Response(void) for (size_t i = 0; i < evolution_.size(); i++) { - for (int ix = 0; ix < img_height_; ix++) + for (int ix = 0; ix < options.img_height; ix++) { - for (int jx = 0; jx < img_width_; jx++) + for (int jx = 0; jx < options.img_width; jx++) { lxx = *(evolution_[i].Lxx.ptr(ix)+jx); lxy = *(evolution_[i].Lxy.ptr(ix)+jx); @@ -376,14 +356,14 @@ void KAZEFeatures::Find_Extremum_Threading(const int& level) { float value = 0.0; bool is_extremum = false; - for (int ix = 1; ix < img_height_ - 1; ix++) { - for (int jx = 1; jx < img_width_ - 1; jx++) { + for (int ix = 1; ix < options.img_height - 1; ix++) { + for (int jx = 1; jx < options.img_width - 1; jx++) { is_extremum = false; value = *(evolution_[level].Ldet.ptr(ix)+jx); // Filter the points with the detector threshold - if (value > dthreshold_ && value >= DEFAULT_MIN_DETECTOR_THRESHOLD) { + if (value > options.dthreshold) { if (value >= *(evolution_[level].Ldet.ptr(ix)+jx - 1)) { // First check on the same scale if (check_maximum_neighbourhood(evolution_[level].Ldet, 1, value, ix, jx, 1)) { @@ -495,10 +475,10 @@ void KAZEFeatures::Do_Subpixel_Refinement(std::vector &kpts) { if (fabs(*(dst.ptr(0))) <= 1.0f && fabs(*(dst.ptr(1))) <= 1.0f && fabs(*(dst.ptr(2))) <= 1.0f) { kpts_[i].pt.x += *(dst.ptr(0)); kpts_[i].pt.y += *(dst.ptr(1)); - dsc = kpts_[i].octave + (kpts_[i].angle + *(dst.ptr(2))) / ((float)(nsublevels_)); + dsc = kpts_[i].octave + (kpts_[i].angle + *(dst.ptr(2))) / ((float)(options.nsublevels)); // In OpenCV the size of a keypoint is the diameter!! - kpts_[i].size = 2.0f*soffset_*pow((float)2.0f, dsc); + kpts_[i].size = 2.0f*options.soffset*pow((float)2.0f, dsc); kpts_[i].angle = 0.0; } // Set the points to be deleted after the for loop @@ -520,6 +500,117 @@ void KAZEFeatures::Do_Subpixel_Refinement(std::vector &kpts) { //************************************************************************************* //************************************************************************************* +class MSURF_Descriptor_Invoker : public cv::ParallelLoopBody +{ +public: + MSURF_Descriptor_Invoker(std::vector &kpts, cv::Mat &desc, std::vector& evolution, const KAZEOptions& _options) + : _kpts(&kpts) + , _desc(&desc) + , _evolution(&evolution) + , options(_options) + { + } + + virtual ~MSURF_Descriptor_Invoker() + { + } + + void operator() (const cv::Range& range) const + { + std::vector &kpts = *_kpts; + cv::Mat &desc = *_desc; + std::vector &evolution = *_evolution; + + for (int i = range.start; i < range.end; i++) + { + kpts[i].angle = 0.0; + if (options.upright) + { + kpts[i].angle = 0.0; + if (options.extended) + Get_MSURF_Upright_Descriptor_128(kpts[i], desc.ptr((int)i)); + else + Get_MSURF_Upright_Descriptor_64(kpts[i], desc.ptr((int)i)); + } + else + { + KAZEFeatures::Compute_Main_Orientation(kpts[i], evolution, options); + + if (options.extended) + Get_MSURF_Descriptor_128(kpts[i], desc.ptr((int)i)); + else + Get_MSURF_Descriptor_64(kpts[i], desc.ptr((int)i)); + } + } + } +private: + void Get_MSURF_Upright_Descriptor_64(const cv::KeyPoint& kpt, float* desc) const; + void Get_MSURF_Descriptor_64(const cv::KeyPoint& kpt, float* desc) const; + void Get_MSURF_Upright_Descriptor_128(const cv::KeyPoint& kpt, float* desc) const; + void Get_MSURF_Descriptor_128(const cv::KeyPoint& kpt, float *desc) const; + + std::vector * _kpts; + cv::Mat * _desc; + std::vector * _evolution; + KAZEOptions options; +}; + +class GSURF_Descriptor_Invoker : public cv::ParallelLoopBody +{ +public: + GSURF_Descriptor_Invoker(std::vector &kpts, cv::Mat &desc, std::vector& evolution, const KAZEOptions& _options) + : _kpts(&kpts) + , _desc(&desc) + , _evolution(&evolution) + , options(_options) + { + } + + virtual ~GSURF_Descriptor_Invoker() + { + } + + void operator() (const cv::Range& range) const + { + std::vector &kpts = *_kpts; + cv::Mat &desc = *_desc; + std::vector &evolution = *_evolution; + + for (int i = range.start; i < range.end; i++) + { + kpts[i].angle = 0.0; + if (options.upright) + { + kpts[i].angle = 0.0; + if (options.extended) + Get_GSURF_Upright_Descriptor_128(kpts[i], desc.ptr((int)i)); + else + Get_GSURF_Upright_Descriptor_64(kpts[i], desc.ptr((int)i)); + } + else + { + KAZEFeatures::Compute_Main_Orientation(kpts[i], evolution, options); + + if (options.extended) + Get_GSURF_Descriptor_128(kpts[i], desc.ptr((int)i)); + else + Get_GSURF_Descriptor_64(kpts[i], desc.ptr((int)i)); + } + } + } + +private: + void Get_GSURF_Upright_Descriptor_64(const cv::KeyPoint& kpt, float* desc) const; + void Get_GSURF_Descriptor_64(const cv::KeyPoint& kpt, float *desc) const; + void Get_GSURF_Upright_Descriptor_128(const cv::KeyPoint& kpt, float* desc) const; + void Get_GSURF_Descriptor_128(const cv::KeyPoint& kpt, float* desc) const; + + std::vector * _kpts; + cv::Mat * _desc; + std::vector * _evolution; + KAZEOptions options; +}; + /** * @brief This method computes the set of descriptors through the nonlinear scale space * @param kpts Vector of keypoints @@ -528,134 +619,23 @@ void KAZEFeatures::Do_Subpixel_Refinement(std::vector &kpts) { void KAZEFeatures::Feature_Description(std::vector &kpts, cv::Mat &desc) { // Allocate memory for the matrix of descriptors - if (use_extended_ == true) { + if (options.extended == true) { desc = Mat::zeros((int)kpts.size(), 128, CV_32FC1); } else { desc = Mat::zeros((int)kpts.size(), 64, CV_32FC1); } - if (use_upright_ == true) { - if (use_extended_ == false) { - if (descriptor_mode_ == 0) { -#ifdef _OPENMP -#pragma omp parallel for -#endif - for (size_t i = 0; i < kpts.size(); i++) { - kpts[i].angle = 0.0; - Get_SURF_Upright_Descriptor_64(kpts[i], desc.ptr((int)i)); - } - } - else if (descriptor_mode_ == 1) { -#ifdef _OPENMP -#pragma omp parallel for -#endif - for (size_t i = 0; i < kpts.size(); i++) { - kpts[i].angle = 0.0; - Get_MSURF_Upright_Descriptor_64(kpts[i], desc.ptr((int)i)); - } - } - else if (descriptor_mode_ == 2) { -#ifdef _OPENMP -#pragma omp parallel for -#endif - for (size_t i = 0; i < kpts.size(); i++) { - kpts[i].angle = 0.0; - Get_GSURF_Upright_Descriptor_64(kpts[i], desc.ptr((int)i)); - } - } - } - else - { - if (descriptor_mode_ == 0) { -#ifdef _OPENMP -#pragma omp parallel for -#endif - for (size_t i = 0; i < kpts.size(); i++) { - kpts[i].angle = 0.0; - Get_SURF_Upright_Descriptor_128(kpts[i], desc.ptr((int)i)); - } - } - else if (descriptor_mode_ == 1) { -#ifdef _OPENMP -#pragma omp parallel for -#endif - for (size_t i = 0; i < kpts.size(); i++) { - kpts[i].angle = 0.0; - Get_MSURF_Upright_Descriptor_128(kpts[i], desc.ptr((int)i)); - } - } - else if (descriptor_mode_ == 2) { -#ifdef _OPENMP -#pragma omp parallel for -#endif - for (size_t i = 0; i < kpts.size(); i++) { - kpts[i].angle = 0.0; - Get_GSURF_Upright_Descriptor_128(kpts[i], desc.ptr((int)i)); - } - } - } - } - else { - if (use_extended_ == false) { - if (descriptor_mode_ == 0) { -#ifdef _OPENMP -#pragma omp parallel for -#endif - for (size_t i = 0; i < kpts.size(); i++) { - Compute_Main_Orientation_SURF(kpts[i]); - Get_SURF_Descriptor_64(kpts[i], desc.ptr((int)i)); - } - } - else if (descriptor_mode_ == 1) { -#ifdef _OPENMP -#pragma omp parallel for -#endif - for (size_t i = 0; i < kpts.size(); i++) { - Compute_Main_Orientation_SURF(kpts[i]); - Get_MSURF_Descriptor_64(kpts[i], desc.ptr((int)i)); - } - } - else if (descriptor_mode_ == 2) { -#ifdef _OPENMP -#pragma omp parallel for -#endif - for (size_t i = 0; i < kpts.size(); i++) { - Compute_Main_Orientation_SURF(kpts[i]); - Get_GSURF_Descriptor_64(kpts[i], desc.ptr((int)i)); - } - } - } - else { - if (descriptor_mode_ == 0) { -#ifdef _OPENMP -#pragma omp parallel for -#endif - for (size_t i = 0; i < kpts.size(); i++) { - Compute_Main_Orientation_SURF(kpts[i]); - Get_SURF_Descriptor_128(kpts[i], desc.ptr((int)i)); - } - } - else if (descriptor_mode_ == 1) { -#ifdef _OPENMP -#pragma omp parallel for -#endif - for (size_t i = 0; i < kpts.size(); i++) { - Compute_Main_Orientation_SURF(kpts[i]); - Get_MSURF_Descriptor_128(kpts[i], desc.ptr((int)i)); - } - } - else if (descriptor_mode_ == 2) { -#ifdef _OPENMP -#pragma omp parallel for -#endif - for (size_t i = 0; i < kpts.size(); i++) { - Compute_Main_Orientation_SURF(kpts[i]); - Get_GSURF_Descriptor_128(kpts[i], desc.ptr((int)i)); - } - } - } - } + switch (options.descriptor) + { + case cv::KAZE::DESCRIPTOR_MSURF: + cv::parallel_for_(cv::Range(0, (int)kpts.size()), MSURF_Descriptor_Invoker(kpts, desc, evolution_, options)); + break; + + case cv::KAZE::DESCRIPTOR_GSURF: + cv::parallel_for_(cv::Range(0, (int)kpts.size()), GSURF_Descriptor_Invoker(kpts, desc, evolution_, options)); + break; + }; } //************************************************************************************* @@ -667,7 +647,7 @@ void KAZEFeatures::Feature_Description(std::vector &kpts, cv::Mat * @note The orientation is computed using a similar approach as described in the * original SURF method. See Bay et al., Speeded Up Robust Features, ECCV 2006 */ -void KAZEFeatures::Compute_Main_Orientation_SURF(cv::KeyPoint &kpt) +void KAZEFeatures::Compute_Main_Orientation(cv::KeyPoint &kpt, const std::vector& evolution_, const KAZEOptions& options) { int ix = 0, iy = 0, idx = 0, s = 0, level = 0; float xf = 0.0, yf = 0.0, gweight = 0.0; @@ -689,7 +669,7 @@ void KAZEFeatures::Compute_Main_Orientation_SURF(cv::KeyPoint &kpt) iy = fRound(yf + j*s); ix = fRound(xf + i*s); - if (iy >= 0 && iy < img_height_ && ix >= 0 && ix < img_width_) { + if (iy >= 0 && iy < options.img_height && ix >= 0 && ix < options.img_width) { gweight = gaussian(iy - yf, ix - xf, 2.5f*s); resX[idx] = gweight*(*(evolution_[level].Lx.ptr(iy)+ix)); resY[idx] = gweight*(*(evolution_[level].Ly.ptr(iy)+ix)); @@ -739,212 +719,6 @@ void KAZEFeatures::Compute_Main_Orientation_SURF(cv::KeyPoint &kpt) //************************************************************************************* //************************************************************************************* -/** - * @brief This method computes the upright descriptor (no rotation invariant) - * of the provided keypoint - * @param kpt Input keypoint - * @param desc Descriptor vector - * @note Rectangular grid of 20 s x 20 s. Descriptor Length 64. No additional - * Gaussian weighting is performed. The descriptor is inspired from Bay et al., - * Speeded Up Robust Features, ECCV, 2006 - */ -void KAZEFeatures::Get_SURF_Upright_Descriptor_64(const cv::KeyPoint &kpt, float *desc) -{ - float dx = 0.0, dy = 0.0, mdx = 0.0, mdy = 0.0; - float rx = 0.0, ry = 0.0, len = 0.0, xf = 0.0, yf = 0.0, sample_x = 0.0, sample_y = 0.0; - float fx = 0.0, fy = 0.0, res1 = 0.0, res2 = 0.0, res3 = 0.0, res4 = 0.0; - int x1 = 0, y1 = 0, x2 = 0, y2 = 0, sample_step = 0, pattern_size = 0, dcount = 0; - int dsize = 0, scale = 0, level = 0; - - // Set the descriptor size and the sample and pattern sizes - dsize = 64; - sample_step = 5; - pattern_size = 10; - - // Get the information from the keypoint - yf = kpt.pt.y; - xf = kpt.pt.x; - level = kpt.class_id; - scale = fRound(kpt.size / 2.0f); - - // Calculate descriptor for this interest point - for (int i = -pattern_size; i < pattern_size; i += sample_step) { - for (int j = -pattern_size; j < pattern_size; j += sample_step) { - - dx = dy = mdx = mdy = 0.0; - - for (int k = i; k < i + sample_step; k++) { - for (int l = j; l < j + sample_step; l++) { - - sample_y = k*scale + yf; - sample_x = l*scale + xf; - - y1 = (int)(sample_y - .5f); - x1 = (int)(sample_x - .5f); - - checkDescriptorLimits(x1, y1, img_width_, img_height_); - - y2 = (int)(sample_y + .5f); - x2 = (int)(sample_x + .5f); - - checkDescriptorLimits(x2, y2, img_width_, img_height_); - - fx = sample_x - x1; - fy = sample_y - y1; - - res1 = *(evolution_[level].Lx.ptr(y1)+x1); - res2 = *(evolution_[level].Lx.ptr(y1)+x2); - res3 = *(evolution_[level].Lx.ptr(y2)+x1); - res4 = *(evolution_[level].Lx.ptr(y2)+x2); - rx = (1.0f - fx)*(1.0f - fy)*res1 + fx*(1.0f - fy)*res2 + (1.0f - fx)*fy*res3 + fx*fy*res4; - - res1 = *(evolution_[level].Ly.ptr(y1)+x1); - res2 = *(evolution_[level].Ly.ptr(y1)+x2); - res3 = *(evolution_[level].Ly.ptr(y2)+x1); - res4 = *(evolution_[level].Ly.ptr(y2)+x2); - ry = (1.0f - fx)*(1.0f - fy)*res1 + fx*(1.0f - fy)*res2 + (1.0f - fx)*fy*res3 + fx*fy*res4; - - // Sum the derivatives to the cumulative descriptor - dx += rx; - dy += ry; - mdx += fabs(rx); - mdy += fabs(ry); - } - } - - // Add the values to the descriptor vector - desc[dcount++] = dx; - desc[dcount++] = dy; - desc[dcount++] = mdx; - desc[dcount++] = mdy; - - // Store the current length^2 of the vector - len += dx*dx + dy*dy + mdx*mdx + mdy*mdy; - } - } - - // convert to unit vector - len = sqrt(len); - - for (int i = 0; i < dsize; i++) { - desc[i] /= len; - } - - if (use_normalization == true) { - clippingDescriptor(desc, dsize, CLIPPING_NORMALIZATION_NITER, CLIPPING_NORMALIZATION_RATIO); - } -} - -//************************************************************************************* -//************************************************************************************* - -/** - * @brief This method computes the descriptor of the provided keypoint given the - * main orientation - * @param kpt Input keypoint - * @param desc Descriptor vector - * @note Rectangular grid of 20 s x 20 s. Descriptor Length 64. No additional - * Gaussian weighting is performed. The descriptor is inspired from Bay et al., - * Speeded Up Robust Features, ECCV, 2006 - */ -void KAZEFeatures::Get_SURF_Descriptor_64(const cv::KeyPoint &kpt, float *desc) { - - float dx = 0.0, dy = 0.0, mdx = 0.0, mdy = 0.0; - float rx = 0.0, ry = 0.0, rrx = 0.0, rry = 0.0, len = 0.0, xf = 0.0, yf = 0.0; - float sample_x = 0.0, sample_y = 0.0, co = 0.0, si = 0.0, angle = 0.0; - float fx = 0.0, fy = 0.0, res1 = 0.0, res2 = 0.0, res3 = 0.0, res4 = 0.0; - int x1 = 0, y1 = 0, x2 = 0, y2 = 0, sample_step = 0, pattern_size = 0, dcount = 0; - int dsize = 0, scale = 0, level = 0; - - // Set the descriptor size and the sample and pattern sizes - dsize = 64; - sample_step = 5; - pattern_size = 10; - - // Get the information from the keypoint - yf = kpt.pt.y; - xf = kpt.pt.x; - scale = fRound(kpt.size / 2.0f); - angle = kpt.angle; - level = kpt.class_id; - co = cos(angle); - si = sin(angle); - - // Calculate descriptor for this interest point - for (int i = -pattern_size; i < pattern_size; i += sample_step) { - for (int j = -pattern_size; j < pattern_size; j += sample_step) { - dx = dy = mdx = mdy = 0.0; - - for (int k = i; k < i + sample_step; k++) { - for (int l = j; l < j + sample_step; l++) { - - // Get the coordinates of the sample point on the rotated axis - sample_y = yf + (l*scale*co + k*scale*si); - sample_x = xf + (-l*scale*si + k*scale*co); - - y1 = (int)(sample_y - .5f); - x1 = (int)(sample_x - .5f); - - checkDescriptorLimits(x1, y1, img_width_, img_height_); - - y2 = (int)(sample_y + .5f); - x2 = (int)(sample_x + .5f); - - checkDescriptorLimits(x2, y2, img_width_, img_height_); - - fx = sample_x - x1; - fy = sample_y - y1; - - res1 = *(evolution_[level].Lx.ptr(y1)+x1); - res2 = *(evolution_[level].Lx.ptr(y1)+x2); - res3 = *(evolution_[level].Lx.ptr(y2)+x1); - res4 = *(evolution_[level].Lx.ptr(y2)+x2); - rx = (1.0f - fx)*(1.0f - fy)*res1 + fx*(1.0f - fy)*res2 + (1.0f - fx)*fy*res3 + fx*fy*res4; - - res1 = *(evolution_[level].Ly.ptr(y1)+x1); - res2 = *(evolution_[level].Ly.ptr(y1)+x2); - res3 = *(evolution_[level].Ly.ptr(y2)+x1); - res4 = *(evolution_[level].Ly.ptr(y2)+x2); - ry = (1.0f - fx)*(1.0f - fy)*res1 + fx*(1.0f - fy)*res2 + (1.0f - fx)*fy*res3 + fx*fy*res4; - - // Get the x and y derivatives on the rotated axis - rry = rx*co + ry*si; - rrx = -rx*si + ry*co; - - // Sum the derivatives to the cumulative descriptor - dx += rrx; - dy += rry; - mdx += fabs(rrx); - mdy += fabs(rry); - } - } - - // Add the values to the descriptor vector - desc[dcount++] = dx; - desc[dcount++] = dy; - desc[dcount++] = mdx; - desc[dcount++] = mdy; - - // Store the current length^2 of the vector - len += dx*dx + dy*dy + mdx*mdx + mdy*mdy; - } - } - - // convert to unit vector - len = sqrt(len); - - for (int i = 0; i < dsize; i++) { - desc[i] /= len; - } - - if (use_normalization == true) { - clippingDescriptor(desc, dsize, CLIPPING_NORMALIZATION_NITER, CLIPPING_NORMALIZATION_RATIO); - } -} - -//************************************************************************************* -//************************************************************************************* - /** * @brief This method computes the upright descriptor (not rotation invariant) of * the provided keypoint @@ -954,7 +728,7 @@ void KAZEFeatures::Get_SURF_Descriptor_64(const cv::KeyPoint &kpt, float *desc) * from Agrawal et al., CenSurE: Center Surround Extremas for Realtime Feature Detection and Matching, * ECCV 2008 */ -void KAZEFeatures::Get_MSURF_Upright_Descriptor_64(const cv::KeyPoint &kpt, float *desc) +void MSURF_Descriptor_Invoker::Get_MSURF_Upright_Descriptor_64(const cv::KeyPoint &kpt, float *desc) const { float dx = 0.0, dy = 0.0, mdx = 0.0, mdy = 0.0, gauss_s1 = 0.0, gauss_s2 = 0.0; float rx = 0.0, ry = 0.0, len = 0.0, xf = 0.0, yf = 0.0, ys = 0.0, xs = 0.0; @@ -964,6 +738,8 @@ void KAZEFeatures::Get_MSURF_Upright_Descriptor_64(const cv::KeyPoint &kpt, floa float fx = 0.0, fy = 0.0, res1 = 0.0, res2 = 0.0, res3 = 0.0, res4 = 0.0; int dsize = 0, scale = 0, level = 0; + std::vector& evolution_ = *_evolution; + // Subregion centers for the 4x4 gaussian weighting float cx = -0.5f, cy = 0.5f; @@ -1013,12 +789,12 @@ void KAZEFeatures::Get_MSURF_Upright_Descriptor_64(const cv::KeyPoint &kpt, floa y1 = (int)(sample_y - 0.5f); x1 = (int)(sample_x - 0.5f); - checkDescriptorLimits(x1, y1, img_width_, img_height_); + checkDescriptorLimits(x1, y1, options.img_width, options.img_height); y2 = (int)(sample_y + 0.5f); x2 = (int)(sample_x + 0.5f); - checkDescriptorLimits(x2, y2, img_width_, img_height_); + checkDescriptorLimits(x2, y2, options.img_width, options.img_height); fx = sample_x - x1; fy = sample_y - y1; @@ -1069,8 +845,8 @@ void KAZEFeatures::Get_MSURF_Upright_Descriptor_64(const cv::KeyPoint &kpt, floa desc[i] /= len; } - if (use_normalization == true) { - clippingDescriptor(desc, dsize, CLIPPING_NORMALIZATION_NITER, CLIPPING_NORMALIZATION_RATIO); + if (options.use_clipping_normalilzation) { + clippingDescriptor(desc, dsize, options.clipping_normalization_niter, options.clipping_normalization_ratio); } } @@ -1086,7 +862,7 @@ void KAZEFeatures::Get_MSURF_Upright_Descriptor_64(const cv::KeyPoint &kpt, floa * from Agrawal et al., CenSurE: Center Surround Extremas for Realtime Feature Detection and Matching, * ECCV 2008 */ -void KAZEFeatures::Get_MSURF_Descriptor_64(const cv::KeyPoint &kpt, float *desc) +void MSURF_Descriptor_Invoker::Get_MSURF_Descriptor_64(const cv::KeyPoint &kpt, float *desc) const { float dx = 0.0, dy = 0.0, mdx = 0.0, mdy = 0.0, gauss_s1 = 0.0, gauss_s2 = 0.0; float rx = 0.0, ry = 0.0, rrx = 0.0, rry = 0.0, len = 0.0, xf = 0.0, yf = 0.0, ys = 0.0, xs = 0.0; @@ -1096,6 +872,8 @@ void KAZEFeatures::Get_MSURF_Descriptor_64(const cv::KeyPoint &kpt, float *desc) int kx = 0, ky = 0, i = 0, j = 0, dcount = 0; int dsize = 0, scale = 0, level = 0; + std::vector& evolution_ = *_evolution; + // Subregion centers for the 4x4 gaussian weighting float cx = -0.5f, cy = 0.5f; @@ -1149,12 +927,12 @@ void KAZEFeatures::Get_MSURF_Descriptor_64(const cv::KeyPoint &kpt, float *desc) y1 = fRound(sample_y - 0.5f); x1 = fRound(sample_x - 0.5f); - checkDescriptorLimits(x1, y1, img_width_, img_height_); + checkDescriptorLimits(x1, y1, options.img_width, options.img_height); y2 = (int)(sample_y + 0.5f); x2 = (int)(sample_x + 0.5f); - checkDescriptorLimits(x2, y2, img_width_, img_height_); + checkDescriptorLimits(x2, y2, options.img_width, options.img_height); fx = sample_x - x1; fy = sample_y - y1; @@ -1202,8 +980,8 @@ void KAZEFeatures::Get_MSURF_Descriptor_64(const cv::KeyPoint &kpt, float *desc) desc[i] /= len; } - if (use_normalization == true) { - clippingDescriptor(desc, dsize, CLIPPING_NORMALIZATION_NITER, CLIPPING_NORMALIZATION_RATIO); + if (options.use_clipping_normalilzation) { + clippingDescriptor(desc, dsize, options.clipping_normalization_niter, options.clipping_normalization_ratio); } } @@ -1219,7 +997,7 @@ void KAZEFeatures::Get_MSURF_Descriptor_64(const cv::KeyPoint &kpt, float *desc) * G-SURF descriptor as described in Pablo F. Alcantarilla, Luis M. Bergasa and * Andrew J. Davison, Gauge-SURF Descriptors, Image and Vision Computing 31(1), 2013 */ -void KAZEFeatures::Get_GSURF_Upright_Descriptor_64(const cv::KeyPoint &kpt, float *desc) +void GSURF_Descriptor_Invoker::Get_GSURF_Upright_Descriptor_64(const cv::KeyPoint &kpt, float *desc) const { float dx = 0.0, dy = 0.0, mdx = 0.0, mdy = 0.0; float rx = 0.0, ry = 0.0, rxx = 0.0, rxy = 0.0, ryy = 0.0, len = 0.0, xf = 0.0, yf = 0.0; @@ -1229,6 +1007,8 @@ void KAZEFeatures::Get_GSURF_Upright_Descriptor_64(const cv::KeyPoint &kpt, floa int x1 = 0, y1 = 0, x2 = 0, y2 = 0, sample_step = 0, pattern_size = 0, dcount = 0; int dsize = 0, scale = 0, level = 0; + std::vector& evolution_ = *_evolution; + // Set the descriptor size and the sample and pattern sizes dsize = 64; sample_step = 5; @@ -1256,12 +1036,12 @@ void KAZEFeatures::Get_GSURF_Upright_Descriptor_64(const cv::KeyPoint &kpt, floa y1 = (int)(sample_y - 0.5f); x1 = (int)(sample_x - 0.5f); - checkDescriptorLimits(x1, y1, img_width_, img_height_); + checkDescriptorLimits(x1, y1, options.img_width, options.img_height); y2 = (int)(sample_y + 0.5f); x2 = (int)(sample_x + 0.5f); - checkDescriptorLimits(x2, y2, img_width_, img_height_); + checkDescriptorLimits(x2, y2, options.img_width, options.img_height); fx = sample_x - x1; fy = sample_y - y1; @@ -1337,8 +1117,8 @@ void KAZEFeatures::Get_GSURF_Upright_Descriptor_64(const cv::KeyPoint &kpt, floa desc[i] /= len; } - if (use_normalization == true) { - clippingDescriptor(desc, dsize, CLIPPING_NORMALIZATION_NITER, CLIPPING_NORMALIZATION_RATIO); + if (options.use_clipping_normalilzation) { + clippingDescriptor(desc, dsize, options.clipping_normalization_niter, options.clipping_normalization_ratio); } } @@ -1354,7 +1134,7 @@ void KAZEFeatures::Get_GSURF_Upright_Descriptor_64(const cv::KeyPoint &kpt, floa * G-SURF descriptor as described in Pablo F. Alcantarilla, Luis M. Bergasa and * Andrew J. Davison, Gauge-SURF Descriptors, Image and Vision Computing 31(1), 2013 */ -void KAZEFeatures::Get_GSURF_Descriptor_64(const cv::KeyPoint &kpt, float *desc) +void GSURF_Descriptor_Invoker::Get_GSURF_Descriptor_64(const cv::KeyPoint &kpt, float *desc) const { float dx = 0.0, dy = 0.0, mdx = 0.0, mdy = 0.0; float rx = 0.0, ry = 0.0, rxx = 0.0, rxy = 0.0, ryy = 0.0, len = 0.0, xf = 0.0, yf = 0.0; @@ -1364,6 +1144,8 @@ void KAZEFeatures::Get_GSURF_Descriptor_64(const cv::KeyPoint &kpt, float *desc) int x1 = 0, y1 = 0, x2 = 0, y2 = 0, sample_step = 0, pattern_size = 0, dcount = 0; int dsize = 0, scale = 0, level = 0; + std::vector& evolution_ = *_evolution; + // Set the descriptor size and the sample and pattern sizes dsize = 64; sample_step = 5; @@ -1394,12 +1176,12 @@ void KAZEFeatures::Get_GSURF_Descriptor_64(const cv::KeyPoint &kpt, float *desc) y1 = (int)(sample_y - 0.5f); x1 = (int)(sample_x - 0.5f); - checkDescriptorLimits(x1, y1, img_width_, img_height_); + checkDescriptorLimits(x1, y1, options.img_width, options.img_height); y2 = (int)(sample_y + 0.5f); x2 = (int)(sample_x + 0.5f); - checkDescriptorLimits(x2, y2, img_width_, img_height_); + checkDescriptorLimits(x2, y2, options.img_width, options.img_height); fx = sample_x - x1; fy = sample_y - y1; @@ -1475,8 +1257,8 @@ void KAZEFeatures::Get_GSURF_Descriptor_64(const cv::KeyPoint &kpt, float *desc) desc[i] /= len; } - if (use_normalization == true) { - clippingDescriptor(desc, dsize, CLIPPING_NORMALIZATION_NITER, CLIPPING_NORMALIZATION_RATIO); + if (options.use_clipping_normalilzation) { + clippingDescriptor(desc, dsize, options.clipping_normalization_niter, options.clipping_normalization_ratio); } } @@ -1484,253 +1266,6 @@ void KAZEFeatures::Get_GSURF_Descriptor_64(const cv::KeyPoint &kpt, float *desc) //************************************************************************************* //************************************************************************************* -/** - * @brief This method computes the upright extended descriptor (no rotation invariant) - * of the provided keypoint - * @param kpt Input keypoint - * @param desc Descriptor vector - * @note Rectangular grid of 20 s x 20 s. Descriptor Length 128. No additional - * Gaussian weighting is performed. The descriptor is inspired from Bay et al., - * Speeded Up Robust Features, ECCV, 2006 - */ -void KAZEFeatures::Get_SURF_Upright_Descriptor_128(const cv::KeyPoint &kpt, float *desc) -{ - float rx = 0.0, ry = 0.0, len = 0.0, xf = 0.0, yf = 0.0, sample_x = 0.0, sample_y = 0.0; - float fx = 0.0, fy = 0.0, res1 = 0.0, res2 = 0.0, res3 = 0.0, res4 = 0.0; - float dxp = 0.0, dyp = 0.0, mdxp = 0.0, mdyp = 0.0; - float dxn = 0.0, dyn = 0.0, mdxn = 0.0, mdyn = 0.0; - int x1 = 0, y1 = 0, x2 = 0, y2 = 0, sample_step = 0, pattern_size = 0, dcount = 0; - int dsize = 0, scale = 0, level = 0; - - // Set the descriptor size and the sample and pattern sizes - dsize = 128; - sample_step = 5; - pattern_size = 10; - - // Get the information from the keypoint - yf = kpt.pt.y; - xf = kpt.pt.x; - scale = fRound(kpt.size / 2.0f); - level = kpt.class_id; - - // Calculate descriptor for this interest point - for (int i = -pattern_size; i < pattern_size; i += sample_step) { - for (int j = -pattern_size; j < pattern_size; j += sample_step) { - - dxp = dxn = mdxp = mdxn = 0.0; - dyp = dyn = mdyp = mdyn = 0.0; - - for (int k = i; k < i + sample_step; k++) { - for (int l = j; l < j + sample_step; l++) { - - sample_y = k*scale + yf; - sample_x = l*scale + xf; - - y1 = (int)(sample_y - 0.5f); - x1 = (int)(sample_x - 0.5f); - - checkDescriptorLimits(x1, y1, img_width_, img_height_); - - y2 = (int)(sample_y + 0.5f); - x2 = (int)(sample_x + 0.5f); - - checkDescriptorLimits(x2, y2, img_width_, img_height_); - - fx = sample_x - x1; - fy = sample_y - y1; - - res1 = *(evolution_[level].Lx.ptr(y1)+x1); - res2 = *(evolution_[level].Lx.ptr(y1)+x2); - res3 = *(evolution_[level].Lx.ptr(y2)+x1); - res4 = *(evolution_[level].Lx.ptr(y2)+x2); - rx = (1.0f - fx)*(1.0f - fy)*res1 + fx*(1.0f - fy)*res2 + (1.0f - fx)*fy*res3 + fx*fy*res4; - - res1 = *(evolution_[level].Ly.ptr(y1)+x1); - res2 = *(evolution_[level].Ly.ptr(y1)+x2); - res3 = *(evolution_[level].Ly.ptr(y2)+x1); - res4 = *(evolution_[level].Ly.ptr(y2)+x2); - ry = (1.0f - fx)*(1.0f - fy)*res1 + fx*(1.0f - fy)*res2 + (1.0f - fx)*fy*res3 + fx*fy*res4; - - // Sum the derivatives to the cumulative descriptor - if (ry >= 0.0) { - dxp += rx; - mdxp += fabs(rx); - } - else { - dxn += rx; - mdxn += fabs(rx); - } - - if (rx >= 0.0) { - dyp += ry; - mdyp += fabs(ry); - } - else { - dyn += ry; - mdyn += fabs(ry); - } - } - } - - // Add the values to the descriptor vector - desc[dcount++] = dxp; - desc[dcount++] = dxn; - desc[dcount++] = mdxp; - desc[dcount++] = mdxn; - desc[dcount++] = dyp; - desc[dcount++] = dyn; - desc[dcount++] = mdyp; - desc[dcount++] = mdyn; - - // Store the current length^2 of the vector - len += dxp*dxp + dxn*dxn + mdxp*mdxp + mdxn*mdxn + - dyp*dyp + dyn*dyn + mdyp*mdyp + mdyn*mdyn; - } - } - - // convert to unit vector - len = sqrt(len); - - for (int i = 0; i < dsize; i++) { - desc[i] /= len; - } - - if (use_normalization == true) { - clippingDescriptor(desc, dsize, CLIPPING_NORMALIZATION_NITER, CLIPPING_NORMALIZATION_RATIO); - } -} - -//************************************************************************************* -//************************************************************************************* - -/** - * @brief This method computes the extended descriptor of the provided keypoint given the - * main orientation - * @param kpt Input keypoint - * @param desc Descriptor vector - * @note Rectangular grid of 20 s x 20 s. Descriptor Length 128. No additional - * Gaussian weighting is performed. The descriptor is inspired from Bay et al., - * Speeded Up Robust Features, ECCV, 2006 - */ -void KAZEFeatures::Get_SURF_Descriptor_128(const cv::KeyPoint &kpt, float *desc) -{ - float rx = 0.0, ry = 0.0, rrx = 0.0, rry = 0.0, len = 0.0, xf = 0.0, yf = 0.0; - float sample_x = 0.0, sample_y = 0.0, co = 0.0, si = 0.0, angle = 0.0; - float fx = 0.0, fy = 0.0, res1 = 0.0, res2 = 0.0, res3 = 0.0, res4 = 0.0; - float dxp = 0.0, dyp = 0.0, mdxp = 0.0, mdyp = 0.0; - float dxn = 0.0, dyn = 0.0, mdxn = 0.0, mdyn = 0.0; - int x1 = 0, y1 = 0, x2 = 0, y2 = 0, sample_step = 0, pattern_size = 0, dcount = 0; - int dsize = 0, scale = 0, level = 0; - - // Set the descriptor size and the sample and pattern sizes - dsize = 128; - sample_step = 5; - pattern_size = 10; - - // Get the information from the keypoint - yf = kpt.pt.y; - xf = kpt.pt.x; - scale = fRound(kpt.size / 2.0f); - angle = kpt.angle; - level = kpt.class_id; - co = cos(angle); - si = sin(angle); - - // Calculate descriptor for this interest point - for (int i = -pattern_size; i < pattern_size; i += sample_step) { - for (int j = -pattern_size; j < pattern_size; j += sample_step) { - - dxp = dxn = mdxp = mdxn = 0.0; - dyp = dyn = mdyp = mdyn = 0.0; - - for (int k = i; k < i + sample_step; k++) { - for (int l = j; l < j + sample_step; l++) { - - // Get the coordinates of the sample point on the rotated axis - sample_y = yf + (l*scale*co + k*scale*si); - sample_x = xf + (-l*scale*si + k*scale*co); - - y1 = (int)(sample_y - 0.5f); - x1 = (int)(sample_x - 0.5f); - - checkDescriptorLimits(x1, y1, img_width_, img_height_); - - y2 = (int)(sample_y + 0.5f); - x2 = (int)(sample_x + 0.5f); - - checkDescriptorLimits(x2, y2, img_width_, img_height_); - - fx = sample_x - x1; - fy = sample_y - y1; - - res1 = *(evolution_[level].Lx.ptr(y1)+x1); - res2 = *(evolution_[level].Lx.ptr(y1)+x2); - res3 = *(evolution_[level].Lx.ptr(y2)+x1); - res4 = *(evolution_[level].Lx.ptr(y2)+x2); - rx = (1.0f - fx)*(1.0f - fy)*res1 + fx*(1.0f - fy)*res2 + (1.0f - fx)*fy*res3 + fx*fy*res4; - - res1 = *(evolution_[level].Ly.ptr(y1)+x1); - res2 = *(evolution_[level].Ly.ptr(y1)+x2); - res3 = *(evolution_[level].Ly.ptr(y2)+x1); - res4 = *(evolution_[level].Ly.ptr(y2)+x2); - ry = (1.0f - fx)*(1.0f - fy)*res1 + fx*(1.0f - fy)*res2 + (1.0f - fx)*fy*res3 + fx*fy*res4; - - // Get the x and y derivatives on the rotated axis - rry = rx*co + ry*si; - rrx = -rx*si + ry*co; - - // Sum the derivatives to the cumulative descriptor - if (rry >= 0.0) { - dxp += rrx; - mdxp += fabs(rrx); - } - else { - dxn += rrx; - mdxn += fabs(rrx); - } - - if (rrx >= 0.0) { - dyp += rry; - mdyp += fabs(rry); - } - else { - dyn += rry; - mdyn += fabs(rry); - } - } - } - - // Add the values to the descriptor vector - desc[dcount++] = dxp; - desc[dcount++] = dxn; - desc[dcount++] = mdxp; - desc[dcount++] = mdxn; - desc[dcount++] = dyp; - desc[dcount++] = dyn; - desc[dcount++] = mdyp; - desc[dcount++] = mdyn; - - // Store the current length^2 of the vector - len += dxp*dxp + dxn*dxn + mdxp*mdxp + mdxn*mdxn + - dyp*dyp + dyn*dyn + mdyp*mdyp + mdyn*mdyn; - } - } - - // convert to unit vector - len = sqrt(len); - - for (int i = 0; i < dsize; i++) { - desc[i] /= len; - } - - if (use_normalization == true) { - clippingDescriptor(desc, dsize, CLIPPING_NORMALIZATION_NITER, CLIPPING_NORMALIZATION_RATIO); - } -} - -//************************************************************************************* -//************************************************************************************* - /** * @brief This method computes the extended upright descriptor (not rotation invariant) of * the provided keypoint @@ -1740,8 +1275,8 @@ void KAZEFeatures::Get_SURF_Descriptor_128(const cv::KeyPoint &kpt, float *desc) * from Agrawal et al., CenSurE: Center Surround Extremas for Realtime Feature Detection and Matching, * ECCV 2008 */ -void KAZEFeatures::Get_MSURF_Upright_Descriptor_128(const cv::KeyPoint &kpt, float *desc) { - +void MSURF_Descriptor_Invoker::Get_MSURF_Upright_Descriptor_128(const cv::KeyPoint &kpt, float *desc) const +{ float gauss_s1 = 0.0, gauss_s2 = 0.0; float rx = 0.0, ry = 0.0, len = 0.0, xf = 0.0, yf = 0.0, ys = 0.0, xs = 0.0; float sample_x = 0.0, sample_y = 0.0; @@ -1755,6 +1290,8 @@ void KAZEFeatures::Get_MSURF_Upright_Descriptor_128(const cv::KeyPoint &kpt, flo // Subregion centers for the 4x4 gaussian weighting float cx = -0.5f, cy = 0.5f; + std::vector& evolution_ = *_evolution; + // Set the descriptor size and the sample and pattern sizes dsize = 128; sample_step = 5; @@ -1804,12 +1341,12 @@ void KAZEFeatures::Get_MSURF_Upright_Descriptor_128(const cv::KeyPoint &kpt, flo y1 = (int)(sample_y - 0.5f); x1 = (int)(sample_x - 0.5f); - checkDescriptorLimits(x1, y1, img_width_, img_height_); + checkDescriptorLimits(x1, y1, options.img_width, options.img_height); y2 = (int)(sample_y + 0.5f); x2 = (int)(sample_x + 0.5f); - checkDescriptorLimits(x2, y2, img_width_, img_height_); + checkDescriptorLimits(x2, y2, options.img_width, options.img_height); fx = sample_x - x1; fy = sample_y - y1; @@ -1879,8 +1416,8 @@ void KAZEFeatures::Get_MSURF_Upright_Descriptor_128(const cv::KeyPoint &kpt, flo desc[i] /= len; } - if (use_normalization == true) { - clippingDescriptor(desc, dsize, CLIPPING_NORMALIZATION_NITER, CLIPPING_NORMALIZATION_RATIO); + if (options.use_clipping_normalilzation) { + clippingDescriptor(desc, dsize, options.clipping_normalization_niter, options.clipping_normalization_ratio); } } @@ -1896,8 +1433,8 @@ void KAZEFeatures::Get_MSURF_Upright_Descriptor_128(const cv::KeyPoint &kpt, flo * from Agrawal et al., CenSurE: Center Surround Extremas for Realtime Feature Detection and Matching, * ECCV 2008 */ -void KAZEFeatures::Get_MSURF_Descriptor_128(const cv::KeyPoint &kpt, float *desc) { - +void MSURF_Descriptor_Invoker::Get_MSURF_Descriptor_128(const cv::KeyPoint &kpt, float *desc) const +{ float gauss_s1 = 0.0, gauss_s2 = 0.0; float rx = 0.0, ry = 0.0, rrx = 0.0, rry = 0.0, len = 0.0, xf = 0.0, yf = 0.0, ys = 0.0, xs = 0.0; float sample_x = 0.0, sample_y = 0.0, co = 0.0, si = 0.0, angle = 0.0; @@ -1908,6 +1445,8 @@ void KAZEFeatures::Get_MSURF_Descriptor_128(const cv::KeyPoint &kpt, float *desc int kx = 0, ky = 0, i = 0, j = 0, dcount = 0; int dsize = 0, scale = 0, level = 0; + std::vector& evolution_ = *_evolution; + // Subregion centers for the 4x4 gaussian weighting float cx = -0.5f, cy = 0.5f; @@ -1964,12 +1503,12 @@ void KAZEFeatures::Get_MSURF_Descriptor_128(const cv::KeyPoint &kpt, float *desc y1 = fRound(sample_y - 0.5f); x1 = fRound(sample_x - 0.5f); - checkDescriptorLimits(x1, y1, img_width_, img_height_); + checkDescriptorLimits(x1, y1, options.img_width, options.img_height); y2 = (int)(sample_y + 0.5f); x2 = (int)(sample_x + 0.5f); - checkDescriptorLimits(x2, y2, img_width_, img_height_); + checkDescriptorLimits(x2, y2, options.img_width, options.img_height); fx = sample_x - x1; fy = sample_y - y1; @@ -2040,8 +1579,8 @@ void KAZEFeatures::Get_MSURF_Descriptor_128(const cv::KeyPoint &kpt, float *desc desc[i] /= len; } - if (use_normalization == true) { - clippingDescriptor(desc, dsize, CLIPPING_NORMALIZATION_NITER, CLIPPING_NORMALIZATION_RATIO); + if (options.use_clipping_normalilzation) { + clippingDescriptor(desc, dsize, options.clipping_normalization_niter, options.clipping_normalization_ratio); } } @@ -2057,7 +1596,7 @@ void KAZEFeatures::Get_MSURF_Descriptor_128(const cv::KeyPoint &kpt, float *desc * G-SURF descriptor as described in Pablo F. Alcantarilla, Luis M. Bergasa and * Andrew J. Davison, Gauge-SURF Descriptors, Image and Vision Computing 31(1), 2013 */ -void KAZEFeatures::Get_GSURF_Upright_Descriptor_128(const cv::KeyPoint &kpt, float *desc) +void GSURF_Descriptor_Invoker::Get_GSURF_Upright_Descriptor_128(const cv::KeyPoint &kpt, float *desc) const { float len = 0.0, xf = 0.0, yf = 0.0, sample_x = 0.0, sample_y = 0.0; float rx = 0.0, ry = 0.0, rxx = 0.0, rxy = 0.0, ryy = 0.0, modg = 0.0; @@ -2067,6 +1606,8 @@ void KAZEFeatures::Get_GSURF_Upright_Descriptor_128(const cv::KeyPoint &kpt, flo int x1 = 0, y1 = 0, x2 = 0, y2 = 0, sample_step = 0, pattern_size = 0, dcount = 0; int dsize = 0, scale = 0, level = 0; + std::vector& evolution_ = *_evolution; + // Set the descriptor size and the sample and pattern sizes dsize = 128; sample_step = 5; @@ -2094,12 +1635,12 @@ void KAZEFeatures::Get_GSURF_Upright_Descriptor_128(const cv::KeyPoint &kpt, flo y1 = (int)(sample_y - 0.5f); x1 = (int)(sample_x - 0.5f); - checkDescriptorLimits(x1, y1, img_width_, img_height_); + checkDescriptorLimits(x1, y1, options.img_width, options.img_height); y2 = (int)(sample_y + 0.5f); x2 = (int)(sample_x + 0.5f); - checkDescriptorLimits(x2, y2, img_width_, img_height_); + checkDescriptorLimits(x2, y2, options.img_width, options.img_height); fx = sample_x - x1; fy = sample_y - y1; @@ -2193,8 +1734,8 @@ void KAZEFeatures::Get_GSURF_Upright_Descriptor_128(const cv::KeyPoint &kpt, flo desc[i] /= len; } - if (use_normalization == true) { - clippingDescriptor(desc, dsize, CLIPPING_NORMALIZATION_NITER, CLIPPING_NORMALIZATION_RATIO); + if (options.use_clipping_normalilzation) { + clippingDescriptor(desc, dsize, options.clipping_normalization_niter, options.clipping_normalization_ratio); } } @@ -2210,7 +1751,8 @@ void KAZEFeatures::Get_GSURF_Upright_Descriptor_128(const cv::KeyPoint &kpt, flo * G-SURF descriptor as described in Pablo F. Alcantarilla, Luis M. Bergasa and * Andrew J. Davison, Gauge-SURF Descriptors, Image and Vision Computing 31(1), 2013 */ -void KAZEFeatures::Get_GSURF_Descriptor_128(const cv::KeyPoint &kpt, float *desc) { +void GSURF_Descriptor_Invoker::Get_GSURF_Descriptor_128(const cv::KeyPoint &kpt, float *desc) const +{ float len = 0.0, xf = 0.0, yf = 0.0; float rx = 0.0, ry = 0.0, rxx = 0.0, rxy = 0.0, ryy = 0.0; @@ -2222,6 +1764,8 @@ void KAZEFeatures::Get_GSURF_Descriptor_128(const cv::KeyPoint &kpt, float *desc int x1 = 0, y1 = 0, x2 = 0, y2 = 0, sample_step = 0, pattern_size = 0, dcount = 0; int dsize = 0, scale = 0, level = 0; + std::vector& evolution_ = *_evolution; + // Set the descriptor size and the sample and pattern sizes dsize = 128; sample_step = 5; @@ -2253,12 +1797,12 @@ void KAZEFeatures::Get_GSURF_Descriptor_128(const cv::KeyPoint &kpt, float *desc y1 = (int)(sample_y - 0.5f); x1 = (int)(sample_x - 0.5f); - checkDescriptorLimits(x1, y1, img_width_, img_height_); + checkDescriptorLimits(x1, y1, options.img_width, options.img_height); y2 = (int)(sample_y + 0.5f); x2 = (int)(sample_x + 0.5f); - checkDescriptorLimits(x2, y2, img_width_, img_height_); + checkDescriptorLimits(x2, y2, options.img_width, options.img_height); fx = sample_x - x1; fy = sample_y - y1; @@ -2351,8 +1895,8 @@ void KAZEFeatures::Get_GSURF_Descriptor_128(const cv::KeyPoint &kpt, float *desc desc[i] /= len; } - if (use_normalization == true) { - clippingDescriptor(desc, dsize, CLIPPING_NORMALIZATION_NITER, CLIPPING_NORMALIZATION_RATIO); + if (options.use_clipping_normalilzation) { + clippingDescriptor(desc, dsize, options.clipping_normalization_niter, options.clipping_normalization_ratio); } } @@ -2371,22 +1915,8 @@ void KAZEFeatures::Get_GSURF_Descriptor_128(const cv::KeyPoint &kpt, float *desc */ void KAZEFeatures::AOS_Step_Scalar(cv::Mat &Ld, const cv::Mat &Ldprev, const cv::Mat &c, const float& stepsize) { -#ifdef _OPENMP -#pragma omp sections - { -#pragma omp section - { - AOS_Rows(Ldprev,c,stepsize); - } -#pragma omp section - { - AOS_Columns(Ldprev,c,stepsize); - } - } -#else AOS_Rows(Ldprev, c, stepsize); AOS_Columns(Ldprev, c, stepsize); -#endif Ld = 0.5f*(Lty_ + Ltx_.t()); } diff --git a/modules/features2d/src/kaze/KAZEFeatures.h b/modules/features2d/src/kaze/KAZEFeatures.h index c901561240..81509c47d9 100644 --- a/modules/features2d/src/kaze/KAZEFeatures.h +++ b/modules/features2d/src/kaze/KAZEFeatures.h @@ -26,97 +26,52 @@ class KAZEFeatures { private: - // Parameters of the Nonlinear diffusion class - float soffset_; // Base scale offset - float sderivatives_; // Standard deviation of the Gaussian for the nonlinear diff. derivatives - int omax_; // Maximum octave level - int nsublevels_; // Number of sublevels per octave level - int img_width_; // Width of the original image - int img_height_; // Height of the original image - std::vector evolution_; // Vector of nonlinear diffusion evolution - float kcontrast_; // The contrast parameter for the scalar nonlinear diffusion - float dthreshold_; // Feature detector threshold response - int diffusivity_; // Diffusivity type, 0->PM G1, 1->PM G2, 2-> Weickert - int descriptor_mode_; // Descriptor mode - bool use_fed_; // Set to true in case we want to use FED for the nonlinear diffusion filtering. Set false for using AOS - bool use_upright_; // Set to true in case we want to use the upright version of the descriptors - bool use_extended_; // Set to true in case we want to use the extended version of the descriptors - bool use_normalization; + KAZEOptions options; - // Vector of keypoint vectors for finding extrema in multiple threads - std::vector > kpts_par_; + // Parameters of the Nonlinear diffusion class + std::vector evolution_; // Vector of nonlinear diffusion evolution - // FED parameters - int ncycles_; // Number of cycles - bool reordering_; // Flag for reordering time steps - std::vector > tsteps_; // Vector of FED dynamic time steps - std::vector nsteps_; // Vector of number of steps per cycle + // Vector of keypoint vectors for finding extrema in multiple threads + std::vector > kpts_par_; - // Computation times variables in ms - //double tkcontrast_; // Kcontrast factor computation - //double tnlscale_; // Nonlinear Scale space generation - //double tdetector_; // Feature detector - //double tmderivatives_; // Multiscale derivatives computation - //double tdresponse_; // Detector response computation - //double tdescriptor_; // Feature descriptor - //double tsubpixel_; // Subpixel refinement + // FED parameters + int ncycles_; // Number of cycles + bool reordering_; // Flag for reordering time steps + std::vector > tsteps_; // Vector of FED dynamic time steps + std::vector nsteps_; // Vector of number of steps per cycle - // Some auxiliary variables used in the AOS step - cv::Mat Ltx_, Lty_, px_, py_, ax_, ay_, bx_, by_, qr_, qc_; + // Some auxiliary variables used in the AOS step + cv::Mat Ltx_, Lty_, px_, py_, ax_, ay_, bx_, by_, qr_, qc_; public: - // Constructor - KAZEFeatures(KAZEOptions& options); + // Constructor + KAZEFeatures(KAZEOptions& options); - // Public methods for KAZE interface - void Allocate_Memory_Evolution(void); - int Create_Nonlinear_Scale_Space(const cv::Mat& img); - void Feature_Detection(std::vector& kpts); - void Feature_Description(std::vector& kpts, cv::Mat& desc); + // Public methods for KAZE interface + void Allocate_Memory_Evolution(void); + int Create_Nonlinear_Scale_Space(const cv::Mat& img); + void Feature_Detection(std::vector& kpts); + void Feature_Description(std::vector& kpts, cv::Mat& desc); + + static void Compute_Main_Orientation(cv::KeyPoint& kpt, const std::vector& evolution_, const KAZEOptions& options); private: - // Feature Detection Methods - void Compute_KContrast(const cv::Mat& img, const float& kper); - void Compute_Multiscale_Derivatives(void); - void Compute_Detector_Response(void); - void Determinant_Hessian_Parallel(std::vector& kpts); - void Find_Extremum_Threading(const int& level); - void Do_Subpixel_Refinement(std::vector& kpts); + // Feature Detection Methods + void Compute_KContrast(const cv::Mat& img, const float& kper); + void Compute_Multiscale_Derivatives(void); + void Compute_Detector_Response(void); + void Determinant_Hessian_Parallel(std::vector& kpts); + void Find_Extremum_Threading(const int& level); + void Do_Subpixel_Refinement(std::vector& kpts); - // AOS Methods - void AOS_Step_Scalar(cv::Mat &Ld, const cv::Mat &Ldprev, const cv::Mat &c, const float& stepsize); - void AOS_Rows(const cv::Mat &Ldprev, const cv::Mat &c, const float& stepsize); - void AOS_Columns(const cv::Mat &Ldprev, const cv::Mat &c, const float& stepsize); - void Thomas(const cv::Mat &a, const cv::Mat &b, const cv::Mat &Ld, cv::Mat &x); + // AOS Methods + void AOS_Step_Scalar(cv::Mat &Ld, const cv::Mat &Ldprev, const cv::Mat &c, const float& stepsize); + void AOS_Rows(const cv::Mat &Ldprev, const cv::Mat &c, const float& stepsize); + void AOS_Columns(const cv::Mat &Ldprev, const cv::Mat &c, const float& stepsize); + void Thomas(const cv::Mat &a, const cv::Mat &b, const cv::Mat &Ld, cv::Mat &x); - // Feature Description methods - void Compute_Main_Orientation_SURF(cv::KeyPoint& kpt); - - // Descriptor Mode -> 0 SURF 64 - void Get_SURF_Upright_Descriptor_64(const cv::KeyPoint& kpt, float* desc); - void Get_SURF_Descriptor_64(const cv::KeyPoint& kpt, float* desc); - - // Descriptor Mode -> 0 SURF 128 - void Get_SURF_Upright_Descriptor_128(const cv::KeyPoint& kpt, float* desc); - void Get_SURF_Descriptor_128(const cv::KeyPoint& kpt, float* desc); - - // Descriptor Mode -> 1 M-SURF 64 - void Get_MSURF_Upright_Descriptor_64(const cv::KeyPoint& kpt, float* desc); - void Get_MSURF_Descriptor_64(const cv::KeyPoint& kpt, float* desc); - - // Descriptor Mode -> 1 M-SURF 128 - void Get_MSURF_Upright_Descriptor_128(const cv::KeyPoint& kpt, float* desc); - void Get_MSURF_Descriptor_128(const cv::KeyPoint& kpt, float *desc); - - // Descriptor Mode -> 2 G-SURF 64 - void Get_GSURF_Upright_Descriptor_64(const cv::KeyPoint& kpt, float* desc); - void Get_GSURF_Descriptor_64(const cv::KeyPoint& kpt, float *desc); - - // Descriptor Mode -> 2 G-SURF 128 - void Get_GSURF_Upright_Descriptor_128(const cv::KeyPoint& kpt, float* desc); - void Get_GSURF_Descriptor_128(const cv::KeyPoint& kpt, float* desc); }; //************************************************************************************* diff --git a/modules/features2d/test/test_keypoints.cpp b/modules/features2d/test/test_keypoints.cpp index 3cbd3f6937..a14a9dd72c 100644 --- a/modules/features2d/test/test_keypoints.cpp +++ b/modules/features2d/test/test_keypoints.cpp @@ -169,12 +169,18 @@ TEST(Features2d_Detector_Keypoints_Dense, validation) TEST(Features2d_Detector_Keypoints_KAZE, validation) { - CV_FeatureDetectorKeypointsTest test(Algorithm::create("Feature2D.KAZE")); - test.safe_run(); + CV_FeatureDetectorKeypointsTest test_gsurf(cv::Ptr(new cv::KAZE(cv::KAZE::DESCRIPTOR_GSURF, false, false))); + test_gsurf.safe_run(); + + CV_FeatureDetectorKeypointsTest test_msurf(cv::Ptr(new cv::KAZE(cv::KAZE::DESCRIPTOR_MSURF, false, false))); + test_msurf.safe_run(); } TEST(Features2d_Detector_Keypoints_AKAZE, validation) { - CV_FeatureDetectorKeypointsTest test(Algorithm::create("Feature2D.AKAZE")); - test.safe_run(); + CV_FeatureDetectorKeypointsTest test_kaze(cv::Ptr(new cv::AKAZE(cv::AKAZE::DESCRIPTOR_KAZE))); + test_kaze.safe_run(); + + CV_FeatureDetectorKeypointsTest test_mldb(cv::Ptr(new cv::AKAZE(cv::AKAZE::DESCRIPTOR_MLDB))); + test_mldb.safe_run(); }