~paparazzi-uav/paparazzi/v5.0-manual

« back to all changes in this revision

Viewing changes to sw/ext/opencv_bebop/opencv/modules/features2d/test/test_rotation_and_scale_invariance.cpp

  • Committer: Paparazzi buildbot
  • Date: 2016-05-18 15:00:29 UTC
  • Revision ID: felix.ruess+docbot@gmail.com-20160518150029-e8lgzi5kvb4p7un9
Manual import commit 4b8bbb730080dac23cf816b98908dacfabe2a8ec from v5.0 branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*M///////////////////////////////////////////////////////////////////////////////////////
 
2
//
 
3
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
 
4
//
 
5
//  By downloading, copying, installing or using the software you agree to this license.
 
6
//  If you do not agree to this license, do not download, install,
 
7
//  copy or use the software.
 
8
//
 
9
//
 
10
//                        Intel License Agreement
 
11
//                For Open Source Computer Vision Library
 
12
//
 
13
// Copyright (C) 2000, Intel Corporation, all rights reserved.
 
14
// Third party copyrights are property of their respective owners.
 
15
//
 
16
// Redistribution and use in source and binary forms, with or without modification,
 
17
// are permitted provided that the following conditions are met:
 
18
//
 
19
//   * Redistribution's of source code must retain the above copyright notice,
 
20
//     this list of conditions and the following disclaimer.
 
21
//
 
22
//   * Redistribution's in binary form must reproduce the above copyright notice,
 
23
//     this list of conditions and the following disclaimer in the documentation
 
24
//     and/or other materials provided with the distribution.
 
25
//
 
26
//   * The name of Intel Corporation may not be used to endorse or promote products
 
27
//     derived from this software without specific prior written permission.
 
28
//
 
29
// This software is provided by the copyright holders and contributors "as is" and
 
30
// any express or implied warranties, including, but not limited to, the implied
 
31
// warranties of merchantability and fitness for a particular purpose are disclaimed.
 
32
// In no event shall the Intel Corporation or contributors be liable for any direct,
 
33
// indirect, incidental, special, exemplary, or consequential damages
 
34
// (including, but not limited to, procurement of substitute goods or services;
 
35
// loss of use, data, or profits; or business interruption) however caused
 
36
// and on any theory of liability, whether in contract, strict liability,
 
37
// or tort (including negligence or otherwise) arising in any way out of
 
38
// the use of this software, even if advised of the possibility of such damage.
 
39
//
 
40
//M*/
 
41
 
 
42
#include "test_precomp.hpp"
 
43
 
 
44
using namespace std;
 
45
using namespace cv;
 
46
 
 
47
const string IMAGE_TSUKUBA = "/features2d/tsukuba.png";
 
48
const string IMAGE_BIKES = "/detectors_descriptors_evaluation/images_datasets/bikes/img1.png";
 
49
 
 
50
#define SHOW_DEBUG_LOG 0
 
51
 
 
52
static
 
53
Mat generateHomography(float angle)
 
54
{
 
55
    // angle - rotation around Oz in degrees
 
56
    float angleRadian = static_cast<float>(angle * CV_PI / 180);
 
57
    Mat H = Mat::eye(3, 3, CV_32FC1);
 
58
    H.at<float>(0,0) = H.at<float>(1,1) = std::cos(angleRadian);
 
59
    H.at<float>(0,1) = -std::sin(angleRadian);
 
60
    H.at<float>(1,0) =  std::sin(angleRadian);
 
61
 
 
62
    return H;
 
63
}
 
64
 
 
65
static
 
66
Mat rotateImage(const Mat& srcImage, float angle, Mat& dstImage, Mat& dstMask)
 
67
{
 
68
    // angle - rotation around Oz in degrees
 
69
    float diag = std::sqrt(static_cast<float>(srcImage.cols * srcImage.cols + srcImage.rows * srcImage.rows));
 
70
    Mat LUShift = Mat::eye(3, 3, CV_32FC1); // left up
 
71
    LUShift.at<float>(0,2) = static_cast<float>(-srcImage.cols/2);
 
72
    LUShift.at<float>(1,2) = static_cast<float>(-srcImage.rows/2);
 
73
    Mat RDShift = Mat::eye(3, 3, CV_32FC1); // right down
 
74
    RDShift.at<float>(0,2) = diag/2;
 
75
    RDShift.at<float>(1,2) = diag/2;
 
76
    Size sz(cvRound(diag), cvRound(diag));
 
77
 
 
78
    Mat srcMask(srcImage.size(), CV_8UC1, Scalar(255));
 
79
 
 
80
    Mat H = RDShift * generateHomography(angle) * LUShift;
 
81
    warpPerspective(srcImage, dstImage, H, sz);
 
82
    warpPerspective(srcMask, dstMask, H, sz);
 
83
 
 
84
    return H;
 
85
}
 
