diff --git a/modules/nonfree/include/opencv2/nonfree/ocl.hpp b/modules/nonfree/include/opencv2/nonfree/ocl.hpp index 78b6b466c4..ad0c16ac48 100644 --- a/modules/nonfree/include/opencv2/nonfree/ocl.hpp +++ b/modules/nonfree/include/opencv2/nonfree/ocl.hpp @@ -53,7 +53,7 @@ namespace cv //! Speeded up robust features, port from GPU module. ////////////////////////////////// SURF ////////////////////////////////////////// - class CV_EXPORTS SURF_OCL + class CV_EXPORTS SURF_OCL : public Feature2D { public: enum KeypointLayout @@ -72,10 +72,13 @@ namespace cv SURF_OCL(); //! the full constructor taking all the necessary parameters explicit SURF_OCL(double _hessianThreshold, int _nOctaves = 4, - int _nOctaveLayers = 2, bool _extended = false, float _keypointsRatio = 0.01f, bool _upright = false); + int _nOctaveLayers = 2, bool _extended = true, float _keypointsRatio = 0.01f, bool _upright = false); //! returns the descriptor size in float's (64 or 128) int descriptorSize() const; + + int descriptorType() const; + //! upload host keypoints to device memory void uploadKeypoints(const vector &keypoints, oclMat &keypointsocl); //! download keypoints from device to host memory @@ -103,6 +106,17 @@ namespace cv void operator()(const oclMat &img, const oclMat &mask, std::vector &keypoints, std::vector &descriptors, bool useProvidedKeypoints = false); + //! finds the keypoints using fast hessian detector used in SURF + void operator()(InputArray img, InputArray mask, + CV_OUT vector& keypoints) const; + //! finds the keypoints and computes their descriptors. Optionally it can compute descriptors for the user-provided keypoints + void operator()(InputArray img, InputArray mask, + CV_OUT vector& keypoints, + OutputArray descriptors, + bool useProvidedKeypoints=false) const; + + AlgorithmInfo* info() const; + void releaseMemory(); // SURF parameters @@ -116,7 +130,9 @@ namespace cv oclMat sum, mask1, maskSum, intBuffer; oclMat det, trace; oclMat maxPosBuffer; - + protected: + void detectImpl( const Mat& image, vector& keypoints, const Mat& mask) const; + void computeImpl( const Mat& image, vector& keypoints, Mat& descriptors) const; }; } } diff --git a/modules/nonfree/src/nonfree_init.cpp b/modules/nonfree/src/nonfree_init.cpp index f18e7d81d9..136b362ca4 100644 --- a/modules/nonfree/src/nonfree_init.cpp +++ b/modules/nonfree/src/nonfree_init.cpp @@ -63,6 +63,20 @@ CV_INIT_ALGORITHM(SIFT, "Feature2D.SIFT", obj.info()->addParam(obj, "edgeThreshold", obj.edgeThreshold); obj.info()->addParam(obj, "sigma", obj.sigma)) +#ifdef HAVE_OPENCV_OCL + +namespace ocl { +CV_INIT_ALGORITHM(SURF_OCL, "Feature2D.SURF_OCL", + obj.info()->addParam(obj, "hessianThreshold", obj.hessianThreshold); + obj.info()->addParam(obj, "nOctaves", obj.nOctaves); + obj.info()->addParam(obj, "nOctaveLayers", obj.nOctaveLayers); + obj.info()->addParam(obj, "extended", obj.extended); + obj.info()->addParam(obj, "upright", obj.upright)) +} + +#endif + + /////////////////////////////////////////////////////////////////////////////////////////////////////////// bool initModule_nonfree(void) diff --git a/modules/nonfree/src/surf_ocl.cpp b/modules/nonfree/src/surf_ocl.cpp index 293fd84b56..2922c2cee6 100644 --- a/modules/nonfree/src/surf_ocl.cpp +++ b/modules/nonfree/src/surf_ocl.cpp @@ -305,6 +305,11 @@ int cv::ocl::SURF_OCL::descriptorSize() const return extended ? 128 : 64; } +int cv::ocl::SURF_OCL::descriptorType() const +{ + return CV_32F; +} + void cv::ocl::SURF_OCL::uploadKeypoints(const vector &keypoints, oclMat &keypointsGPU) { if (keypoints.empty()) @@ -447,6 +452,81 @@ void cv::ocl::SURF_OCL::operator()(const oclMat &img, const oclMat &mask, vector downloadDescriptors(descriptorsGPU, descriptors); } + +void cv::ocl::SURF_OCL::operator()(InputArray img, InputArray mask, + CV_OUT vector& keypoints) const +{ + this->operator()(img, mask, keypoints, noArray(), false); +} + +void cv::ocl::SURF_OCL::operator()(InputArray img, InputArray mask, vector &keypoints, + OutputArray descriptors, bool useProvidedKeypoints) const +{ + oclMat _img, _mask; + if(img.kind() == _InputArray::OCL_MAT) + _img = *(oclMat*)img.obj; + else + _img.upload(img.getMat()); + if(_img.channels() != 1) + { + oclMat temp; + cvtColor(_img, temp, COLOR_BGR2GRAY); + _img = temp; + } + + if( !mask.empty() ) + { + if(mask.kind() == _InputArray::OCL_MAT) + _mask = *(oclMat*)mask.obj; + else + _mask.upload(mask.getMat()); + } + + SURF_OCL_Invoker surf((SURF_OCL&)*this, _img, _mask); + oclMat keypointsGPU; + + if (!useProvidedKeypoints || !upright) + ((SURF_OCL*)this)->uploadKeypoints(keypoints, keypointsGPU); + + if (!useProvidedKeypoints) + surf.detectKeypoints(keypointsGPU); + else if (!upright) + surf.findOrientation(keypointsGPU); + if(keypointsGPU.cols*keypointsGPU.rows != 0) + ((SURF_OCL*)this)->downloadKeypoints(keypointsGPU, keypoints); + + if( descriptors.needed() ) + { + oclMat descriptorsGPU; + surf.computeDescriptors(keypointsGPU, descriptorsGPU, descriptorSize()); + Size sz = descriptorsGPU.size(); + if( descriptors.kind() == _InputArray::STD_VECTOR ) + { + CV_Assert(descriptors.type() == CV_32F); + std::vector* v = (std::vector*)descriptors.obj; + v->resize(sz.width*sz.height); + Mat m(sz, CV_32F, &v->at(0)); + descriptorsGPU.download(m); + } + else + { + descriptors.create(sz, CV_32F); + Mat m = descriptors.getMat(); + descriptorsGPU.download(m); + } + } +} + +void cv::ocl::SURF_OCL::detectImpl( const Mat& image, vector& keypoints, const Mat& mask) const +{ + (*this)(image, mask, keypoints, noArray(), false); +} + +void cv::ocl::SURF_OCL::computeImpl( const Mat& image, vector& keypoints, Mat& descriptors) const +{ + (*this)(image, Mat(), keypoints, descriptors, true); +} + void cv::ocl::SURF_OCL::releaseMemory() { sum.release(); diff --git a/modules/nonfree/test/test_features2d.cpp b/modules/nonfree/test/test_features2d.cpp index b680d948b8..66a35931ad 100644 --- a/modules/nonfree/test/test_features2d.cpp +++ b/modules/nonfree/test/test_features2d.cpp @@ -50,6 +50,12 @@ const string DETECTOR_DIR = FEATURES2D_DIR + "/feature_detectors"; const string DESCRIPTOR_DIR = FEATURES2D_DIR + "/descriptor_extractors"; const string IMAGE_FILENAME = "tsukuba.png"; +#ifdef HAVE_OPENCV_OCL +#define SURF_NAME "SURF_OCL" +#else +#define SURF_NAME "SURF" +#endif + /****************************************************************************************\ * Regression tests for feature detectors comparing keypoints. * \****************************************************************************************/ @@ -978,7 +984,7 @@ TEST( Features2d_Detector_SIFT, regression ) TEST( Features2d_Detector_SURF, regression ) { - CV_FeatureDetectorTest test( "detector-surf", FeatureDetector::create("SURF") ); + CV_FeatureDetectorTest test( "detector-surf", FeatureDetector::create(SURF_NAME) ); test.safe_run(); } @@ -995,7 +1001,7 @@ TEST( Features2d_DescriptorExtractor_SIFT, regression ) TEST( Features2d_DescriptorExtractor_SURF, regression ) { CV_DescriptorExtractorTest > test( "descriptor-surf", 0.05f, - DescriptorExtractor::create("SURF") ); + DescriptorExtractor::create(SURF_NAME) ); test.safe_run(); } @@ -1036,10 +1042,10 @@ TEST(Features2d_BruteForceDescriptorMatcher_knnMatch, regression) const int sz = 100; const int k = 3; - Ptr ext = DescriptorExtractor::create("SURF"); + Ptr ext = DescriptorExtractor::create(SURF_NAME); ASSERT_TRUE(ext != NULL); - Ptr det = FeatureDetector::create("SURF"); + Ptr det = FeatureDetector::create(SURF_NAME); //"%YAML:1.0\nhessianThreshold: 8000.\noctaves: 3\noctaveLayers: 4\nupright: 0\n" ASSERT_TRUE(det != NULL); @@ -1144,7 +1150,7 @@ protected: }; TEST(Features2d_SIFTHomographyTest, regression) { CV_DetectPlanarTest test("SIFT", 80); test.safe_run(); } -TEST(Features2d_SURFHomographyTest, regression) { CV_DetectPlanarTest test("SURF", 80); test.safe_run(); } +TEST(Features2d_SURFHomographyTest, regression) { CV_DetectPlanarTest test(SURF_NAME, 80); test.safe_run(); } class FeatureDetectorUsingMaskTest : public cvtest::BaseTest { diff --git a/modules/nonfree/test/test_rotation_and_scale_invariance.cpp b/modules/nonfree/test/test_rotation_and_scale_invariance.cpp index 7ca9e3dd74..255cad313c 100644 --- a/modules/nonfree/test/test_rotation_and_scale_invariance.cpp +++ b/modules/nonfree/test/test_rotation_and_scale_invariance.cpp @@ -48,6 +48,12 @@ using namespace cv; const string IMAGE_TSUKUBA = "/features2d/tsukuba.png"; const string IMAGE_BIKES = "/detectors_descriptors_evaluation/images_datasets/bikes/img1.png"; +#ifdef HAVE_OPENCV_OCL +#define SURF_NAME "Feature2D.SURF_OCL" +#else +#define SURF_NAME "Feature2D.SURF" +#endif + #define SHOW_DEBUG_LOG 0 static @@ -615,7 +621,7 @@ protected: */ TEST(Features2d_RotationInvariance_Detector_SURF, regression) { - DetectorRotationInvarianceTest test(Algorithm::create("Feature2D.SURF"), + DetectorRotationInvarianceTest test(Algorithm::create(SURF_NAME), 0.44f, 0.76f); test.safe_run(); @@ -634,8 +640,8 @@ TEST(Features2d_RotationInvariance_Detector_SIFT, DISABLED_regression) */ TEST(Features2d_RotationInvariance_Descriptor_SURF, regression) { - DescriptorRotationInvarianceTest test(Algorithm::create("Feature2D.SURF"), - Algorithm::create("Feature2D.SURF"), + DescriptorRotationInvarianceTest test(Algorithm::create(SURF_NAME), + Algorithm::create(SURF_NAME), NORM_L1, 0.83f); test.safe_run(); @@ -655,7 +661,7 @@ TEST(Features2d_RotationInvariance_Descriptor_SIFT, regression) */ TEST(Features2d_ScaleInvariance_Detector_SURF, regression) { - DetectorScaleInvarianceTest test(Algorithm::create("Feature2D.SURF"), + DetectorScaleInvarianceTest test(Algorithm::create(SURF_NAME), 0.64f, 0.84f); test.safe_run(); @@ -674,8 +680,8 @@ TEST(Features2d_ScaleInvariance_Detector_SIFT, regression) */ TEST(Features2d_ScaleInvariance_Descriptor_SURF, regression) { - DescriptorScaleInvarianceTest test(Algorithm::create("Feature2D.SURF"), - Algorithm::create("Feature2D.SURF"), + DescriptorScaleInvarianceTest test(Algorithm::create(SURF_NAME), + Algorithm::create(SURF_NAME), NORM_L1, 0.61f); test.safe_run();