Merge remote-tracking branch 'upstream/3.4' into merge-3.4
authorAlexander Alekhin <alexander.a.alekhin@gmail.com>
Mon, 29 Jun 2020 21:00:18 +0000 (21:00 +0000)
committerAlexander Alekhin <alexander.a.alekhin@gmail.com>
Mon, 29 Jun 2020 21:19:09 +0000 (21:19 +0000)
1  2 
modules/core/include/opencv2/core/cvdef.h
modules/features2d/include/opencv2/features2d.hpp
modules/features2d/test/test_descriptors_invariance.cpp
modules/features2d/test/test_descriptors_invariance.impl.hpp
modules/features2d/test/test_detectors_invariance.cpp

@@@ -84,9 -84,15 +84,15 @@@ namespace cv { namespace debug_build_gu
  #endif
  
  #define __CV_VA_NUM_ARGS_HELPER(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
 -#define __CV_VA_NUM_ARGS(...) __CV_VA_NUM_ARGS_HELPER(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
 +#define __CV_VA_NUM_ARGS(...) __CV_EXPAND(__CV_VA_NUM_ARGS_HELPER(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))
  
- #if defined __GNUC__
+ #ifdef CV_Func
+ // keep current value (through OpenCV port file)
+ #elif defined __GNUC__ || (defined (__cpluscplus) && (__cpluscplus >= 201103))
+ #define CV_Func __func__
+ #elif defined __clang__ && (__clang_minor__ * 100 + __clang_major >= 305)
+ #define CV_Func __func__
+ #elif defined(__STDC_VERSION__) && (__STDC_VERSION >= 199901)
  #define CV_Func __func__
  #elif defined _MSC_VER
  #define CV_Func __FUNCTION__
index f252f1e,0000000..780e86e
mode 100644,000000..100644
--- /dev/null
@@@ -1,174 -1,0 +1,198 @@@
 +// This file is part of OpenCV project.
 +// It is subject to the license terms in the LICENSE file found in the top-level directory
 +// of this distribution and at http://opencv.org/license.html
 +
 +#include "test_invariance_utils.hpp"
 +
 +namespace opencv_test { namespace {
 +
 +#define SHOW_DEBUG_LOG 1
 +
 +typedef tuple<std::string, Ptr<FeatureDetector>, Ptr<DescriptorExtractor>, float>
 +    String_FeatureDetector_DescriptorExtractor_Float_t;
 +
 +
 +static
++void SetSuitableSIFTOctave(vector<KeyPoint>& keypoints,
++                             int firstOctave = -1, int nOctaveLayers = 3, double sigma = 1.6)
++{
++    for (size_t i = 0; i < keypoints.size(); i++ )
++    {
++        int octv, layer;
++        KeyPoint& kpt = keypoints[i];
++        double octv_layer = std::log(kpt.size / sigma) / std::log(2.) - 1;
++        octv = cvFloor(octv_layer);
++        layer = cvRound( (octv_layer - octv) * nOctaveLayers );
++        if (octv < firstOctave)
++        {
++            octv = firstOctave;
++            layer = 0;
++        }
++        kpt.octave = (layer << 8) | (octv & 255);
++    }
++}
++
++static
 +void rotateKeyPoints(const vector<KeyPoint>& src, const Mat& H, float angle, vector<KeyPoint>& dst)
 +{
 +    // suppose that H is rotation given from rotateImage() and angle has value passed to rotateImage()
 +    vector<Point2f> srcCenters, dstCenters;
 +    KeyPoint::convert(src, srcCenters);
 +
 +    perspectiveTransform(srcCenters, dstCenters, H);
 +
 +    dst = src;
 +    for(size_t i = 0; i < dst.size(); i++)
 +    {
 +        dst[i].pt = dstCenters[i];
 +        float dstAngle = src[i].angle + angle;
 +        if(dstAngle >= 360.f)
 +            dstAngle -= 360.f;
 +        dst[i].angle = dstAngle;
 +    }
 +}
 +
 +class DescriptorInvariance : public TestWithParam<String_FeatureDetector_DescriptorExtractor_Float_t>
 +{
 +protected:
 +    virtual void SetUp() {
 +        // Read test data
 +        const std::string filename = cvtest::TS::ptr()->get_data_path() + get<0>(GetParam());
 +        image0 = imread(filename);
 +        ASSERT_FALSE(image0.empty()) << "couldn't read input image";
 +
 +        featureDetector = get<1>(GetParam());
 +        descriptorExtractor = get<2>(GetParam());
 +        minInliersRatio = get<3>(GetParam());
 +    }
 +
 +    Ptr<FeatureDetector> featureDetector;
 +    Ptr<DescriptorExtractor> descriptorExtractor;
 +    float minInliersRatio;
 +    Mat image0;
 +};
 +
 +typedef DescriptorInvariance DescriptorScaleInvariance;
 +typedef DescriptorInvariance DescriptorRotationInvariance;
 +
 +TEST_P(DescriptorRotationInvariance, rotation)
 +{
 +    Mat image1, mask1;
 +    const int borderSize = 16;
 +    Mat mask0(image0.size(), CV_8UC1, Scalar(0));
 +    mask0(Rect(borderSize, borderSize, mask0.cols - 2*borderSize, mask0.rows - 2*borderSize)).setTo(Scalar(255));
 +
 +    vector<KeyPoint> keypoints0;
 +    Mat descriptors0;
 +    featureDetector->detect(image0, keypoints0, mask0);
 +    std::cout << "Keypoints: " << keypoints0.size() << std::endl;
 +    EXPECT_GE(keypoints0.size(), 15u);
 +    descriptorExtractor->compute(image0, keypoints0, descriptors0);
 +
 +    BFMatcher bfmatcher(descriptorExtractor->defaultNorm());
 +
 +    const float minIntersectRatio = 0.5f;
 +    const int maxAngle = 360, angleStep = 15;
 +    for(int angle = 0; angle < maxAngle; angle += angleStep)
 +    {
 +        Mat H = rotateImage(image0, mask0, static_cast<float>(angle), image1, mask1);
 +
 +        vector<KeyPoint> keypoints1;
 +        rotateKeyPoints(keypoints0, H, static_cast<float>(angle), keypoints1);
 +        Mat descriptors1;
 +        descriptorExtractor->compute(image1, keypoints1, descriptors1);
 +
 +        vector<DMatch> descMatches;
 +        bfmatcher.match(descriptors0, descriptors1, descMatches);
 +
 +        int descInliersCount = 0;
 +        for(size_t m = 0; m < descMatches.size(); m++)
 +        {
 +            const KeyPoint& transformed_p0 = keypoints1[descMatches[m].queryIdx];
 +            const KeyPoint& p1 = keypoints1[descMatches[m].trainIdx];
 +            if(calcIntersectRatio(transformed_p0.pt, 0.5f * transformed_p0.size,
 +                                  p1.pt, 0.5f * p1.size) >= minIntersectRatio)
 +            {
 +                descInliersCount++;
 +            }
 +        }
 +
 +        float descInliersRatio = static_cast<float>(descInliersCount) / keypoints0.size();
 +        EXPECT_GE(descInliersRatio, minInliersRatio);
 +#if SHOW_DEBUG_LOG
 +        std::cout
 +            << "angle = " << angle
 +            << ", inliers = " << descInliersCount
 +            << ", descInliersRatio = " << static_cast<float>(descInliersCount) / keypoints0.size()
 +            << std::endl;
 +#endif
 +    }
 +}
 +
 +
 +TEST_P(DescriptorScaleInvariance, scale)
 +{
 +    vector<KeyPoint> keypoints0;
 +    featureDetector->detect(image0, keypoints0);
 +    std::cout << "Keypoints: " << keypoints0.size() << std::endl;
 +    EXPECT_GE(keypoints0.size(), 15u);
 +    Mat descriptors0;
 +    descriptorExtractor->compute(image0, keypoints0, descriptors0);
 +
 +    BFMatcher bfmatcher(descriptorExtractor->defaultNorm());
 +    for(int scaleIdx = 1; scaleIdx <= 3; scaleIdx++)
 +    {
 +        float scale = 1.f + scaleIdx * 0.5f;
 +
 +        Mat image1;
 +        resize(image0, image1, Size(), 1./scale, 1./scale, INTER_LINEAR_EXACT);
 +
 +        vector<KeyPoint> keypoints1;
 +        scaleKeyPoints(keypoints0, keypoints1, 1.0f/scale);
++        if (featureDetector->getDefaultName() == "Feature2D.SIFT")
++        {
++            SetSuitableSIFTOctave(keypoints1);
++        }
 +        Mat descriptors1;
 +        descriptorExtractor->compute(image1, keypoints1, descriptors1);
 +
 +        vector<DMatch> descMatches;
 +        bfmatcher.match(descriptors0, descriptors1, descMatches);
 +
 +        const float minIntersectRatio = 0.5f;
 +        int descInliersCount = 0;
 +        for(size_t m = 0; m < descMatches.size(); m++)
 +        {
 +            const KeyPoint& transformed_p0 = keypoints0[descMatches[m].queryIdx];
 +            const KeyPoint& p1 = keypoints0[descMatches[m].trainIdx];
 +            if(calcIntersectRatio(transformed_p0.pt, 0.5f * transformed_p0.size,
 +                                  p1.pt, 0.5f * p1.size) >= minIntersectRatio)
 +            {
 +                descInliersCount++;
 +            }
 +        }
 +
 +        float descInliersRatio = static_cast<float>(descInliersCount) / keypoints0.size();
 +        EXPECT_GE(descInliersRatio, minInliersRatio);
 +#if SHOW_DEBUG_LOG
 +        std::cout
 +            << "scale = " << scale
 +            << ", inliers = " << descInliersCount
 +            << ", descInliersRatio = " << static_cast<float>(descInliersCount) / keypoints0.size()
 +            << std::endl;
 +#endif
 +    }
 +}
 +
 +#undef SHOW_DEBUG_LOG
 +}} // namespace
 +
 +namespace std {
 +using namespace opencv_test;
 +static inline void PrintTo(const String_FeatureDetector_DescriptorExtractor_Float_t& v, std::ostream* os)
 +{
 +    *os << "(\"" << get<0>(v)
 +        << "\", " << get<3>(v)
 +        << ")";
 +}
 +} // namespace
@@@ -36,9 -234,8 +36,8 @@@ INSTANTIATE_TEST_CASE_P(AKAZE_DESCRIPTO
   * Detector's scale invariance check
   */
  
- // TODO: Expected: (keyPointMatchesRatio) >= (minKeyPointMatchesRatio), actual: 0.596752 vs 0.69
- INSTANTIATE_TEST_CASE_P(DISABLED_SIFT, DetectorScaleInvariance,
-                         Value(IMAGE_BIKES, SIFT::create(), 0.69f, 0.98f));
+ INSTANTIATE_TEST_CASE_P(SIFT, DetectorScaleInvariance,
 -                        Value(IMAGE_BIKES, SIFT::create(0, 3, 0.09), 0.69f, 0.98f));
++                        Value(IMAGE_BIKES, SIFT::create(0, 3, 0.09), 0.65f, 0.98f));
  
  INSTANTIATE_TEST_CASE_P(BRISK, DetectorScaleInvariance,
                          Value(IMAGE_BIKES, BRISK::create(), 0.08f, 0.49f));