86
 
 
87
void rotateKeyPoints(const vector<KeyPoint>& src, const Mat& H, float angle, vector<KeyPoint>& dst)
 
88
{
 
89
    // suppose that H is rotation given from rotateImage() and angle has value passed to rotateImage()
 
90
    vector<Point2f> srcCenters, dstCenters;
 
91
    KeyPoint::convert(src, srcCenters);
 
92
 
 
93
    perspectiveTransform(srcCenters, dstCenters, H);
 
94
 
 
95
    dst = src;
 
96
    for(size_t i = 0; i < dst.size(); i++)
 
97
    {
 
98
        dst[i].pt = dstCenters[i];
 
99
        float dstAngle = src[i].angle + angle;
 
100
        if(dstAngle >= 360.f)
 
101
            dstAngle -= 360.f;
 
102
        dst[i].angle = dstAngle;
 
103
    }
 
104
}
 
105
 
 
106
void scaleKeyPoints(const vector<KeyPoint>& src, vector<KeyPoint>& dst, float scale)
 
107
{
 
108
    dst.resize(src.size());
 
109
    for(size_t i = 0; i < src.size(); i++)
 
110
        dst[i] = KeyPoint(src[i].pt.x * scale, src[i].pt.y * scale, src[i].size * scale, src[i].angle);
 
111
}
 
112
 
 
113
static
 
114
float calcCirclesIntersectArea(const Point2f& p0, float r0, const Point2f& p1, float r1)
 
115
{
 
116
    float c = static_cast<float>(norm(p0 - p1)), sqr_c = c * c;
 
117
 
 
118
    float sqr_r0 = r0 * r0;
 
119
    float sqr_r1 = r1 * r1;
 
120
 
 
121
    if(r0 + r1 <= c)
 
122
       return 0;
 
123
 
 
124
    float minR = std::min(r0, r1);
 
125
    float maxR = std::max(r0, r1);
 
126
    if(c + minR <= maxR)
 
127
        return static_cast<float>(CV_PI * minR * minR);
 
128
 
 
129
    float cos_halfA0 = (sqr_r0 + sqr_c - sqr_r1) / (2 * r0 * c);
 
130
    float cos_halfA1 = (sqr_r1 + sqr_c - sqr_r0) / (2 * r1 * c);
 
131
 
 
132
    float A0 = 2 * acos(cos_halfA0);
 
133
    float A1 = 2 * acos(cos_halfA1);
 
134
 
 
135
    return  0.5f * sqr_r0 * (A0 - sin(A0)) +
 
136
            0.5f * sqr_r1 * (A1 - sin(A1));
 
137
}
 
138
 
 
139
static
 
140
float calcIntersectRatio(const Point2f& p0, float r0, const Point2f& p1, float r1)
 
141
{
 
142
    float intersectArea = calcCirclesIntersectArea(p0, r0, p1, r1);
 
143
    float unionArea = static_cast<float>(CV_PI) * (r0 * r0 + r1 * r1) - intersectArea;
 
144
    return intersectArea / unionArea;
 
145
}
 
146
 
 
147
static
 
148
void matchKeyPoints(const vector<KeyPoint>& keypoints0, const Mat& H,
 
149
                    const vector<KeyPoint>& keypoints1,
 
150
                    vector<DMatch>& matches)
 
