Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/modules/features2d/test/test_detectors_invariance.impl.hpp
16356 views
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>, float, float> String_FeatureDetector_Float_Float_t;
12
13
14
static
15
void matchKeyPoints(const vector<KeyPoint>& keypoints0, const Mat& H,
16
const vector<KeyPoint>& keypoints1,
17
vector<DMatch>& matches)
18
{
19
vector<Point2f> points0;
20
KeyPoint::convert(keypoints0, points0);
21
Mat points0t;
22
if(H.empty())
23
points0t = Mat(points0);
24
else
25
perspectiveTransform(Mat(points0), points0t, H);
26
27
matches.clear();
28
vector<uchar> usedMask(keypoints1.size(), 0);
29
for(int i0 = 0; i0 < static_cast<int>(keypoints0.size()); i0++)
30
{
31
int nearestPointIndex = -1;
32
float maxIntersectRatio = 0.f;
33
const float r0 = 0.5f * keypoints0[i0].size;
34
for(size_t i1 = 0; i1 < keypoints1.size(); i1++)
35
{
36
if(nearestPointIndex >= 0 && usedMask[i1])
37
continue;
38
39
float r1 = 0.5f * keypoints1[i1].size;
40
float intersectRatio = calcIntersectRatio(points0t.at<Point2f>(i0), r0,
41
keypoints1[i1].pt, r1);
42
if(intersectRatio > maxIntersectRatio)
43
{
44
maxIntersectRatio = intersectRatio;
45
nearestPointIndex = static_cast<int>(i1);
46
}
47
}
48
49
matches.push_back(DMatch(i0, nearestPointIndex, maxIntersectRatio));
50
if(nearestPointIndex >= 0)
51
usedMask[nearestPointIndex] = 1;
52
}
53
}
54
55
class DetectorInvariance : public TestWithParam<String_FeatureDetector_Float_Float_t>
56
{
57
protected:
58
virtual void SetUp() {
59
// Read test data
60
const std::string filename = cvtest::TS::ptr()->get_data_path() + get<0>(GetParam());
61
image0 = imread(filename);
62
ASSERT_FALSE(image0.empty()) << "couldn't read input image";
63
64
featureDetector = get<1>(GetParam());
65
minKeyPointMatchesRatio = get<2>(GetParam());
66
minInliersRatio = get<3>(GetParam());
67
}
68
69
Ptr<FeatureDetector> featureDetector;
70
float minKeyPointMatchesRatio;
71
float minInliersRatio;
72
Mat image0;
73
};
74
75
typedef DetectorInvariance DetectorScaleInvariance;
76
typedef DetectorInvariance DetectorRotationInvariance;
77
78
TEST_P(DetectorRotationInvariance, rotation)
79
{
80
Mat image1, mask1;
81
const int borderSize = 16;
82
Mat mask0(image0.size(), CV_8UC1, Scalar(0));
83
mask0(Rect(borderSize, borderSize, mask0.cols - 2*borderSize, mask0.rows - 2*borderSize)).setTo(Scalar(255));
84
85
vector<KeyPoint> keypoints0;
86
featureDetector->detect(image0, keypoints0, mask0);
87
EXPECT_GE(keypoints0.size(), 15u);
88
89
const int maxAngle = 360, angleStep = 15;
90
for(int angle = 0; angle < maxAngle; angle += angleStep)
91
{
92
Mat H = rotateImage(image0, mask0, static_cast<float>(angle), image1, mask1);
93
94
vector<KeyPoint> keypoints1;
95
featureDetector->detect(image1, keypoints1, mask1);
96
97
vector<DMatch> matches;
98
matchKeyPoints(keypoints0, H, keypoints1, matches);
99
100
int angleInliersCount = 0;
101
102
const float minIntersectRatio = 0.5f;
103
int keyPointMatchesCount = 0;
104
for(size_t m = 0; m < matches.size(); m++)
105
{
106
if(matches[m].distance < minIntersectRatio)
107
continue;
108
109
keyPointMatchesCount++;
110
111
// Check does this inlier have consistent angles
112
const float maxAngleDiff = 15.f; // grad
113
float angle0 = keypoints0[matches[m].queryIdx].angle;
114
float angle1 = keypoints1[matches[m].trainIdx].angle;
115
ASSERT_FALSE(angle0 == -1 || angle1 == -1) << "Given FeatureDetector is not rotation invariant, it can not be tested here.";
116
ASSERT_GE(angle0, 0.f);
117
ASSERT_LT(angle0, 360.f);
118
ASSERT_GE(angle1, 0.f);
119
ASSERT_LT(angle1, 360.f);
120
121
float rotAngle0 = angle0 + angle;
122
if(rotAngle0 >= 360.f)
123
rotAngle0 -= 360.f;
124
125
float angleDiff = std::max(rotAngle0, angle1) - std::min(rotAngle0, angle1);
126
angleDiff = std::min(angleDiff, static_cast<float>(360.f - angleDiff));
127
ASSERT_GE(angleDiff, 0.f);
128
bool isAngleCorrect = angleDiff < maxAngleDiff;
129
if(isAngleCorrect)
130
angleInliersCount++;
131
}
132
133
float keyPointMatchesRatio = static_cast<float>(keyPointMatchesCount) / keypoints0.size();
134
EXPECT_GE(keyPointMatchesRatio, minKeyPointMatchesRatio) << "angle: " << angle;
135
136
if(keyPointMatchesCount)
137
{
138
float angleInliersRatio = static_cast<float>(angleInliersCount) / keyPointMatchesCount;
139
EXPECT_GE(angleInliersRatio, minInliersRatio) << "angle: " << angle;
140
}
141
#if SHOW_DEBUG_LOG
142
std::cout
143
<< "angle = " << angle
144
<< ", keypoints = " << keypoints1.size()
145
<< ", keyPointMatchesRatio = " << keyPointMatchesRatio
146
<< ", angleInliersRatio = " << (keyPointMatchesCount ? (static_cast<float>(angleInliersCount) / keyPointMatchesCount) : 0)
147
<< std::endl;
148
#endif
149
}
150
}
151
152
TEST_P(DetectorScaleInvariance, scale)
153
{
154
vector<KeyPoint> keypoints0;
155
featureDetector->detect(image0, keypoints0);
156
EXPECT_GE(keypoints0.size(), 15u);
157
158
for(int scaleIdx = 1; scaleIdx <= 3; scaleIdx++)
159
{
160
float scale = 1.f + scaleIdx * 0.5f;
161
Mat image1;
162
resize(image0, image1, Size(), 1./scale, 1./scale, INTER_LINEAR_EXACT);
163
164
vector<KeyPoint> keypoints1, osiKeypoints1; // osi - original size image
165
featureDetector->detect(image1, keypoints1);
166
EXPECT_GE(keypoints1.size(), 15u);
167
EXPECT_LE(keypoints1.size(), keypoints0.size()) << "Strange behavior of the detector. "
168
"It gives more points count in an image of the smaller size.";
169
170
scaleKeyPoints(keypoints1, osiKeypoints1, scale);
171
vector<DMatch> matches;
172
// image1 is query image (it's reduced image0)
173
// image0 is train image
174
matchKeyPoints(osiKeypoints1, Mat(), keypoints0, matches);
175
176
const float minIntersectRatio = 0.5f;
177
int keyPointMatchesCount = 0;
178
int scaleInliersCount = 0;
179
180
for(size_t m = 0; m < matches.size(); m++)
181
{
182
if(matches[m].distance < minIntersectRatio)
183
continue;
184
185
keyPointMatchesCount++;
186
187
// Check does this inlier have consistent sizes
188
const float maxSizeDiff = 0.8f;//0.9f; // grad
189
float size0 = keypoints0[matches[m].trainIdx].size;
190
float size1 = osiKeypoints1[matches[m].queryIdx].size;
191
ASSERT_GT(size0, 0);
192
ASSERT_GT(size1, 0);
193
if(std::min(size0, size1) > maxSizeDiff * std::max(size0, size1))
194
scaleInliersCount++;
195
}
196
197
float keyPointMatchesRatio = static_cast<float>(keyPointMatchesCount) / keypoints1.size();
198
EXPECT_GE(keyPointMatchesRatio, minKeyPointMatchesRatio);
199
200
if(keyPointMatchesCount)
201
{
202
float scaleInliersRatio = static_cast<float>(scaleInliersCount) / keyPointMatchesCount;
203
EXPECT_GE(scaleInliersRatio, minInliersRatio);
204
}
205
#if SHOW_DEBUG_LOG
206
std::cout
207
<< "scale = " << scale
208
<< ", keyPointMatchesRatio = " << keyPointMatchesRatio
209
<< ", scaleInliersRatio = " << (keyPointMatchesCount ? static_cast<float>(scaleInliersCount) / keyPointMatchesCount : 0)
210
<< std::endl;
211
#endif
212
}
213
}
214
215
#undef SHOW_DEBUG_LOG
216
}} // namespace
217
218
namespace std {
219
using namespace opencv_test;
220
static inline void PrintTo(const String_FeatureDetector_Float_Float_t& v, std::ostream* os)
221
{
222
*os << "(\"" << get<0>(v)
223
<< "\", " << get<2>(v)
224
<< ", " << get<3>(v)
225
<< ")";
226
}
227
} // namespace
228
229