fixed #2580, #2210. some work on #2025.

modified SIFT to 1) double image before finding keypoints, 2) use floating-point internally instead of 16-bit integers, 3) set the keypoint response to the abs(interpolated_DoG_value). step 1) increases the number of detected keypoints significantly and together with 2) and 3) it improves some detection benchmarks. On the other hand, the stability of the small keypoints is lower, so the rotation and scale invariance tests now struggle a bit. In 2.5 need to make this feature optional and add some more intelligence to the algorithm.

added test that finds a planar object using SIFT.
pull/360/head
Vadim Pisarevsky 12 years ago
parent ab8d92e1b8
commit c69312ea0d
  1. 2
      modules/nonfree/CMakeLists.txt
  2. 183
      modules/nonfree/src/sift.cpp
  3. 58
      modules/nonfree/test/test_features2d.cpp
  4. 27
      modules/nonfree/test/test_rotation_and_scale_invariance.cpp
  5. 2
      samples/cpp/descriptor_extractor_matcher.cpp

@ -3,4 +3,4 @@ if(BUILD_ANDROID_PACKAGE)
endif()
set(the_description "Functionality with possible limitations on the use")
ocv_define_module(nonfree opencv_imgproc opencv_features2d)
ocv_define_module(nonfree opencv_imgproc opencv_features2d opencv_calib3d)