151
{
 
152
    vector<Point2f> points0;
 
153
    KeyPoint::convert(keypoints0, points0);
 
154
    Mat points0t;
 
155
    if(H.empty())
 
156
        points0t = Mat(points0);
 
157
    else
 
158
        perspectiveTransform(Mat(points0), points0t, H);
 
159
 
 
160
    matches.clear();
 
161
    vector<uchar> usedMask(keypoints1.size(), 0);
 
162
    for(int i0 = 0; i0 < static_cast<int>(keypoints0.size()); i0++)
 
163
    {
 
164
        int nearestPointIndex = -1;
 
165
        float maxIntersectRatio = 0.f;
 
166
        const float r0 =  0.5f * keypoints0[i0].size;
 
167
        for(size_t i1 = 0; i1 < keypoints1.size(); i1++)
 
168
        {
 
169
            if(nearestPointIndex >= 0 && usedMask[i1])
 
170
                continue;
 
171
 
 
172
            float r1 = 0.5f * keypoints1[i1].size;
 
173
            float intersectRatio = calcIntersectRatio(points0t.at<Point2f>(i0), r0,
 
174
                                                      keypoints1[i1].pt, r1);
 
175
            if(intersectRatio > maxIntersectRatio)
 
176
            {
 
177
                maxIntersectRatio = intersectRatio;
 
178
                nearestPointIndex = static_cast<int>(i1);
 
179
            }
 
180
        }
 
181
 
 
182
        matches.push_back(DMatch(i0, nearestPointIndex, maxIntersectRatio));
 
183
        if(nearestPointIndex >= 0)
 
184
            usedMask[nearestPointIndex] = 1;
 
185
    }
 
186
}
 
187
 
 
188
class DetectorRotationInvarianceTest : public cvtest::BaseTest
 
189
{
 
190
public:
 
191
    DetectorRotationInvarianceTest(const Ptr<FeatureDetector>& _featureDetector,
 
192
                                     float _minKeyPointMatchesRatio,
 
193
                                     float _minAngleInliersRatio) :
 
194
        featureDetector(_featureDetector),
 
195
        minKeyPointMatchesRatio(_minKeyPointMatchesRatio),
 
196
        minAngleInliersRatio(_minAngleInliersRatio)
 
197
    {
 
198
        CV_Assert(featureDetector);
 
199
    }
 
200
 
 
201
protected:
 
202
 
 
203
    void run(int)
 
204
    {
 
205
        const string imageFilename = string(ts->get_data_path()) + IMAGE_TSUKUBA;
 
206
 
 
207
        // Read test data
 
208
        Mat image0 = imread(imageFilename), image1, mask1;
 
209
        if(image0.empty())
 
210
        {
 
211
            ts->printf(cvtest::TS::LOG, "Image %s can not be read.\n", imageFilename.c_str());
 
212
            ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA);
 
213
            return;
 
214
        }
 
215
 
 
216
        vector<KeyPoint> keypoints0;
 
217
        featureDetector->detect(image0, keypoints0);
 
218
        if(keypoints0.size() < 15)
 
219
            CV_Error(Error::StsAssert, "Detector gives too few points in a test image\n");
 
220
 
 
221
        const int maxAngle = 360, angleStep = 15;
 
222
        for(int angle = 0; angle < maxAngle; angle += angleStep)
 
223
        {
 
224
            Mat H = rotateImage(image0, static_cast<float>(angle), image1, mask1);
 
225
 
 
226
            vector<KeyPoint> keypoints1;
 
227
            featureDetector->detect(image1, keypoints1, mask1);
 
228
 
 
229
            vector<DMatch> matches;
 
230
            matchKeyPoints(keypoints0, H, keypoints1, matches);
 
231
 
 
232
            int angleInliersCount = 0;
 
233
 
 
234
            const float minIntersectRatio = 0.5f;
 
235
            int keyPointMatchesCount = 0;
 
236
            for(size_t m = 0; m < matches.size(); m++)
 
237
            {
 
238
                if(matches[m].distance < minIntersectRatio)
 
239
                    continue;
 
240
 
 
241
                keyPointMatchesCount++;
 
242
 
 
243
                // Check does this inlier have consistent angles
 
244
                const float maxAngleDiff = 15.f; // grad
 
245
                float angle0 = keypoints0[matches[m].queryIdx].angle;
 
246
                float angle1 = keypoints1[matches[m].trainIdx].angle;
 
247
                if(angle0 == -1 || angle1 == -1)
 
248
                    CV_Error(Error::StsBadArg, "Given FeatureDetector is not rotation invariant, it can not be tested here.\n");
 
249
                CV_Assert(angle0 >= 0.f && angle0 < 360.f);
 
250
                CV_Assert(angle1 >= 0.f && angle1 < 360.f);
 
251
 
 
252
                float rotAngle0 = angle0 + angle;
 
253
                if(rotAngle0 >= 360.f)
 
254
                    rotAngle0 -= 360.f;
 
255
 
 
256
                float angleDiff = std::max(rotAngle0, angle1) - std::min(rotAngle0, angle1);
 
257
                angleDiff = std::min(angleDiff, static_cast<float>(360.f - angleDiff));
 
258
                CV_Assert(angleDiff >= 0.f);
 
259
                bool isAngleCorrect = angleDiff < maxAngleDiff;
 
260
                if(isAngleCorrect)
 
261
                    angleInliersCount++;
 
262
            }
 
263
 
 
264
            float keyPointMatchesRatio = static_cast<float>(keyPointMatchesCount) / keypoints0.size();
 
265
            if(keyPointMatchesRatio < minKeyPointMatchesRatio)
 
266
            {
 
267
                ts->printf(cvtest::TS::LOG, "Incorrect keyPointMatchesRatio: curr = %f, min = %f.\n",
 
268
                           keyPointMatchesRatio, minKeyPointMatchesRatio);
 
269
                ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
 
270
                return;
 
271
            }
 
272
 
 
273
            if(keyPointMatchesCount)
 
274
            {
 
275
                float angleInliersRatio = static_cast<float>(angleInliersCount) / keyPointMatchesCount;
 
276
                if(angleInliersRatio < minAngleInliersRatio)
 
277
                {
 
278
                    ts->printf(cvtest::TS::LOG, "Incorrect angleInliersRatio: curr = %f, min = %f.\n",
 
279
                               angleInliersRatio, minAngleInliersRatio);
 
280
                    ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
 
281
                    return;
 
282
                }
 
283
            }
 
284
#if SHOW_DEBUG_LOG
 
285
            std::cout << "keyPointMatchesRatio - " << keyPointMatchesRatio
 
286
                << " - angleInliersRatio " << static_cast<float>(angleInliersCount) / keyPointMatchesCount << std::endl;
 
287
#endif
 
288
        }
 
289
        ts->set_failed_test_info( cvtest::TS::OK );
 
290
    }
 
