Commit a1d15192 authored by Andrey Pavlenko's avatar Andrey Pavlenko Committed by OpenCV Buildbot

Merge pull request #2527 from apavlenko:ocl_surf_24

parents a7f96773 fa570561
...@@ -240,7 +240,7 @@ The class ``SURF_GPU`` uses some buffers and provides access to it. All buffers ...@@ -240,7 +240,7 @@ The class ``SURF_GPU`` uses some buffers and provides access to it. All buffers
ocl::SURF_OCL ocl::SURF_OCL
------------- -------------
.. ocv:class:: ocl::SURF_OCL .. ocv:class:: ocl::SURF_OCL : public Feature2D
Class used for extracting Speeded Up Robust Features (SURF) from an image. :: Class used for extracting Speeded Up Robust Features (SURF) from an image. ::
......
...@@ -53,7 +53,7 @@ namespace cv ...@@ -53,7 +53,7 @@ namespace cv
//! Speeded up robust features, port from GPU module. //! Speeded up robust features, port from GPU module.
////////////////////////////////// SURF ////////////////////////////////////////// ////////////////////////////////// SURF //////////////////////////////////////////
class CV_EXPORTS SURF_OCL class CV_EXPORTS SURF_OCL : public cv::Feature2D
{ {
public: public:
enum KeypointLayout enum KeypointLayout
...@@ -72,10 +72,13 @@ namespace cv ...@@ -72,10 +72,13 @@ namespace cv
SURF_OCL(); SURF_OCL();
//! the full constructor taking all the necessary parameters //! the full constructor taking all the necessary parameters
explicit SURF_OCL(double _hessianThreshold, int _nOctaves = 4, 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) //! returns the descriptor size in float's (64 or 128)
int descriptorSize() const; int descriptorSize() const;
int descriptorType() const;
//! upload host keypoints to device memory //! upload host keypoints to device memory
void uploadKeypoints(const vector<cv::KeyPoint> &keypoints, oclMat &keypointsocl); void uploadKeypoints(const vector<cv::KeyPoint> &keypoints, oclMat &keypointsocl);
//! download keypoints from device to host memory //! download keypoints from device to host memory
...@@ -103,6 +106,17 @@ namespace cv ...@@ -103,6 +106,17 @@ namespace cv
void operator()(const oclMat &img, const oclMat &mask, std::vector<KeyPoint> &keypoints, std::vector<float> &descriptors, void operator()(const oclMat &img, const oclMat &mask, std::vector<KeyPoint> &keypoints, std::vector<float> &descriptors,
bool useProvidedKeypoints = false); bool useProvidedKeypoints = false);
//! finds the keypoints using fast hessian detector used in SURF
void operator()(InputArray img, InputArray mask,
CV_OUT vector<KeyPoint>& 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<KeyPoint>& keypoints,
OutputArray descriptors,
bool useProvidedKeypoints=false) const;
AlgorithmInfo* info() const;
void releaseMemory(); void releaseMemory();
// SURF parameters // SURF parameters
...@@ -116,7 +130,9 @@ namespace cv ...@@ -116,7 +130,9 @@ namespace cv
oclMat sum, mask1, maskSum, intBuffer; oclMat sum, mask1, maskSum, intBuffer;
oclMat det, trace; oclMat det, trace;
oclMat maxPosBuffer; oclMat maxPosBuffer;
protected:
void detectImpl( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask) const;
void computeImpl( const Mat& image, vector<KeyPoint>& keypoints, Mat& descriptors) const;
}; };
} }
} }
......
...@@ -11,4 +11,31 @@ static const char * impls[] = { ...@@ -11,4 +11,31 @@ static const char * impls[] = {
"plain" "plain"
}; };
CV_PERF_TEST_MAIN_WITH_IMPLS(nonfree, impls, perf::printCudaInfo()) #ifdef HAVE_OPENCL
#define DUMP_PROPERTY_XML(propertyName, propertyValue) \
do { \
std::stringstream ssName, ssValue;\
ssName << propertyName;\
ssValue << propertyValue; \
::testing::Test::RecordProperty(ssName.str(), ssValue.str()); \
} while (false)
#define DUMP_MESSAGE_STDOUT(msg) \
do { \
std::cout << msg << std::endl; \
} while (false)
#include "opencv2/ocl/private/opencl_dumpinfo.hpp"
#endif
int main(int argc, char **argv)
{
::perf::TestBase::setPerformanceStrategy(::perf::PERF_STRATEGY_SIMPLE);
#if defined(HAVE_CUDA)
CV_PERF_TEST_MAIN_INTERNALS(nonfree, impls, perf::printCudaInfo());
#elif defined(HAVE_OPENCL)
CV_PERF_TEST_MAIN_INTERNALS(nonfree, impls, dumpOpenCLDevice());
#else
CV_PERF_TEST_MAIN_INTERNALS(nonfree, impls)
#endif
}
...@@ -16,9 +16,7 @@ PERF_TEST_P(surf, detect, testing::Values(SURF_IMAGES)) ...@@ -16,9 +16,7 @@ PERF_TEST_P(surf, detect, testing::Values(SURF_IMAGES))
{ {
String filename = getDataPath(GetParam()); String filename = getDataPath(GetParam());
Mat frame = imread(filename, IMREAD_GRAYSCALE); Mat frame = imread(filename, IMREAD_GRAYSCALE);
ASSERT_FALSE(frame.empty()) << "Unable to load source image " << filename;
if (frame.empty())
FAIL() << "Unable to load source image " << filename;
Mat mask; Mat mask;
declare.in(frame).time(90); declare.in(frame).time(90);
...@@ -34,9 +32,7 @@ PERF_TEST_P(surf, extract, testing::Values(SURF_IMAGES)) ...@@ -34,9 +32,7 @@ PERF_TEST_P(surf, extract, testing::Values(SURF_IMAGES))
{ {
String filename = getDataPath(GetParam()); String filename = getDataPath(GetParam());
Mat frame = imread(filename, IMREAD_GRAYSCALE); Mat frame = imread(filename, IMREAD_GRAYSCALE);
ASSERT_FALSE(frame.empty()) << "Unable to load source image " << filename;
if (frame.empty())
FAIL() << "Unable to load source image " << filename;
Mat mask; Mat mask;
declare.in(frame).time(90); declare.in(frame).time(90);
...@@ -55,9 +51,7 @@ PERF_TEST_P(surf, full, testing::Values(SURF_IMAGES)) ...@@ -55,9 +51,7 @@ PERF_TEST_P(surf, full, testing::Values(SURF_IMAGES))
{ {
String filename = getDataPath(GetParam()); String filename = getDataPath(GetParam());
Mat frame = imread(filename, IMREAD_GRAYSCALE); Mat frame = imread(filename, IMREAD_GRAYSCALE);
ASSERT_FALSE(frame.empty()) << "Unable to load source image " << filename;
if (frame.empty())
FAIL() << "Unable to load source image " << filename;
Mat mask; Mat mask;
declare.in(frame).time(90); declare.in(frame).time(90);
......
...@@ -121,4 +121,93 @@ PERF_TEST_P(OCL_SURF, DISABLED_without_data_transfer, testing::Values(SURF_IMAGE ...@@ -121,4 +121,93 @@ PERF_TEST_P(OCL_SURF, DISABLED_without_data_transfer, testing::Values(SURF_IMAGE
SANITY_CHECK_NOTHING(); SANITY_CHECK_NOTHING();
} }
PERF_TEST_P(OCL_SURF, DISABLED_detect, testing::Values(SURF_IMAGES))
{
String filename = getDataPath(GetParam());
Mat frame = imread(filename, IMREAD_GRAYSCALE);
ASSERT_FALSE(frame.empty()) << "Unable to load source image " << filename;
declare.in(frame);
Mat mask;
vector<KeyPoint> points;
Ptr<Feature2D> detector;
if (getSelectedImpl() == "plain")
{
detector = new SURF;
TEST_CYCLE() detector->operator()(frame, mask, points, noArray());
}
else if (getSelectedImpl() == "ocl")
{
detector = new ocl::SURF_OCL;
OCL_TEST_CYCLE() detector->operator()(frame, mask, points, noArray());
}
else CV_TEST_FAIL_NO_IMPL();
SANITY_CHECK_KEYPOINTS(points, 1e-3);
}
PERF_TEST_P(OCL_SURF, DISABLED_extract, testing::Values(SURF_IMAGES))
{
String filename = getDataPath(GetParam());
Mat frame = imread(filename, IMREAD_GRAYSCALE);
ASSERT_FALSE(frame.empty()) << "Unable to load source image " << filename;
declare.in(frame);
Mat mask;
Ptr<Feature2D> detector;
vector<KeyPoint> points;
vector<float> descriptors;
if (getSelectedImpl() == "plain")
{
detector = new SURF;
detector->operator()(frame, mask, points, noArray());
TEST_CYCLE() detector->operator()(frame, mask, points, descriptors, true);
}
else if (getSelectedImpl() == "ocl")
{
detector = new ocl::SURF_OCL;
detector->operator()(frame, mask, points, noArray());
OCL_TEST_CYCLE() detector->operator()(frame, mask, points, descriptors, true);
}
else CV_TEST_FAIL_NO_IMPL();
SANITY_CHECK(descriptors, 1e-4);
}
PERF_TEST_P(OCL_SURF, DISABLED_full, testing::Values(SURF_IMAGES))
{
String filename = getDataPath(GetParam());
Mat frame = imread(filename, IMREAD_GRAYSCALE);
ASSERT_FALSE(frame.empty()) << "Unable to load source image " << filename;
declare.in(frame).time(90);
Mat mask;
Ptr<Feature2D> detector;
vector<KeyPoint> points;
vector<float> descriptors;
if (getSelectedImpl() == "plain")
{
detector = new SURF;
TEST_CYCLE() detector->operator()(frame, mask, points, descriptors, false);
}
else if (getSelectedImpl() == "ocl")
{
detector = new ocl::SURF_OCL;
detector->operator()(frame, mask, points, noArray());
OCL_TEST_CYCLE() detector->operator()(frame, mask, points, descriptors, false);
}
else CV_TEST_FAIL_NO_IMPL();
SANITY_CHECK_KEYPOINTS(points, 1e-3);
SANITY_CHECK(descriptors, 1e-4);
}
#endif // HAVE_OPENCV_OCL #endif // HAVE_OPENCV_OCL
...@@ -63,6 +63,20 @@ CV_INIT_ALGORITHM(SIFT, "Feature2D.SIFT", ...@@ -63,6 +63,20 @@ CV_INIT_ALGORITHM(SIFT, "Feature2D.SIFT",
obj.info()->addParam(obj, "edgeThreshold", obj.edgeThreshold); obj.info()->addParam(obj, "edgeThreshold", obj.edgeThreshold);
obj.info()->addParam(obj, "sigma", obj.sigma)) 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) bool initModule_nonfree(void)
......
...@@ -283,9 +283,9 @@ private: ...@@ -283,9 +283,9 @@ private:
cv::ocl::SURF_OCL::SURF_OCL() cv::ocl::SURF_OCL::SURF_OCL()
{ {
hessianThreshold = 100.0f; hessianThreshold = 100.0f;
extended = true; extended = false;
nOctaves = 4; nOctaves = 4;
nOctaveLayers = 2; nOctaveLayers = 3;
keypointsRatio = 0.01f; keypointsRatio = 0.01f;
upright = false; upright = false;
} }
...@@ -305,6 +305,11 @@ int cv::ocl::SURF_OCL::descriptorSize() const ...@@ -305,6 +305,11 @@ int cv::ocl::SURF_OCL::descriptorSize() const
return extended ? 128 : 64; return extended ? 128 : 64;
} }
int cv::ocl::SURF_OCL::descriptorType() const
{
return CV_32F;
}
void cv::ocl::SURF_OCL::uploadKeypoints(const vector<KeyPoint> &keypoints, oclMat &keypointsGPU) void cv::ocl::SURF_OCL::uploadKeypoints(const vector<KeyPoint> &keypoints, oclMat &keypointsGPU)
{ {
if (keypoints.empty()) if (keypoints.empty())
...@@ -447,6 +452,81 @@ void cv::ocl::SURF_OCL::operator()(const oclMat &img, const oclMat &mask, vector ...@@ -447,6 +452,81 @@ void cv::ocl::SURF_OCL::operator()(const oclMat &img, const oclMat &mask, vector
downloadDescriptors(descriptorsGPU, descriptors); downloadDescriptors(descriptorsGPU, descriptors);
} }
void cv::ocl::SURF_OCL::operator()(InputArray img, InputArray mask,
CV_OUT vector<KeyPoint>& keypoints) const
{
this->operator()(img, mask, keypoints, noArray(), false);
}
void cv::ocl::SURF_OCL::operator()(InputArray img, InputArray mask, vector<KeyPoint> &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<float>* v = (std::vector<float>*)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<KeyPoint>& keypoints, const Mat& mask) const
{
(*this)(image, mask, keypoints, noArray(), false);
}
void cv::ocl::SURF_OCL::computeImpl( const Mat& image, vector<KeyPoint>& keypoints, Mat& descriptors) const
{
(*this)(image, Mat(), keypoints, descriptors, true);
}
void cv::ocl::SURF_OCL::releaseMemory() void cv::ocl::SURF_OCL::releaseMemory()
{ {
sum.release(); sum.release();
......
...@@ -50,6 +50,22 @@ const string DETECTOR_DIR = FEATURES2D_DIR + "/feature_detectors"; ...@@ -50,6 +50,22 @@ const string DETECTOR_DIR = FEATURES2D_DIR + "/feature_detectors";
const string DESCRIPTOR_DIR = FEATURES2D_DIR + "/descriptor_extractors"; const string DESCRIPTOR_DIR = FEATURES2D_DIR + "/descriptor_extractors";
const string IMAGE_FILENAME = "tsukuba.png"; const string IMAGE_FILENAME = "tsukuba.png";
#if defined(HAVE_OPENCV_OCL) && 0 // unblock this to see SURF_OCL tests failures
static Ptr<Feature2D> getSURF()
{
ocl::PlatformsInfo p;
if(ocl::getOpenCLPlatforms(p) > 0)
return new ocl::SURF_OCL;
else
return new SURF;
}
#else
static Ptr<Feature2D> getSURF()
{
return new SURF;
}
#endif
/****************************************************************************************\ /****************************************************************************************\
* Regression tests for feature detectors comparing keypoints. * * Regression tests for feature detectors comparing keypoints. *
\****************************************************************************************/ \****************************************************************************************/
...@@ -978,7 +994,7 @@ TEST( Features2d_Detector_SIFT, regression ) ...@@ -978,7 +994,7 @@ TEST( Features2d_Detector_SIFT, regression )
TEST( Features2d_Detector_SURF, regression ) TEST( Features2d_Detector_SURF, regression )
{ {
CV_FeatureDetectorTest test( "detector-surf", FeatureDetector::create("SURF") ); CV_FeatureDetectorTest test( "detector-surf", Ptr<FeatureDetector>(getSURF()) );
test.safe_run(); test.safe_run();
} }
...@@ -995,7 +1011,7 @@ TEST( Features2d_DescriptorExtractor_SIFT, regression ) ...@@ -995,7 +1011,7 @@ TEST( Features2d_DescriptorExtractor_SIFT, regression )
TEST( Features2d_DescriptorExtractor_SURF, regression ) TEST( Features2d_DescriptorExtractor_SURF, regression )
{ {
CV_DescriptorExtractorTest<L2<float> > test( "descriptor-surf", 0.05f, CV_DescriptorExtractorTest<L2<float> > test( "descriptor-surf", 0.05f,
DescriptorExtractor::create("SURF") ); Ptr<DescriptorExtractor>(getSURF()) );
test.safe_run(); test.safe_run();
} }
...@@ -1036,10 +1052,10 @@ TEST(Features2d_BruteForceDescriptorMatcher_knnMatch, regression) ...@@ -1036,10 +1052,10 @@ TEST(Features2d_BruteForceDescriptorMatcher_knnMatch, regression)
const int sz = 100; const int sz = 100;
const int k = 3; const int k = 3;
Ptr<DescriptorExtractor> ext = DescriptorExtractor::create("SURF"); Ptr<DescriptorExtractor> ext = Ptr<DescriptorExtractor>(getSURF());
ASSERT_TRUE(ext != NULL); ASSERT_TRUE(ext != NULL);
Ptr<FeatureDetector> det = FeatureDetector::create("SURF"); Ptr<FeatureDetector> det = Ptr<FeatureDetector>(getSURF());
//"%YAML:1.0\nhessianThreshold: 8000.\noctaves: 3\noctaveLayers: 4\nupright: 0\n" //"%YAML:1.0\nhessianThreshold: 8000.\noctaves: 3\noctaveLayers: 4\nupright: 0\n"
ASSERT_TRUE(det != NULL); ASSERT_TRUE(det != NULL);
...@@ -1096,7 +1112,11 @@ public: ...@@ -1096,7 +1112,11 @@ public:
protected: protected:
void run(int) void run(int)
{ {
Ptr<Feature2D> f = Algorithm::create<Feature2D>("Feature2D." + fname); Ptr<Feature2D> f;
if(fname == "SURF")
f = getSURF();
else
f = Algorithm::create<Feature2D>("Feature2D." + fname);
if(f.empty()) if(f.empty())
return; return;
string path = string(ts->get_data_path()) + "detectors_descriptors_evaluation/planar/"; string path = string(ts->get_data_path()) + "detectors_descriptors_evaluation/planar/";
......
...@@ -48,6 +48,12 @@ using namespace cv; ...@@ -48,6 +48,12 @@ using namespace cv;
const string IMAGE_TSUKUBA = "/features2d/tsukuba.png"; const string IMAGE_TSUKUBA = "/features2d/tsukuba.png";
const string IMAGE_BIKES = "/detectors_descriptors_evaluation/images_datasets/bikes/img1.png"; const string IMAGE_BIKES = "/detectors_descriptors_evaluation/images_datasets/bikes/img1.png";
#if defined(HAVE_OPENCV_OCL) && 0 // unblock this to see SURF_OCL tests failures
#define SURF_NAME "Feature2D.SURF_OCL"
#else
#define SURF_NAME "Feature2D.SURF"
#endif
#define SHOW_DEBUG_LOG 0 #define SHOW_DEBUG_LOG 0
static static
...@@ -615,7 +621,7 @@ protected: ...@@ -615,7 +621,7 @@ protected:
*/ */
TEST(Features2d_RotationInvariance_Detector_SURF, regression) TEST(Features2d_RotationInvariance_Detector_SURF, regression)
{ {
DetectorRotationInvarianceTest test(Algorithm::create<FeatureDetector>("Feature2D.SURF"), DetectorRotationInvarianceTest test(Algorithm::create<FeatureDetector>(SURF_NAME),
0.44f, 0.44f,
0.76f); 0.76f);
test.safe_run(); test.safe_run();
...@@ -634,8 +640,8 @@ TEST(Features2d_RotationInvariance_Detector_SIFT, DISABLED_regression) ...@@ -634,8 +640,8 @@ TEST(Features2d_RotationInvariance_Detector_SIFT, DISABLED_regression)
*/ */
TEST(Features2d_RotationInvariance_Descriptor_SURF, regression) TEST(Features2d_RotationInvariance_Descriptor_SURF, regression)
{ {
DescriptorRotationInvarianceTest test(Algorithm::create<FeatureDetector>("Feature2D.SURF"), DescriptorRotationInvarianceTest test(Algorithm::create<FeatureDetector>(SURF_NAME),
Algorithm::create<DescriptorExtractor>("Feature2D.SURF"), Algorithm::create<DescriptorExtractor>(SURF_NAME),
NORM_L1, NORM_L1,
0.83f); 0.83f);
test.safe_run(); test.safe_run();
...@@ -655,7 +661,7 @@ TEST(Features2d_RotationInvariance_Descriptor_SIFT, regression) ...@@ -655,7 +661,7 @@ TEST(Features2d_RotationInvariance_Descriptor_SIFT, regression)
*/ */
TEST(Features2d_ScaleInvariance_Detector_SURF, regression) TEST(Features2d_ScaleInvariance_Detector_SURF, regression)
{ {
DetectorScaleInvarianceTest test(Algorithm::create<FeatureDetector>("Feature2D.SURF"), DetectorScaleInvarianceTest test(Algorithm::create<FeatureDetector>(SURF_NAME),
0.64f, 0.64f,
0.84f); 0.84f);
test.safe_run(); test.safe_run();
...@@ -674,8 +680,8 @@ TEST(Features2d_ScaleInvariance_Detector_SIFT, regression) ...@@ -674,8 +680,8 @@ TEST(Features2d_ScaleInvariance_Detector_SIFT, regression)
*/ */
TEST(Features2d_ScaleInvariance_Descriptor_SURF, regression) TEST(Features2d_ScaleInvariance_Descriptor_SURF, regression)
{ {
DescriptorScaleInvarianceTest test(Algorithm::create<FeatureDetector>("Feature2D.SURF"), DescriptorScaleInvarianceTest test(Algorithm::create<FeatureDetector>(SURF_NAME),
Algorithm::create<DescriptorExtractor>("Feature2D.SURF"), Algorithm::create<DescriptorExtractor>(SURF_NAME),
NORM_L1, NORM_L1,
0.61f); 0.61f);
test.safe_run(); test.safe_run();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment