diff --git a/modules/xfeatures2d/include/opencv2/xfeatures2d.hpp b/modules/xfeatures2d/include/opencv2/xfeatures2d.hpp index 58d8218f5..b9982efde 100644 --- a/modules/xfeatures2d/include/opencv2/xfeatures2d.hpp +++ b/modules/xfeatures2d/include/opencv2/xfeatures2d.hpp @@ -118,15 +118,14 @@ public: /** @brief Class for computing BRIEF descriptors described in @cite calon2010 . -@note - - A complete BRIEF extractor sample can be found at - opencv_source_code/samples/cpp/brief_match_test.cpp +@param bytes legth of the descriptor in bytes, valid values are: 16, 32 (default) or 64 . +@param use_orientation sample patterns using keypoints orientation, disabled by default. */ class CV_EXPORTS_W BriefDescriptorExtractor : public Feature2D { public: - CV_WRAP static Ptr create( int bytes = 32 ); + static Ptr create( int bytes = 32, bool use_orientation = false ); }; /** @brief Class implementing the locally uniform comparison image descriptor, described in @cite LUCID diff --git a/modules/xfeatures2d/src/brief.cpp b/modules/xfeatures2d/src/brief.cpp index ec131cbfa..cfb1ae833 100644 --- a/modules/xfeatures2d/src/brief.cpp +++ b/modules/xfeatures2d/src/brief.cpp @@ -61,7 +61,7 @@ public: enum { PATCH_SIZE = 48, KERNEL_SIZE = 9 }; // bytes is a length of descriptor in bytes. It can be equal 16, 32 or 64 bytes. - BriefDescriptorExtractorImpl( int bytes = 32 ); + BriefDescriptorExtractorImpl( int bytes = 32, bool use_orientation = false ); virtual void read( const FileNode& ); virtual void write( FileStorage& ) const; @@ -73,67 +73,103 @@ public: virtual void compute(InputArray image, std::vector& keypoints, OutputArray descriptors); protected: - typedef void(*PixelTestFn)(InputArray, const std::vector&, OutputArray); - + typedef void(*PixelTestFn)(InputArray, const std::vector&, OutputArray, bool use_orientation ); + int bytes_; + bool use_orientation_; PixelTestFn test_fn_; }; -Ptr BriefDescriptorExtractor::create( int bytes ) +Ptr BriefDescriptorExtractor::create( int bytes, bool use_orientation ) { - return makePtr(bytes); + return makePtr(bytes, use_orientation ); } -inline int smoothedSum(const Mat& sum, const KeyPoint& pt, int y, int x) +inline int smoothedSum(const Mat& sum, const KeyPoint& pt, int y, int x, bool use_orientation, Matx21f R) { static const int HALF_KERNEL = BriefDescriptorExtractorImpl::KERNEL_SIZE / 2; - int img_y = (int)(pt.pt.y + 0.5) + y; - int img_x = (int)(pt.pt.x + 0.5) + x; + if ( use_orientation ) + { + int rx = (int)(((float)x)*R(1,0) - ((float)y)*R(0,0)); + int ry = (int)(((float)x)*R(0,0) + ((float)y)*R(1,0)); + if (rx > 24) rx = 24; if (rx < -24) rx = -24; + if (ry > 24) ry = 24; if (ry < -24) ry = -24; + x = rx; y = ry; + } + const int img_y = (int)(pt.pt.y + 0.5) + y; + const int img_x = (int)(pt.pt.x + 0.5) + x; return sum.at(img_y + HALF_KERNEL + 1, img_x + HALF_KERNEL + 1) - sum.at(img_y + HALF_KERNEL + 1, img_x - HALF_KERNEL) - sum.at(img_y - HALF_KERNEL, img_x + HALF_KERNEL + 1) + sum.at(img_y - HALF_KERNEL, img_x - HALF_KERNEL); } -static void pixelTests16(InputArray _sum, const std::vector& keypoints, OutputArray _descriptors) +static void pixelTests16(InputArray _sum, const std::vector& keypoints, OutputArray _descriptors, bool use_orientation ) { + Matx21f R; Mat sum = _sum.getMat(), descriptors = _descriptors.getMat(); - for (int i = 0; i < (int)keypoints.size(); ++i) + for (size_t i = 0; i < keypoints.size(); ++i) { - uchar* desc = descriptors.ptr(i); + uchar* desc = descriptors.ptr(static_cast(i)); const KeyPoint& pt = keypoints[i]; + if ( use_orientation ) + { + float angle = pt.angle; + angle *= (float)(CV_PI/180.f); + R(0,0) = sin(angle); + R(1,0) = cos(angle); + } + #include "generated_16.i" } } -static void pixelTests32(InputArray _sum, const std::vector& keypoints, OutputArray _descriptors) +static void pixelTests32(InputArray _sum, const std::vector& keypoints, OutputArray _descriptors, bool use_orientation) { + Matx21f R; Mat sum = _sum.getMat(), descriptors = _descriptors.getMat(); - for (int i = 0; i < (int)keypoints.size(); ++i) + for (size_t i = 0; i < keypoints.size(); ++i) { - uchar* desc = descriptors.ptr(i); + uchar* desc = descriptors.ptr(static_cast(i)); const KeyPoint& pt = keypoints[i]; + if ( use_orientation ) + { + float angle = pt.angle; + angle *= (float)(CV_PI / 180.f); + R(0,0) = sin(angle); + R(1,0) = cos(angle); + } #include "generated_32.i" } } -static void pixelTests64(InputArray _sum, const std::vector& keypoints, OutputArray _descriptors) +static void pixelTests64(InputArray _sum, const std::vector& keypoints, OutputArray _descriptors, bool use_orientation) { + Matx21f R; Mat sum = _sum.getMat(), descriptors = _descriptors.getMat(); - for (int i = 0; i < (int)keypoints.size(); ++i) + for (size_t i = 0; i < keypoints.size(); ++i) { - uchar* desc = descriptors.ptr(i); + uchar* desc = descriptors.ptr(static_cast(i)); const KeyPoint& pt = keypoints[i]; + if ( use_orientation ) + { + float angle = pt.angle; + angle *= (float)(CV_PI/180.f); + R(0,0) = sin(angle); + R(1,0) = cos(angle); + } #include "generated_64.i" } } -BriefDescriptorExtractorImpl::BriefDescriptorExtractorImpl(int bytes) : +BriefDescriptorExtractorImpl::BriefDescriptorExtractorImpl(int bytes, bool use_orientation) : bytes_(bytes), test_fn_(NULL) { + use_orientation_ = use_orientation; + switch (bytes) { case 16: @@ -212,7 +248,7 @@ void BriefDescriptorExtractorImpl::compute(InputArray image, descriptors.create((int)keypoints.size(), bytes_, CV_8U); descriptors.setTo(Scalar::all(0)); - test_fn_(sum, keypoints, descriptors); + test_fn_(sum, keypoints, descriptors, use_orientation_); } } diff --git a/modules/xfeatures2d/src/generated_16.i b/modules/xfeatures2d/src/generated_16.i index b85bf06d9..f6fcfacee 100644 --- a/modules/xfeatures2d/src/generated_16.i +++ b/modules/xfeatures2d/src/generated_16.i @@ -1,5 +1,5 @@ // Code generated with '$ scripts/generate_code.py src/test_pairs.txt 16' -#define SMOOTHED(y,x) smoothedSum(sum, pt, y, x) +#define SMOOTHED(y,x) smoothedSum(sum, pt, y, x, use_orientation, R) desc[0] = (uchar)(((SMOOTHED(-2, -1) < SMOOTHED(7, -1)) << 7) + ((SMOOTHED(-14, -1) < SMOOTHED(-3, 3)) << 6) + ((SMOOTHED(1, -2) < SMOOTHED(11, 2)) << 5) + ((SMOOTHED(1, 6) < SMOOTHED(-10, -7)) << 4) + ((SMOOTHED(13, 2) < SMOOTHED(-1, 0)) << 3) + ((SMOOTHED(-14, 5) < SMOOTHED(5, -3)) << 2) + ((SMOOTHED(-2, 8) < SMOOTHED(2, 4)) << 1) + ((SMOOTHED(-11, 8) < SMOOTHED(-15, 5)) << 0)); desc[1] = (uchar)(((SMOOTHED(-6, -23) < SMOOTHED(8, -9)) << 7) + ((SMOOTHED(-12, 6) < SMOOTHED(-10, 8)) << 6) + ((SMOOTHED(-3, -1) < SMOOTHED(8, 1)) << 5) + ((SMOOTHED(3, 6) < SMOOTHED(5, 6)) << 4) + ((SMOOTHED(-7, -6) < SMOOTHED(5, -5)) << 3) + ((SMOOTHED(22, -2) < SMOOTHED(-11, -8)) << 2) + ((SMOOTHED(14, 7) < SMOOTHED(8, 5)) << 1) + ((SMOOTHED(-1, 14) < SMOOTHED(-5, -14)) << 0)); desc[2] = (uchar)(((SMOOTHED(-14, 9) < SMOOTHED(2, 0)) << 7) + ((SMOOTHED(7, -3) < SMOOTHED(22, 6)) << 6) + ((SMOOTHED(-6, 6) < SMOOTHED(-8, -5)) << 5) + ((SMOOTHED(-5, 9) < SMOOTHED(7, -1)) << 4) + ((SMOOTHED(-3, -7) < SMOOTHED(-10, -18)) << 3) + ((SMOOTHED(4, -5) < SMOOTHED(0, 11)) << 2) + ((SMOOTHED(2, 3) < SMOOTHED(9, 10)) << 1) + ((SMOOTHED(-10, 3) < SMOOTHED(4, 9)) << 0)); diff --git a/modules/xfeatures2d/src/generated_32.i b/modules/xfeatures2d/src/generated_32.i index 19952d2f7..d53850250 100644 --- a/modules/xfeatures2d/src/generated_32.i +++ b/modules/xfeatures2d/src/generated_32.i @@ -1,5 +1,5 @@ // Code generated with '$ scripts/generate_code.py src/test_pairs.txt 32' -#define SMOOTHED(y,x) smoothedSum(sum, pt, y, x) +#define SMOOTHED(y,x) smoothedSum(sum, pt, y, x, use_orientation, R) desc[0] = (uchar)(((SMOOTHED(-2, -1) < SMOOTHED(7, -1)) << 7) + ((SMOOTHED(-14, -1) < SMOOTHED(-3, 3)) << 6) + ((SMOOTHED(1, -2) < SMOOTHED(11, 2)) << 5) + ((SMOOTHED(1, 6) < SMOOTHED(-10, -7)) << 4) + ((SMOOTHED(13, 2) < SMOOTHED(-1, 0)) << 3) + ((SMOOTHED(-14, 5) < SMOOTHED(5, -3)) << 2) + ((SMOOTHED(-2, 8) < SMOOTHED(2, 4)) << 1) + ((SMOOTHED(-11, 8) < SMOOTHED(-15, 5)) << 0)); desc[1] = (uchar)(((SMOOTHED(-6, -23) < SMOOTHED(8, -9)) << 7) + ((SMOOTHED(-12, 6) < SMOOTHED(-10, 8)) << 6) + ((SMOOTHED(-3, -1) < SMOOTHED(8, 1)) << 5) + ((SMOOTHED(3, 6) < SMOOTHED(5, 6)) << 4) + ((SMOOTHED(-7, -6) < SMOOTHED(5, -5)) << 3) + ((SMOOTHED(22, -2) < SMOOTHED(-11, -8)) << 2) + ((SMOOTHED(14, 7) < SMOOTHED(8, 5)) << 1) + ((SMOOTHED(-1, 14) < SMOOTHED(-5, -14)) << 0)); desc[2] = (uchar)(((SMOOTHED(-14, 9) < SMOOTHED(2, 0)) << 7) + ((SMOOTHED(7, -3) < SMOOTHED(22, 6)) << 6) + ((SMOOTHED(-6, 6) < SMOOTHED(-8, -5)) << 5) + ((SMOOTHED(-5, 9) < SMOOTHED(7, -1)) << 4) + ((SMOOTHED(-3, -7) < SMOOTHED(-10, -18)) << 3) + ((SMOOTHED(4, -5) < SMOOTHED(0, 11)) << 2) + ((SMOOTHED(2, 3) < SMOOTHED(9, 10)) << 1) + ((SMOOTHED(-10, 3) < SMOOTHED(4, 9)) << 0)); diff --git a/modules/xfeatures2d/src/generated_64.i b/modules/xfeatures2d/src/generated_64.i index 2262e2d41..24ad1bd56 100644 --- a/modules/xfeatures2d/src/generated_64.i +++ b/modules/xfeatures2d/src/generated_64.i @@ -1,5 +1,5 @@ // Code generated with '$ scripts/generate_code.py src/test_pairs.txt 64' -#define SMOOTHED(y,x) smoothedSum(sum, pt, y, x) +#define SMOOTHED(y,x) smoothedSum(sum, pt, y, x, use_orientation, R) desc[0] = (uchar)(((SMOOTHED(-2, -1) < SMOOTHED(7, -1)) << 7) + ((SMOOTHED(-14, -1) < SMOOTHED(-3, 3)) << 6) + ((SMOOTHED(1, -2) < SMOOTHED(11, 2)) << 5) + ((SMOOTHED(1, 6) < SMOOTHED(-10, -7)) << 4) + ((SMOOTHED(13, 2) < SMOOTHED(-1, 0)) << 3) + ((SMOOTHED(-14, 5) < SMOOTHED(5, -3)) << 2) + ((SMOOTHED(-2, 8) < SMOOTHED(2, 4)) << 1) + ((SMOOTHED(-11, 8) < SMOOTHED(-15, 5)) << 0)); desc[1] = (uchar)(((SMOOTHED(-6, -23) < SMOOTHED(8, -9)) << 7) + ((SMOOTHED(-12, 6) < SMOOTHED(-10, 8)) << 6) + ((SMOOTHED(-3, -1) < SMOOTHED(8, 1)) << 5) + ((SMOOTHED(3, 6) < SMOOTHED(5, 6)) << 4) + ((SMOOTHED(-7, -6) < SMOOTHED(5, -5)) << 3) + ((SMOOTHED(22, -2) < SMOOTHED(-11, -8)) << 2) + ((SMOOTHED(14, 7) < SMOOTHED(8, 5)) << 1) + ((SMOOTHED(-1, 14) < SMOOTHED(-5, -14)) << 0)); desc[2] = (uchar)(((SMOOTHED(-14, 9) < SMOOTHED(2, 0)) << 7) + ((SMOOTHED(7, -3) < SMOOTHED(22, 6)) << 6) + ((SMOOTHED(-6, 6) < SMOOTHED(-8, -5)) << 5) + ((SMOOTHED(-5, 9) < SMOOTHED(7, -1)) << 4) + ((SMOOTHED(-3, -7) < SMOOTHED(-10, -18)) << 3) + ((SMOOTHED(4, -5) < SMOOTHED(0, 11)) << 2) + ((SMOOTHED(2, 3) < SMOOTHED(9, 10)) << 1) + ((SMOOTHED(-10, 3) < SMOOTHED(4, 9)) << 0)); diff --git a/modules/xfeatures2d/test/test_rotation_and_scale_invariance.cpp b/modules/xfeatures2d/test/test_rotation_and_scale_invariance.cpp index b51c84d96..88467b19c 100644 --- a/modules/xfeatures2d/test/test_rotation_and_scale_invariance.cpp +++ b/modules/xfeatures2d/test/test_rotation_and_scale_invariance.cpp @@ -669,6 +669,32 @@ TEST(Features2d_RotationInvariance_Descriptor_DAISY, regression) test.safe_run(); } +TEST(Features2d_RotationInvariance_Descriptor_BRIEF_64, regression) +{ + DescriptorRotationInvarianceTest test(SURF::create(), + BriefDescriptorExtractor::create(64,true), + NORM_L1, + 0.98f); + test.safe_run(); +} + +TEST(Features2d_RotationInvariance_Descriptor_BRIEF_32, regression) +{ + DescriptorRotationInvarianceTest test(SURF::create(), + BriefDescriptorExtractor::create(32,true), + NORM_L1, + 0.97f); + test.safe_run(); +} + +TEST(Features2d_RotationInvariance_Descriptor_BRIEF_16, regression) +{ + DescriptorRotationInvarianceTest test(SURF::create(), + BriefDescriptorExtractor::create(16,true), + NORM_L1, + 0.85f); + test.safe_run(); +} /* * Detector's scale invariance check