291
 
 
292
    Ptr<FeatureDetector> featureDetector;
 
293
    float minKeyPointMatchesRatio;
 
294
    float minAngleInliersRatio;
 
295
};
 
296
 
 
297
class DescriptorRotationInvarianceTest : public cvtest::BaseTest
 
298
{
 
299
public:
 
300
    DescriptorRotationInvarianceTest(const Ptr<FeatureDetector>& _featureDetector,
 
301
                                     const Ptr<DescriptorExtractor>& _descriptorExtractor,
 
302
                                     int _normType,
 
303
                                     float _minDescInliersRatio) :
 
304
        featureDetector(_featureDetector),
 
305
        descriptorExtractor(_descriptorExtractor),
 
306
        normType(_normType),
 
307
        minDescInliersRatio(_minDescInliersRatio)
 
308
    {
 
309
        CV_Assert(featureDetector);
 
310
        CV_Assert(descriptorExtractor);
 
311
    }
 
312
 
 
313
protected:
 
314
 
 
315
    void run(int)
 
316
    {
 
317
        const string imageFilename = string(ts->get_data_path()) + IMAGE_TSUKUBA;
 
318
 
 
319
        // Read test data
 
320
        Mat image0 = imread(imageFilename), image1, mask1;
 
321
        if(image0.empty())
 
322
        {
 
323
            ts->printf(cvtest::TS::LOG, "Image %s can not be read.\n", imageFilename.c_str());
 
324
            ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA);
 
325
            return;
 
326
        }
 
327
 
 
328
        vector<KeyPoint> keypoints0;
 
329
        Mat descriptors0;
 
330
        featureDetector->detect(image0, keypoints0);
 
331
        if(keypoints0.size() < 15)
 
332
            CV_Error(Error::StsAssert, "Detector gives too few points in a test image\n");
 
333
        descriptorExtractor->compute(image0, keypoints0, descriptors0);
 
334
 
 
335
        BFMatcher bfmatcher(normType);
 
336
 
 
337
        const float minIntersectRatio = 0.5f;
 
338
        const int maxAngle = 360, angleStep = 15;
 
339
        for(int angle = 0; angle < maxAngle; angle += angleStep)
 
340
        {
 
341
            Mat H = rotateImage(image0, static_cast<float>(angle), image1, mask1);
 
342
 
 
343
            vector<KeyPoint> keypoints1;
 
344
            rotateKeyPoints(keypoints0, H, static_cast<float>(angle), keypoints1);
 
345
            Mat descriptors1;
 
346
            descriptorExtractor->compute(image1, keypoints1, descriptors1);
 
347
 
 
348
            vector<DMatch> descMatches;
 
349
            bfmatcher.match(descriptors0, descriptors1, descMatches);
 
350
 
 
351
            int descInliersCount = 0;
 
352
            for(size_t m = 0; m < descMatches.size(); m++)
 
353
            {
 
354
                const KeyPoint& transformed_p0 = keypoints1[descMatches[m].queryIdx];
 
355
                const KeyPoint& p1 = keypoints1[descMatches[m].trainIdx];
 
356
                if(calcIntersectRatio(transformed_p0.pt, 0.5f * transformed_p0.size,
 
357
                                      p1.pt, 0.5f * p1.size) >= minIntersectRatio)
 
358
                {
 
359
                    descInliersCount++;
 
360
                }
 
361
            }
 
362
 
 
363
            float descInliersRatio = static_cast<float>(descInliersCount) / keypoints0.size();
 
364
            if(descInliersRatio < minDescInliersRatio)
 
365
            {
 
366
                ts->printf(cvtest::TS::LOG, "Incorrect descInliersRatio: curr = %f, min = %f.\n",
 
367
                           descInliersRatio, minDescInliersRatio);
 
368
                ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
 
369
                return;
 
370
            }
 
371
#if SHOW_DEBUG_LOG
 
372
            std::cout << "descInliersRatio " << static_cast<float>(descInliersCount) / keypoints0.size() << std::endl;
 
373
#endif
 
374
        }
 
375
        ts->set_failed_test_info( cvtest::TS::OK );
 
376
    }
 
