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