@ -162,8 +162,24 @@ static const float SIFT_DESCR_MAG_THR = 0.2f;
// factor used to convert floating-point descriptor to unsigned char
static const float SIFT_INT_DESCR_FCTR = 512.f;
#if 0
// intermediate type used for DoG pyramids
typedef short sift_wt;
static const int SIFT_FIXPT_SCALE = 48;
#else
// intermediate type used for DoG pyramids
typedef float sift_wt;
static const int SIFT_FIXPT_SCALE = 1;
#endif
static inline void
unpackOctave(const KeyPoint& kpt, int& octave, int& layer, float& scale)
{
octave = kpt.octave & 255;
layer = (kpt.octave >> 8) & 255;
octave = octave < 128 ? octave : (-128 | octave);
scale = octave >= 0 ? 1.f/(1 << octave) : (float)(1 << -octave);
}
static Mat createInitialImage( const Mat& img, bool doubleImageSize, float sigma )
{
@ -172,7 +188,7 @@ static Mat createInitialImage( const Mat& img, bool doubleImageSize, float sigma
cvtColor(img, gray, COLOR_BGR2GRAY);
else
img.copyTo(gray);
gray.convertTo(gray_fpt, CV_16S, SIFT_FIXPT_SCALE, 0);
gray.convertTo(gray_fpt, DataType<sift_wt>::type, SIFT_FIXPT_SCALE, 0);
float sig_diff;
@ -245,7 +261,7 @@ void SIFT::buildDoGPyramid( const vector<Mat>& gpyr, vector<Mat>& dogpyr ) const
const Mat& src1 = gpyr[o*(nOctaveLayers + 3) + i];
const Mat& src2 = gpyr[o*(nOctaveLayers + 3) + i + 1];
Mat& dst = dogpyr[o*(nOctaveLayers + 2) + i];
subtract(src2, src1, dst, noArray(), CV_16S);
subtract(src2, src1, dst, noArray(), DataType<sift_wt>::type);
}
}
}
@ -276,8 +292,8 @@ static float calcOrientationHist( const Mat& img, Point pt, int radius,
if( x <= 0 || x >= img.cols - 1 )
continue;
float dx = (float)(img.at<short>(y, x+1) - img.at<short>(y, x-1));
float dy = (float)(img.at<short>(y-1, x) - img.at<short>(y+1, x));
float dx = (float)(img.at<sift_wt>(y, x+1) - img.at<sift_wt>(y, x-1));
float dy = (float)(img.at<sift_wt>(y-1, x) - img.at<sift_wt>(y+1, x));
X[k] = dx; Y[k] = dy; W[k] = (i*i + j*j)*expf_scale;
k++;
@ -323,7 +339,7 @@ static float calcOrientationHist( const Mat& img, Point pt, int radius,
//
// Interpolates a scale-space extremum's location and scale to subpixel
// accuracy to form an image feature. Rejects features with low contrast.
// accuracy to form an image feature. Rejects features with low contrast.
// Based on Section 4 of Lowe's paper.
static bool adjustLocalExtrema( const vector<Mat>& dog_pyr, KeyPoint& kpt, int octv,
int& layer, int& r, int& c, int nOctaveLayers,
@ -334,7 +350,7 @@ static bool adjustLocalExtrema( const vector<Mat>& dog_pyr, KeyPoint& kpt, int o
const float second_deriv_scale = img_scale;
const float cross_deriv_scale = img_scale*0.25f;
float xi=0, xr=0, xc=0, contr;
float xi=0, xr=0, xc=0, contr=0;
int i = 0;
for( ; i < SIFT_MAX_INTERP_STEPS; i++ )
@ -344,20 +360,20 @@ static bool adjustLocalExtrema( const vector<Mat>& dog_pyr, KeyPoint& kpt, int o
const Mat& prev = dog_pyr[idx-1];
const Mat& next = dog_pyr[idx+1];
Vec3f dD((img.at<short>(r, c+1) - img.at<short>(r, c-1))*deriv_scale,
(img.at<short>(r+1, c) - img.at<short>(r-1, c))*deriv_scale,
(next.at<short>(r, c) - prev.at<short>(r, c))*deriv_scale);
float v2 = (float)img.at<short>(r, c)*2;
float dxx = (img.at<short>(r, c+1) + img.at<short>(r, c-1) - v2)*second_deriv_scale;
float dyy = (img.at<short>(r+1, c) + img.at<short>(r-1, c) - v2)*second_deriv_scale;
float dss = (next.at<short>(r, c) + prev.at<short>(r, c) - v2)*second_deriv_scale;
float dxy = (img.at<short>(r+1, c+1) - img.at<short>(r+1, c-1) -
img.at<short>(r-1, c+1) + img.at<short>(r-1, c-1))*cross_deriv_scale;
float dxs = (next.at<short>(r, c+1) - next.at<short>(r, c-1) -
prev.at<short>(r, c+1) + prev.at<short>(r, c-1))*cross_deriv_scale;
float dys = (next.at<short>(r+1, c) - next.at<short>(r-1, c) -
prev.at<short>(r+1, c) + prev.at<short>(r-1, c))*cross_deriv_scale;
Vec3f dD((img.at<sift_wt>(r, c+1) - img.at<sift_wt>(r, c-1))*deriv_scale,
(img.at<sift_wt>(r+1, c) - img.at<sift_wt>(r-1, c))*deriv_scale,
(next.at<sift_wt>(r, c) - prev.at<sift_wt>(r, c))*deriv_scale);
float v2 = (float)img.at<sift_wt>(r, c)*2;
float dxx = (img.at<sift_wt>(r, c+1) + img.at<sift_wt>(r, c-1) - v2)*second_deriv_scale;
float dyy = (img.at<sift_wt>(r+1, c) + img.at<sift_wt>(r-1, c) - v2)*second_deriv_scale;
float dss = (next.at<sift_wt>(r, c) + prev.at<sift_wt>(r, c) - v2)*second_deriv_scale;
float dxy = (img.at<sift_wt>(r+1, c+1) - img.at<sift_wt>(r+1, c-1) -
img.at<sift_wt>(r-1, c+1) + img.at<sift_wt>(r-1, c-1))*cross_deriv_scale;
float dxs = (next.at<sift_wt>(r, c+1) - next.at<sift_wt>(r, c-1) -
prev.at<sift_wt>(r, c+1) + prev.at<sift_wt>(r, c-1))*cross_deriv_scale;
float dys = (next.at<sift_wt>(r+1, c) - next.at<sift_wt>(r-1, c) -
prev.at<sift_wt>(r+1, c) + prev.at<sift_wt>(r-1, c))*cross_deriv_scale;
Matx33f H(dxx, dxy, dxs,
dxy, dyy, dys,
@ -369,20 +385,25 @@ static bool adjustLocalExtrema( const vector<Mat>& dog_pyr, KeyPoint& kpt, int o
xr = -X[1];
xc = -X[0];
if( std::abs( xi ) < 0.5f && std::abs( xr ) < 0.5f && std::abs( xc ) < 0.5f )
if( std::abs(xi) < 0.5f && std::abs(xr) < 0.5f && std::abs(xc) < 0.5f )
break;
c += cvRound( xc );
r += cvRound( xr );
layer += cvRound( xi );
if( std::abs(xi) > (float)(INT_MAX/3) ||
std::abs(xr) > (float)(INT_MAX/3) ||
std::abs(xc) > (float)(INT_MAX/3) )
return false;
c += cvRound(xc);
r += cvRound(xr);
layer += cvRound(xi);
if( layer < 1 || layer > nOctaveLayers ||
c < SIFT_IMG_BORDER || c >= img.cols - SIFT_IMG_BORDER ||
r < SIFT_IMG_BORDER || r >= img.rows - SIFT_IMG_BORDER )
c < SIFT_IMG_BORDER || c >= img.cols - SIFT_IMG_BORDER ||
r < SIFT_IMG_BORDER || r >= img.rows - SIFT_IMG_BORDER )
return false;
}
/* ensure convergence of interpolation */
// ensure convergence of interpolation
if( i >= SIFT_MAX_INTERP_STEPS )
return false;
@ -391,21 +412,21 @@ static bool adjustLocalExtrema( const vector<Mat>& dog_pyr, KeyPoint& kpt, int o
const Mat& img = dog_pyr[idx];
const Mat& prev = dog_pyr[idx-1];
const Mat& next = dog_pyr[idx+1];
Matx31f dD((img.at<short>(r, c+1) - img.at<short>(r, c-1))*deriv_scale,
(img.at<short>(r+1, c) - img.at<short>(r-1, c))*deriv_scale,
(next.at<short>(r, c) - prev.at<short>(r, c))*deriv_scale);
Matx31f dD((img.at<sift_wt>(r, c+1) - img.at<sift_wt>(r, c-1))*deriv_scale,
(img.at<sift_wt>(r+1, c) - img.at<sift_wt>(r-1, c))*deriv_scale,
(next.at<sift_wt>(r, c) - prev.at<sift_wt>(r, c))*deriv_scale);
float t = dD.dot(Matx31f(xc, xr, xi));
contr = img.at<short>(r, c)*img_scale + t * 0.5f;
contr = img.at<sift_wt>(r, c)*img_scale + t * 0.5f;
if( std::abs( contr ) * nOctaveLayers < contrastThreshold )
return false;
/* principal curvatures are computed using the trace and det of Hessian */
float v2 = img.at<short>(r, c)*2.f;
float dxx = (img.at<short>(r, c+1) + img.at<short>(r, c-1) - v2)*second_deriv_scale;
float dyy = (img.at<short>(r+1, c) + img.at<short>(r-1, c) - v2)*second_deriv_scale;
float dxy = (img.at<short>(r+1, c+1) - img.at<short>(r+1, c-1) -
img.at<short>(r-1, c+1) + img.at<short>(r-1, c-1)) * cross_deriv_scale;
// principal curvatures are computed using the trace and det of Hessian
float v2 = img.at<sift_wt>(r, c)*2.f;
float dxx = (img.at<sift_wt>(r, c+1) + img.at<sift_wt>(r, c-1) - v2)*second_deriv_scale;
float dyy = (img.at<sift_wt>(r+1, c) + img.at<sift_wt>(r-1, c) - v2)*second_deriv_scale;
float dxy = (img.at<sift_wt>(r+1, c+1) - img.at<sift_wt>(r+1, c-1) -
img.at<sift_wt>(r-1, c+1) + img.at<sift_wt>(r-1, c-1)) * cross_deriv_scale;
float tr = dxx + dyy;
float det = dxx * dyy - dxy * dxy;
@ -417,6 +438,7 @@ static bool adjustLocalExtrema( const vector<Mat>& dog_pyr, KeyPoint& kpt, int o
kpt.pt.y = (r + xr) * (1 << octv);
kpt.octave = octv + (layer << 8) + (cvRound((xi + 0.5)*255) << 16);
kpt.size = sigma*powf(2.f, (layer + xi) / nOctaveLayers)*(1 << octv)*2;
kpt.response = std::abs(contr);
return true;
}
@ -448,13 +470,13 @@ void SIFT::findScaleSpaceExtrema( const vector<Mat>& gauss_pyr, const vector<Mat
for( int r = SIFT_IMG_BORDER; r < rows-SIFT_IMG_BORDER; r++)
{
const short* currptr = img.ptr<short>(r);
const short* prevptr = prev.ptr<short>(r);
const short* nextptr = next.ptr<short>(r);
const sift_wt* currptr = img.ptr<sift_wt>(r);
const sift_wt* prevptr = prev.ptr<sift_wt>(r);
const sift_wt* nextptr = next.ptr<sift_wt>(r);
for( int c = SIFT_IMG_BORDER; c < cols-SIFT_IMG_BORDER; c++)
{
int val = currptr[c];
sift_wt val = currptr[c];
// find local extrema with pixel accuracy
if( std::abs(val) > threshold &&
@ -541,11 +563,9 @@ static void calcSIFTDescriptor( const Mat& img, Point2f ptf, float ori, float sc
for( i = -radius, k = 0; i <= radius; i++ )
for( j = -radius; j <= radius; j++ )
{
/*
Calculate sample's histogram array coords rotated relative to ori.
Subtract 0.5 so samples that fall e.g. in the center of row 1 (i.e.
r_rot = 1.5) have full weight placed in row 1 after interpolation.
*/
// Calculate sample's histogram array coords rotated relative to ori.
// Subtract 0.5 so samples that fall e.g. in the center of row 1 (i.e.
// r_rot = 1.5) have full weight placed in row 1 after interpolation.
float c_rot = j * cos_t - i * sin_t;
float r_rot = j * sin_t + i * cos_t;
float rbin = r_rot + d/2 - 0.5f;
@ -553,10 +573,10 @@ static void calcSIFTDescriptor( const Mat& img, Point2f ptf, float ori, float sc
int r = pt.y + i, c = pt.x + j;
if( rbin > -1 && rbin < d && cbin > -1 && cbin < d &&
r > 0 && r < rows - 1 && c > 0 && c < cols - 1 )
r > 0 && r < rows - 1 && c > 0 && c < cols - 1 )
{
float dx = (float)(img.at<short>(r, c+1) - img.at<short>(r, c-1));
float dy = (float)(img.at<short>(r-1, c) - img.at<short>(r+1, c));
float dx = (float)(img.at<sift_wt>(r, c+1) - img.at<sift_wt>(r, c-1));
float dy = (float)(img.at<sift_wt>(r-1, c) - img.at<sift_wt>(r+1, c));
X[k] = dx; Y[k] = dy; RBin[k] = rbin; CBin[k] = cbin;
W[k] = (c_rot * c_rot + r_rot * r_rot)*exp_scale;
k++;
@ -632,29 +652,46 @@ static void calcSIFTDescriptor( const Mat& img, Point2f ptf, float ori, float sc
nrm2 += val*val;
}
nrm2 = SIFT_INT_DESCR_FCTR/std::max(std::sqrt(nrm2), FLT_EPSILON);
#if 1
for( k = 0; k < len; k++ )
{
dst[k] = saturate_cast<uchar>(dst[k]*nrm2);
}
#else
float nrm1 = 0;
for( k = 0; k < len; k++ )
{
dst[k] *= nrm2;
nrm1 += dst[k];
}
nrm1 = 1.f/std::max(nrm1, FLT_EPSILON);
for( k = 0; k < len; k++ )
{
dst[k] = std::sqrt(dst[k] * nrm1);//saturate_cast<uchar>(std::sqrt(dst[k] * nrm1)*SIFT_INT_DESCR_FCTR);
}
#endif
}
static void calcDescriptors(const vector<Mat>& gpyr, const vector<KeyPoint>& keypoints,
Mat& descriptors, int nOctaveLayers )
Mat& descriptors, int nOctaveLayers, int firstOctave )
{
int d = SIFT_DESCR_WIDTH, n = SIFT_DESCR_HIST_BINS;
for( size_t i = 0; i < keypoints.size(); i++ )
{
KeyPoint kpt = keypoints[i];
int octv=kpt.octave & 255, layer=(kpt.octave >> 8) & 255;
float scale = 1.f/(1 << octv);
int octave, layer;
float scale;
unpackOctave(kpt, octave, layer, scale);
CV_Assert(octave >= firstOctave && layer <= nOctaveLayers+2);
float size=kpt.size*scale;
Point2f ptf(kpt.pt.x*scale, kpt.pt.y*scale);
const Mat& img = gpyr[octv*(nOctaveLayers + 3) + layer];
const Mat& img = gpyr[(octave - firstOctave)*(nOctaveLayers + 3) + layer];
float angle = 360.f - kpt.angle;
if(std::abs(angle - 360.f) < FLT_EPSILON)
angle = 0.f;
angle = 0.f;
calcSIFTDescriptor(img, ptf, angle, size*0.5f, d, n, descriptors.ptr<float>((int)i));
}
}
@ -691,6 +728,7 @@ void SIFT::operator()(InputArray _image, InputArray _mask,
OutputArray _descriptors,
bool useProvidedKeypoints) const
{
int firstOctave = -1, actualNOctaves = 0, actualNLayers = 0;
Mat image = _image.getMat(), mask = _mask.getMat();
if( image.empty() || image.depth() != CV_8U )
@ -699,9 +737,28 @@ void SIFT::operator()(InputArray _image, InputArray _mask,
if( !mask.empty() && mask.type() != CV_8UC1 )
CV_Error( CV_StsBadArg, "mask has incorrect type (!=CV_8UC1)" );
Mat base = createInitialImage(image, false, (float)sigma);
if( useProvidedKeypoints )
{
firstOctave = 0;
int maxOctave = INT_MIN;
for( size_t i = 0; i < keypoints.size(); i++ )
{
int octave, layer;
float scale;
unpackOctave(keypoints[i], octave, layer, scale);
firstOctave = std::min(firstOctave, octave);
maxOctave = std::max(maxOctave, octave);
actualNLayers = std::max(actualNLayers, layer-2);
}
firstOctave = std::min(firstOctave, 0);
CV_Assert( firstOctave >= -1 && actualNLayers <= nOctaveLayers );
actualNOctaves = maxOctave - firstOctave + 1;
}
Mat base = createInitialImage(image, firstOctave < 0, (float)sigma);
vector<Mat> gpyr, dogpyr;
int nOctaves = cvRound(log( (double)std::min( base.cols, base.rows ) ) / log(2.) - 2);
int nOctaves = actualNOctaves > 0 ? actualNOctaves : cvRound(log( (double)std::min( base.cols, base.rows ) ) / log(2.) - 2) - firstOctave;
//double t, tf = getTickFrequency();
//t = (double)getTickCount();
@ -724,6 +781,16 @@ void SIFT::operator()(InputArray _image, InputArray _mask,
KeyPointsFilter::retainBest(keypoints, nfeatures);
//t = (double)getTickCount() - t;
//printf("keypoint detection time: %g\n", t*1000./tf);
if( firstOctave < 0 )
for( size_t i = 0; i < keypoints.size(); i++ )
{
KeyPoint& kpt = keypoints[i];
float scale = 1.f/(float)(1 << -firstOctave);
kpt.octave = (kpt.octave & ~255) | ((kpt.octave + firstOctave) & 255);
kpt.pt *= scale;
kpt.size *= scale;
}
}
else
{
@ -738,7 +805,7 @@ void SIFT::operator()(InputArray _image, InputArray _mask,
_descriptors.create((int)keypoints.size(), dsize, CV_32F);
Mat descriptors = _descriptors.getMat();
calcDescriptors(gpyr, keypoints, descriptors, nOctaveLayers);
calcDescriptors(gpyr, keypoints, descriptors, nOctaveLayers, firstOctave);
//t = (double)getTickCount() - t;
//printf("descriptor extraction time: %g\n", t*1000./tf);
}

@ -40,6 +40,7 @@
//M*/
#include "test_precomp.hpp"
#include "opencv2/calib3d/calib3d.hpp"
using namespace std;
using namespace cv;
@ -1085,4 +1086,59 @@ TEST(Features2d_BruteForceDescriptorMatcher_knnMatch, regression)
Ptr<DescriptorExtractor> s = DescriptorExtractor::create("SURF");
ASSERT_STREQ(s->paramHelp("extended").c_str(), "");
}
*/
*/
class CV_DetectPlanarTest : public cvtest::BaseTest
{
public:
CV_DetectPlanarTest(const string& _fname, int _min_ninliers) : fname(_fname), min_ninliers(_min_ninliers) {}
protected:
void run(int)
{
Ptr<Feature2D> f = Algorithm::create<Feature2D>("Feature2D." + fname);
if(f.empty())
return;
string path = string(ts->get_data_path()) + "detectors_descriptors_evaluation/planar/";
string imgname1 = path + "box.png";
string imgname2 = path + "box_in_scene.png";
Mat img1 = imread(imgname1, 0);
Mat img2 = imread(imgname2, 0);
if( img1.empty() || img2.empty() )
{
ts->printf( cvtest::TS::LOG, "missing %s and/or %s\n", imgname1.c_str(), imgname2.c_str());
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
return;
}
vector<KeyPoint> kpt1, kpt2;
Mat d1, d2;
f->operator()(img1, Mat(), kpt1, d1);
f->operator()(img1, Mat(), kpt2, d2);
vector<DMatch> matches;
BFMatcher(NORM_L2, true).match(d1, d2, matches);
vector<Point2f> pt1, pt2;
for( size_t i = 0; i < matches.size(); i++ ) {
pt1.push_back(kpt1[matches[i].queryIdx].pt);
pt2.push_back(kpt2[matches[i].trainIdx].pt);
}
Mat inliers, H = findHomography(pt1, pt2, RANSAC, 10, inliers);
int ninliers = countNonZero(inliers);
if( ninliers < min_ninliers )
{
ts->printf( cvtest::TS::LOG, "too little inliers (%d) vs expected %d\n", ninliers, min_ninliers);
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
return;
}
}
string fname;
int min_ninliers;
};
TEST(Features2d_SIFTHomographyTest, regression) { CV_DetectPlanarTest test("SIFT", 80); test.safe_run(); }
//TEST(Features2d_SURFHomographyTest, regression) { CV_DetectPlanarTest test("SURF", 80); test.safe_run(); }

@ -186,6 +186,20 @@ void matchKeyPoints(const vector<KeyPoint>& keypoints0, const Mat& H,
}
}
static void removeVerySmallKeypoints(vector<KeyPoint>& keypoints)
{
size_t i, j = 0, n = keypoints.size();
for( i = 0; i < n; i++ )
{
if( (keypoints[i].octave & 128) != 0 )
;
else
keypoints[j++] = keypoints[i];
}
keypoints.resize(j);
}
class DetectorRotationInvarianceTest : public cvtest::BaseTest
{
public:
@ -216,6 +230,7 @@ protected:
vector<KeyPoint> keypoints0;
featureDetector->detect(image0, keypoints0);
removeVerySmallKeypoints(keypoints0);
if(keypoints0.size() < 15)
CV_Error(CV_StsAssert, "Detector gives too few points in a test image\n");
@ -226,6 +241,7 @@ protected:
vector<KeyPoint> keypoints1;
featureDetector->detect(image1, keypoints1, mask1);
removeVerySmallKeypoints(keypoints1);
vector<DMatch> matches;
matchKeyPoints(keypoints0, H, keypoints1, matches);
@ -329,6 +345,7 @@ protected:
vector<KeyPoint> keypoints0;
Mat descriptors0;
featureDetector->detect(image0, keypoints0);
removeVerySmallKeypoints(keypoints0);
if(keypoints0.size() < 15)
CV_Error(CV_StsAssert, "Detector gives too few points in a test image\n");
descriptorExtractor->compute(image0, keypoints0, descriptors0);
@ -382,6 +399,7 @@ protected:
float minDescInliersRatio;
};
class DetectorScaleInvarianceTest : public cvtest::BaseTest
{
public:
@ -412,6 +430,7 @@ protected:
vector<KeyPoint> keypoints0;
featureDetector->detect(image0, keypoints0);
removeVerySmallKeypoints(keypoints0);
if(keypoints0.size() < 15)
CV_Error(CV_StsAssert, "Detector gives too few points in a test image\n");
@ -423,6 +442,7 @@ protected:
vector<KeyPoint> keypoints1, osiKeypoints1; // osi - original size image
featureDetector->detect(image1, keypoints1);
removeVerySmallKeypoints(keypoints1);
if(keypoints1.size() < 15)
CV_Error(CV_StsAssert, "Detector gives too few points in a test image\n");
@ -531,6 +551,7 @@ protected:
vector<KeyPoint> keypoints0;
featureDetector->detect(image0, keypoints0);
removeVerySmallKeypoints(keypoints0);
if(keypoints0.size() < 15)
CV_Error(CV_StsAssert, "Detector gives too few points in a test image\n");
Mat descriptors0;
@ -603,8 +624,8 @@ TEST(Features2d_RotationInvariance_Detector_SURF, regression)
TEST(Features2d_RotationInvariance_Detector_SIFT, regression)
{
DetectorRotationInvarianceTest test(Algorithm::create<FeatureDetector>("Feature2D.SIFT"),
0.75f,
0.76f);
0.45f,
0.70f);
test.safe_run();
}
@ -665,7 +686,7 @@ TEST(Features2d_ScaleInvariance_Descriptor_SIFT, regression)
DescriptorScaleInvarianceTest test(Algorithm::create<FeatureDetector>("Feature2D.SIFT"),
Algorithm::create<DescriptorExtractor>("Feature2D.SIFT"),
NORM_L1,
0.87f);
0.78f);
test.safe_run();
}

@ -221,6 +221,8 @@ static void doIteration( const Mat& img1, Mat& img2, bool isWarpPerspective,
drawMatches( img1, keypoints1, img2, keypoints2, filteredMatches, drawImg, CV_RGB(0, 0, 255), CV_RGB(255, 0, 0), matchesMask,
DrawMatchesFlags::DRAW_OVER_OUTIMG | DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
#endif
printf("Number of inliers: %d\n", countNonZero(matchesMask));
}
else
drawMatches( img1, keypoints1, img2, keypoints2, filteredMatches, drawImg );

Loading…
Cancel
Save