377
 
 
378
    Ptr<FeatureDetector> featureDetector;
 
379
    Ptr<DescriptorExtractor> descriptorExtractor;
 
380
    int normType;
 
381
    float minDescInliersRatio;
 
382
};
 
383
 
 
384
class DetectorScaleInvarianceTest : public cvtest::BaseTest
 
385
{
 
386
public:
 
387
    DetectorScaleInvarianceTest(const Ptr<FeatureDetector>& _featureDetector,
 
388
                                float _minKeyPointMatchesRatio,
 
389
                                float _minScaleInliersRatio) :
 
390
        featureDetector(_featureDetector),
 
391
        minKeyPointMatchesRatio(_minKeyPointMatchesRatio),
 
392
        minScaleInliersRatio(_minScaleInliersRatio)
 
393
    {
 
394
        CV_Assert(featureDetector);
 
395
    }
 
396
 
 
397
protected:
 
398
 
 
399
    void run(int)
 
400
    {
 
401
        const string imageFilename = string(ts->get_data_path()) + IMAGE_BIKES;
 
402
 
 
403
        // Read test data
 
404
        Mat image0 = imread(imageFilename);
 
405
        if(image0.empty())
 
406
        {
 
407
            ts->printf(cvtest::TS::LOG, "Image %s can not be read.\n", imageFilename.c_str());
 
408
            ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA);
 
409
            return;
 
410
        }
 
411
 
 
412
        vector<KeyPoint> keypoints0;
 
413
        featureDetector->detect(image0, keypoints0);
 
414
        if(keypoints0.size() < 15)
 
415
            CV_Error(Error::StsAssert, "Detector gives too few points in a test image\n");
 
416
 
 
417
        for(int scaleIdx = 1; scaleIdx <= 3; scaleIdx++)
 
418
        {
 
419
            float scale = 1.f + scaleIdx * 0.5f;
 
420
            Mat image1;
 
421
            resize(image0, image1, Size(), 1./scale, 1./scale);
 
422
 
 
423
            vector<KeyPoint> keypoints1, osiKeypoints1; // osi - original size image
 
424
            featureDetector->detect(image1, keypoints1);
 
425
            if(keypoints1.size() < 15)
 
426
                CV_Error(Error::StsAssert, "Detector gives too few points in a test image\n");
 
427
 
 
428
            if(keypoints1.size() > keypoints0.size())
 
429
            {
 
430
                ts->printf(cvtest::TS::LOG, "Strange behavior of the detector. "
 
431
                    "It gives more points count in an image of the smaller size.\n"
 
432
                    "original size (%d, %d), keypoints count = %d\n"
 
433
                    "reduced size (%d, %d), keypoints count = %d\n",
 
434
                    image0.cols, image0.rows, keypoints0.size(),
 
435
                    image1.cols, image1.rows, keypoints1.size());
 
436
                ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT);
 
437
                return;
 
438
            }
 
439
 
 
440
            scaleKeyPoints(keypoints1, osiKeypoints1, scale);
 
441
 
 
442
            vector<DMatch> matches;
 
443
            // image1 is query image (it's reduced image0)
 
444
            // image0 is train image
 
445
            matchKeyPoints(osiKeypoints1, Mat(), keypoints0, matches);
 
446
 
 
447
            const float minIntersectRatio = 0.5f;
 
448
            int keyPointMatchesCount = 0;
 
449
            int scaleInliersCount = 0;
 
450
 
 
451
            for(size_t m = 0; m < matches.size(); m++)
 
452
            {
 
453
                if(matches[m].distance < minIntersectRatio)
 
454
                    continue;
 
455
 
 
456
                keyPointMatchesCount++;
 
457
 
 
458
                // Check does this inlier have consistent sizes
 
459
                const float maxSizeDiff = 0.8f;//0.9f; // grad
 
460
                float size0 = keypoints0[matches[m].trainIdx].size;
 
461
                float size1 = osiKeypoints1[matches[m].queryIdx].size;
 
462
                CV_Assert(size0 > 0 && size1 > 0);
 
463
                if(std::min(size0, size1) > maxSizeDiff * std::max(size0, size1))
 
464
                    scaleInliersCount++;
 
465
            }
 
466
 
 
467
            float keyPointMatchesRatio = static_cast<float>(keyPointMatchesCount) / keypoints1.size();
 
468
            if(keyPointMatchesRatio < minKeyPointMatchesRatio)
 
469
            {
 
470
                ts->printf(cvtest::TS::LOG, "Incorrect keyPointMatchesRatio: curr = %f, min = %f.\n",
 
471
                           keyPointMatchesRatio, minKeyPointMatchesRatio);
 
472
                ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
 
473
                return;
 
474
            }
 
475
 
 
476
            if(keyPointMatchesCount)
 
477
            {
 
478
                float scaleInliersRatio = static_cast<float>(scaleInliersCount) / keyPointMatchesCount;
 
479
                if(scaleInliersRatio < minScaleInliersRatio)
 
480
                {
 
481
                    ts->printf(cvtest::TS::LOG, "Incorrect scaleInliersRatio: curr = %f, min = %f.\n",
 
482
                               scaleInliersRatio, minScaleInliersRatio);
 
483
                    ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
 
484
                    return;
 
485
                }
 
486
            }
 
487
#if SHOW_DEBUG_LOG
 
488
            std::cout << "keyPointMatchesRatio - " << keyPointMatchesRatio
 
489
                << " - scaleInliersRatio " << static_cast<float>(scaleInliersCount) / keyPointMatchesCount << std::endl;
 
490
#endif
 
491
        }
 
