Skip to content

Commit 40b1dc1

Browse files
committed
Merge pull request opencv#12464 from alalek:fix_contrib_1754
2 parents 8eba3c1 + b50c70b commit 40b1dc1

8 files changed

+918
-922
lines changed

modules/features2d/test/test_descriptors_invariance.cpp

Lines changed: 3 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -5,163 +5,13 @@
55
#include "test_precomp.hpp"
66
#include "test_invariance_utils.hpp"
77

8-
namespace opencv_test { namespace {
8+
#include "test_descriptors_invariance.impl.hpp"
99

10-
#define SHOW_DEBUG_LOG 1
10+
namespace opencv_test { namespace {
1111

12-
typedef tuple<std::string, Ptr<FeatureDetector>, Ptr<DescriptorExtractor>, float>
13-
String_FeatureDetector_DescriptorExtractor_Float_t;
1412
const static std::string IMAGE_TSUKUBA = "features2d/tsukuba.png";
1513
const static std::string IMAGE_BIKES = "detectors_descriptors_evaluation/images_datasets/bikes/img1.png";
16-
#define Value(...) Values(String_FeatureDetector_DescriptorExtractor_Float_t(__VA_ARGS__))
17-
18-
static
19-
void rotateKeyPoints(const vector<KeyPoint>& src, const Mat& H, float angle, vector<KeyPoint>& dst)
20-
{
21-
// suppose that H is rotation given from rotateImage() and angle has value passed to rotateImage()
22-
vector<Point2f> srcCenters, dstCenters;
23-
KeyPoint::convert(src, srcCenters);
24-
25-
perspectiveTransform(srcCenters, dstCenters, H);
26-
27-
dst = src;
28-
for(size_t i = 0; i < dst.size(); i++)
29-
{
30-
dst[i].pt = dstCenters[i];
31-
float dstAngle = src[i].angle + angle;
32-
if(dstAngle >= 360.f)
33-
dstAngle -= 360.f;
34-
dst[i].angle = dstAngle;
35-
}
36-
}
37-
38-
class DescriptorInvariance : public TestWithParam<String_FeatureDetector_DescriptorExtractor_Float_t>
39-
{
40-
protected:
41-
virtual void SetUp() {
42-
// Read test data
43-
const std::string filename = cvtest::TS::ptr()->get_data_path() + get<0>(GetParam());
44-
image0 = imread(filename);
45-
ASSERT_FALSE(image0.empty()) << "couldn't read input image";
46-
47-
featureDetector = get<1>(GetParam());
48-
descriptorExtractor = get<2>(GetParam());
49-
minInliersRatio = get<3>(GetParam());
50-
}
51-
52-
Ptr<FeatureDetector> featureDetector;
53-
Ptr<DescriptorExtractor> descriptorExtractor;
54-
float minInliersRatio;
55-
Mat image0;
56-
};
57-
58-
typedef DescriptorInvariance DescriptorScaleInvariance;
59-
typedef DescriptorInvariance DescriptorRotationInvariance;
60-
61-
TEST_P(DescriptorRotationInvariance, rotation)
62-
{
63-
Mat image1, mask1;
64-
const int borderSize = 16;
65-
Mat mask0(image0.size(), CV_8UC1, Scalar(0));
66-
mask0(Rect(borderSize, borderSize, mask0.cols - 2*borderSize, mask0.rows - 2*borderSize)).setTo(Scalar(255));
67-
68-
vector<KeyPoint> keypoints0;
69-
Mat descriptors0;
70-
featureDetector->detect(image0, keypoints0, mask0);
71-
std::cout << "Keypoints: " << keypoints0.size() << std::endl;
72-
EXPECT_GE(keypoints0.size(), 15u);
73-
descriptorExtractor->compute(image0, keypoints0, descriptors0);
74-
75-
BFMatcher bfmatcher(descriptorExtractor->defaultNorm());
76-
77-
const float minIntersectRatio = 0.5f;
78-
const int maxAngle = 360, angleStep = 15;
79-
for(int angle = 0; angle < maxAngle; angle += angleStep)
80-
{
81-
Mat H = rotateImage(image0, mask0, static_cast<float>(angle), image1, mask1);
82-
83-
vector<KeyPoint> keypoints1;
84-
rotateKeyPoints(keypoints0, H, static_cast<float>(angle), keypoints1);
85-
Mat descriptors1;
86-
descriptorExtractor->compute(image1, keypoints1, descriptors1);
87-
88-
vector<DMatch> descMatches;
89-
bfmatcher.match(descriptors0, descriptors1, descMatches);
90-
91-
int descInliersCount = 0;
92-
for(size_t m = 0; m < descMatches.size(); m++)
93-
{
94-
const KeyPoint& transformed_p0 = keypoints1[descMatches[m].queryIdx];
95-
const KeyPoint& p1 = keypoints1[descMatches[m].trainIdx];
96-
if(calcIntersectRatio(transformed_p0.pt, 0.5f * transformed_p0.size,
97-
p1.pt, 0.5f * p1.size) >= minIntersectRatio)
98-
{
99-
descInliersCount++;
100-
}
101-
}
102-
103-
float descInliersRatio = static_cast<float>(descInliersCount) / keypoints0.size();
104-
EXPECT_GE(descInliersRatio, minInliersRatio);
105-
#if SHOW_DEBUG_LOG
106-
std::cout
107-
<< "angle = " << angle
108-
<< ", inliers = " << descInliersCount
109-
<< ", descInliersRatio = " << static_cast<float>(descInliersCount) / keypoints0.size()
110-
<< std::endl;
111-
#endif
112-
}
113-
}
114-
115-
116-
TEST_P(DescriptorScaleInvariance, scale)
117-
{
118-
vector<KeyPoint> keypoints0;
119-
featureDetector->detect(image0, keypoints0);
120-
std::cout << "Keypoints: " << keypoints0.size() << std::endl;
121-
EXPECT_GE(keypoints0.size(), 15u);
122-
Mat descriptors0;
123-
descriptorExtractor->compute(image0, keypoints0, descriptors0);
124-
125-
BFMatcher bfmatcher(descriptorExtractor->defaultNorm());
126-
for(int scaleIdx = 1; scaleIdx <= 3; scaleIdx++)
127-
{
128-
float scale = 1.f + scaleIdx * 0.5f;
129-
130-
Mat image1;
131-
resize(image0, image1, Size(), 1./scale, 1./scale, INTER_LINEAR_EXACT);
132-
133-
vector<KeyPoint> keypoints1;
134-
scaleKeyPoints(keypoints0, keypoints1, 1.0f/scale);
135-
Mat descriptors1;
136-
descriptorExtractor->compute(image1, keypoints1, descriptors1);
137-
138-
vector<DMatch> descMatches;
139-
bfmatcher.match(descriptors0, descriptors1, descMatches);
140-
141-
const float minIntersectRatio = 0.5f;
142-
int descInliersCount = 0;
143-
for(size_t m = 0; m < descMatches.size(); m++)
144-
{
145-
const KeyPoint& transformed_p0 = keypoints0[descMatches[m].queryIdx];
146-
const KeyPoint& p1 = keypoints0[descMatches[m].trainIdx];
147-
if(calcIntersectRatio(transformed_p0.pt, 0.5f * transformed_p0.size,
148-
p1.pt, 0.5f * p1.size) >= minIntersectRatio)
149-
{
150-
descInliersCount++;
151-
}
152-
}
153-
154-
float descInliersRatio = static_cast<float>(descInliersCount) / keypoints0.size();
155-
EXPECT_GE(descInliersRatio, minInliersRatio);
156-
#if SHOW_DEBUG_LOG
157-
std::cout
158-
<< "scale = " << scale
159-
<< ", inliers = " << descInliersCount
160-
<< ", descInliersRatio = " << static_cast<float>(descInliersCount) / keypoints0.size()
161-
<< std::endl;
162-
#endif
163-
}
164-
}
14+
#define Value(...) Values(make_tuple(__VA_ARGS__))
16515

16616
/*
16717
* Descriptors's rotation invariance check
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
// This file is part of OpenCV project.
2+
// It is subject to the license terms in the LICENSE file found in the top-level directory
3+
// of this distribution and at http://opencv.org/license.html
4+
5+
#include "test_invariance_utils.hpp"
6+
7+
namespace opencv_test { namespace {
8+
9+
#define SHOW_DEBUG_LOG 1
10+
11+
typedef tuple<std::string, Ptr<FeatureDetector>, Ptr<DescriptorExtractor>, float>
12+
String_FeatureDetector_DescriptorExtractor_Float_t;
13+
14+
15+
static
16+
void rotateKeyPoints(const vector<KeyPoint>& src, const Mat& H, float angle, vector<KeyPoint>& dst)
17+
{
18+
// suppose that H is rotation given from rotateImage() and angle has value passed to rotateImage()
19+
vector<Point2f> srcCenters, dstCenters;
20+
KeyPoint::convert(src, srcCenters);
21+
22+
perspectiveTransform(srcCenters, dstCenters, H);
23+
24+
dst = src;
25+
for(size_t i = 0; i < dst.size(); i++)
26+
{
27+
dst[i].pt = dstCenters[i];
28+
float dstAngle = src[i].angle + angle;
29+
if(dstAngle >= 360.f)
30+
dstAngle -= 360.f;
31+
dst[i].angle = dstAngle;
32+
}
33+
}
34+
35+
class DescriptorInvariance : public TestWithParam<String_FeatureDetector_DescriptorExtractor_Float_t>
36+
{
37+
protected:
38+
virtual void SetUp() {
39+
// Read test data
40+
const std::string filename = cvtest::TS::ptr()->get_data_path() + get<0>(GetParam());
41+
image0 = imread(filename);
42+
ASSERT_FALSE(image0.empty()) << "couldn't read input image";
43+
44+
featureDetector = get<1>(GetParam());
45+
descriptorExtractor = get<2>(GetParam());
46+
minInliersRatio = get<3>(GetParam());
47+
}
48+
49+
Ptr<FeatureDetector> featureDetector;
50+
Ptr<DescriptorExtractor> descriptorExtractor;
51+
float minInliersRatio;
52+
Mat image0;
53+
};
54+
55+
typedef DescriptorInvariance DescriptorScaleInvariance;
56+
typedef DescriptorInvariance DescriptorRotationInvariance;
57+
58+
TEST_P(DescriptorRotationInvariance, rotation)
59+
{
60+
Mat image1, mask1;
61+
const int borderSize = 16;
62+
Mat mask0(image0.size(), CV_8UC1, Scalar(0));
63+
mask0(Rect(borderSize, borderSize, mask0.cols - 2*borderSize, mask0.rows - 2*borderSize)).setTo(Scalar(255));
64+
65+
vector<KeyPoint> keypoints0;
66+
Mat descriptors0;
67+
featureDetector->detect(image0, keypoints0, mask0);
68+
std::cout << "Keypoints: " << keypoints0.size() << std::endl;
69+
EXPECT_GE(keypoints0.size(), 15u);
70+
descriptorExtractor->compute(image0, keypoints0, descriptors0);
71+
72+
BFMatcher bfmatcher(descriptorExtractor->defaultNorm());
73+
74+
const float minIntersectRatio = 0.5f;
75+
const int maxAngle = 360, angleStep = 15;
76+
for(int angle = 0; angle < maxAngle; angle += angleStep)
77+
{
78+
Mat H = rotateImage(image0, mask0, static_cast<float>(angle), image1, mask1);
79+
80+
vector<KeyPoint> keypoints1;
81+
rotateKeyPoints(keypoints0, H, static_cast<float>(angle), keypoints1);
82+
Mat descriptors1;
83+
descriptorExtractor->compute(image1, keypoints1, descriptors1);
84+
85+
vector<DMatch> descMatches;
86+
bfmatcher.match(descriptors0, descriptors1, descMatches);
87+
88+
int descInliersCount = 0;
89+
for(size_t m = 0; m < descMatches.size(); m++)
90+
{
91+
const KeyPoint& transformed_p0 = keypoints1[descMatches[m].queryIdx];
92+
const KeyPoint& p1 = keypoints1[descMatches[m].trainIdx];
93+
if(calcIntersectRatio(transformed_p0.pt, 0.5f * transformed_p0.size,
94+
p1.pt, 0.5f * p1.size) >= minIntersectRatio)
95+
{
96+
descInliersCount++;
97+
}
98+
}
99+
100+
float descInliersRatio = static_cast<float>(descInliersCount) / keypoints0.size();
101+
EXPECT_GE(descInliersRatio, minInliersRatio);
102+
#if SHOW_DEBUG_LOG
103+
std::cout
104+
<< "angle = " << angle
105+
<< ", inliers = " << descInliersCount
106+
<< ", descInliersRatio = " << static_cast<float>(descInliersCount) / keypoints0.size()
107+
<< std::endl;
108+
#endif
109+
}
110+
}
111+
112+
113+
TEST_P(DescriptorScaleInvariance, scale)
114+
{
115+
vector<KeyPoint> keypoints0;
116+
featureDetector->detect(image0, keypoints0);
117+
std::cout << "Keypoints: " << keypoints0.size() << std::endl;
118+
EXPECT_GE(keypoints0.size(), 15u);
119+
Mat descriptors0;
120+
descriptorExtractor->compute(image0, keypoints0, descriptors0);
121+
122+
BFMatcher bfmatcher(descriptorExtractor->defaultNorm());
123+
for(int scaleIdx = 1; scaleIdx <= 3; scaleIdx++)
124+
{
125+
float scale = 1.f + scaleIdx * 0.5f;
126+
127+
Mat image1;
128+
resize(image0, image1, Size(), 1./scale, 1./scale, INTER_LINEAR_EXACT);
129+
130+
vector<KeyPoint> keypoints1;
131+
scaleKeyPoints(keypoints0, keypoints1, 1.0f/scale);
132+
Mat descriptors1;
133+
descriptorExtractor->compute(image1, keypoints1, descriptors1);
134+
135+
vector<DMatch> descMatches;
136+
bfmatcher.match(descriptors0, descriptors1, descMatches);
137+
138+
const float minIntersectRatio = 0.5f;
139+
int descInliersCount = 0;
140+
for(size_t m = 0; m < descMatches.size(); m++)
141+
{
142+
const KeyPoint& transformed_p0 = keypoints0[descMatches[m].queryIdx];
143+
const KeyPoint& p1 = keypoints0[descMatches[m].trainIdx];
144+
if(calcIntersectRatio(transformed_p0.pt, 0.5f * transformed_p0.size,
145+
p1.pt, 0.5f * p1.size) >= minIntersectRatio)
146+
{
147+
descInliersCount++;
148+
}
149+
}
150+
151+
float descInliersRatio = static_cast<float>(descInliersCount) / keypoints0.size();
152+
EXPECT_GE(descInliersRatio, minInliersRatio);
153+
#if SHOW_DEBUG_LOG
154+
std::cout
155+
<< "scale = " << scale
156+
<< ", inliers = " << descInliersCount
157+
<< ", descInliersRatio = " << static_cast<float>(descInliersCount) / keypoints0.size()
158+
<< std::endl;
159+
#endif
160+
}
161+
}
162+
163+
#undef SHOW_DEBUG_LOG
164+
}} // namespace
165+
166+
namespace std {
167+
using namespace opencv_test;
168+
static inline void PrintTo(const String_FeatureDetector_DescriptorExtractor_Float_t& v, std::ostream* os)
169+
{
170+
*os << "(\"" << get<0>(v)
171+
<< "\", " << get<3>(v)
172+
<< ")";
173+
}
174+
} // namespace

0 commit comments

Comments
 (0)