492
        ts->set_failed_test_info( cvtest::TS::OK );
 
493
    }
 
494
 
 
495
    Ptr<FeatureDetector> featureDetector;
 
496
    float minKeyPointMatchesRatio;
 
497
    float minScaleInliersRatio;
 
498
};
 
499
 
 
500
class DescriptorScaleInvarianceTest : public cvtest::BaseTest
 
501
{
 
502
public:
 
503
    DescriptorScaleInvarianceTest(const Ptr<FeatureDetector>& _featureDetector,
 
504
                                const Ptr<DescriptorExtractor>& _descriptorExtractor,
 
505
                                int _normType,
 
506
                                float _minDescInliersRatio) :
 
507
        featureDetector(_featureDetector),
 
508
        descriptorExtractor(_descriptorExtractor),
 
509
        normType(_normType),
 
510
        minDescInliersRatio(_minDescInliersRatio)
 
511
    {
 
512
        CV_Assert(featureDetector);
 
513
        CV_Assert(descriptorExtractor);
 
514
    }
 
515
 
 
516
protected:
 
517
 
 
518
    void run(int)
 
519
    {
 
520
        const string imageFilename = string(ts->get_data_path()) + IMAGE_BIKES;
 
521
 
 
522
        // Read test data
 
523
        Mat image0 = imread(imageFilename);
 
524
        if(image0.empty())
 
525
        {
 
526
            ts->printf(cvtest::TS::LOG, "Image %s can not be read.\n", imageFilename.c_str());
 
527
            ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA);
 
528
            return;
 
529
        }
 
530
 
 
531
        vector<KeyPoint> keypoints0;
 
532
        featureDetector->detect(image0, keypoints0);
 
533
        if(keypoints0.size() < 15)
 
534
            CV_Error(Error::StsAssert, "Detector gives too few points in a test image\n");
 
535
        Mat descriptors0;
 
536
        descriptorExtractor->compute(image0, keypoints0, descriptors0);
 
537
 
 
538
        BFMatcher bfmatcher(normType);
 
539
        for(int scaleIdx = 1; scaleIdx <= 3; scaleIdx++)
 
540
        {
 
541
            float scale = 1.f + scaleIdx * 0.5f;
 
542
 
 
543
            Mat image1;
 
544
            resize(image0, image1, Size(), 1./scale, 1./scale);
 
545
 
 
546
            vector<KeyPoint> keypoints1;
 
547
            scaleKeyPoints(keypoints0, keypoints1, 1.0f/scale);
 
548
            Mat descriptors1;
 
549
            descriptorExtractor->compute(image1, keypoints1, descriptors1);
 
550
 
 
551
            vector<DMatch> descMatches;
 
552
            bfmatcher.match(descriptors0, descriptors1, descMatches);
 
553
 
 
554
            const float minIntersectRatio = 0.5f;
 
555
            int descInliersCount = 0;
 
556
            for(size_t m = 0; m < descMatches.size(); m++)
 
557
            {
 
558
                const KeyPoint& transformed_p0 = keypoints0[descMatches[m].queryIdx];
 
559
                const KeyPoint& p1 = keypoints0[descMatches[m].trainIdx];
 
560
                if(calcIntersectRatio(transformed_p0.pt, 0.5f * transformed_p0.size,
 
561
                                      p1.pt, 0.5f * p1.size) >= minIntersectRatio)
 
562
                {
 
563
                    descInliersCount++;
 
564
                }
 
565
            }
 
566
 
 
567
            float descInliersRatio = static_cast<float>(descInliersCount) / keypoints0.size();
 
568
            if(descInliersRatio < minDescInliersRatio)
 
569
            {
 
570
                ts->printf(cvtest::TS::LOG, "Incorrect descInliersRatio: curr = %f, min = %f.\n",
 
571
                           descInliersRatio, minDescInliersRatio);
 
572
                ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
 
573
                return;
 
574
            }
 
575
#if SHOW_DEBUG_LOG
 
576
            std::cout << "descInliersRatio " << static_cast<float>(descInliersCount) / keypoints0.size() << std::endl;
 
577
#endif
 
578
        }
 
579
        ts->set_failed_test_info( cvtest::TS::OK );
 
580
    }
 
581
 
 
582
    Ptr<FeatureDetector> featureDetector;
 
583
    Ptr<DescriptorExtractor> descriptorExtractor;
 
584
    int normType;
 
585
    float minKeyPointMatchesRatio;
 
586
    float minDescInliersRatio;
 
587
};
 
588
 
 
589
// Tests registration
 
590
 
 
591
/*
 
592
 * Detector's rotation invariance check
 
593
 */
 
594
 
 
595
TEST(Features2d_RotationInvariance_Detector_BRISK, regression)
 
596
{
 
597
    DetectorRotationInvarianceTest test(BRISK::create(),
 
598
                                        0.32f,
 
599
                                        0.76f);
 
600
    test.safe_run();
 
601
}
 
602
 
 
603
TEST(Features2d_RotationInvariance_Detector_ORB, regression)
 
604
{
 
605
    DetectorRotationInvarianceTest test(ORB::create(),
 
606
                                        0.47f,
 
607
                                        0.76f);
 
608
    test.safe_run();
 
609
}
 
610
 
 
611
/*
 
612
 * Descriptors's rotation invariance check
 
613
 */
 
614
 
 
615
TEST(Features2d_RotationInvariance_Descriptor_BRISK, regression)
 
616
{
 
617
    Ptr<Feature2D> f2d = BRISK::create();
 
618
    DescriptorRotationInvarianceTest test(f2d, f2d, f2d->defaultNorm(), 0.99f);
 
619
    test.safe_run();
 
620
}
 
621
 
 
622
TEST(Features2d_RotationInvariance_Descriptor_ORB, regression)
 
623
{
 
624
    Ptr<Feature2D> f2d = ORB::create();
 
625
    DescriptorRotationInvarianceTest test(f2d, f2d, f2d->defaultNorm(), 0.99f);
 
626
    test.safe_run();
 
627
}
 
628
 
 
629
//TEST(Features2d_RotationInvariance_Descriptor_FREAK, regression)
 
630
//{
 
631
//    DescriptorRotationInvarianceTest test(Algorithm::create<FeatureDetector>("Feature2D.ORB"),
 
632
//                                          Algorithm::create<DescriptorExtractor>("Feature2D.FREAK"),
 
633
//                                          Algorithm::create<DescriptorExtractor>("Feature2D.FREAK")->defaultNorm(),
 
634
//                                          0.f);
 
635
//    test.safe_run();
 
636
//}
 
637
 
 
638
/*
 
639
 * Detector's scale invariance check
 
640
 */
 
641
 
 
642
TEST(Features2d_ScaleInvariance_Detector_BRISK, regression)
 
643
{
 
644
    DetectorScaleInvarianceTest test(BRISK::create(), 0.08f, 0.49f);
 
645
    test.safe_run();
 
646
}
 
647
 
 
648
TEST(Features2d_ScaleInvariance_Detector_KAZE, regression)
 
649
{
 
650
    DetectorScaleInvarianceTest test(KAZE::create(), 0.08f, 0.49f);
 
651
    test.safe_run();
 
652
}
 
653
 
 
654
TEST(Features2d_ScaleInvariance_Detector_AKAZE, regression)
 
655
{
 
656
    DetectorScaleInvarianceTest test(AKAZE::create(), 0.08f, 0.49f);
 
657
    test.safe_run();
 
658
}
 
659
 
 
660
//TEST(Features2d_ScaleInvariance_Detector_ORB, regression)
 
661
//{
 
662
//    DetectorScaleInvarianceTest test(Algorithm::create<FeatureDetector>("Feature2D.ORB"),
 
663
//                                     0.22f,
 
664
//                                     0.83f);
 
665
//    test.safe_run();
 
666
//}
 
667
 
 
668
/*
 
669
 * Descriptor's scale invariance check
 
670
 */
 
671
 
 
672
//TEST(Features2d_ScaleInvariance_Descriptor_BRISK, regression)
 
673
//{
 
674
//    DescriptorScaleInvarianceTest test(Algorithm::create<FeatureDetector>("Feature2D.BRISK"),
 
675
//                                       Algorithm::create<DescriptorExtractor>("Feature2D.BRISK"),
 
676
//                                       Algorithm::create<DescriptorExtractor>("Feature2D.BRISK")->defaultNorm(),
 
677
//                                       0.99f);
 
678
//    test.safe_run();
 
679
//}
 
680
 
 
681
//TEST(Features2d_ScaleInvariance_Descriptor_ORB, regression)
 
682
//{
 
683
//    DescriptorScaleInvarianceTest test(Algorithm::create<FeatureDetector>("Feature2D.ORB"),
 
684
//                                       Algorithm::create<DescriptorExtractor>("Feature2D.ORB"),
 
685
//                                       Algorithm::create<DescriptorExtractor>("Feature2D.ORB")->defaultNorm(),
 
686
//                                       0.01f);
 
687
//    test.safe_run();
 
688
//}
 
689
 
 
690
//TEST(Features2d_ScaleInvariance_Descriptor_FREAK, regression)
 
691
//{
 
692
//    DescriptorScaleInvarianceTest test(Algorithm::create<FeatureDetector>("Feature2D.ORB"),
 
693
//                                       Algorithm::create<DescriptorExtractor>("Feature2D.FREAK"),
 
694
//                                       Algorithm::create<DescriptorExtractor>("Feature2D.FREAK")->defaultNorm(),
 
695
//                                       0.01f);
 
696
//    test.safe_run();
 
697
//}