Merge pull request #16717 from OrestChura:oc/goodFeatures
authorOrest Chura <orest.chura@intel.com>
Tue, 7 Apr 2020 15:53:24 +0000 (18:53 +0300)
committerGitHub <noreply@github.com>
Tue, 7 Apr 2020 15:53:24 +0000 (15:53 +0000)
- cv::gapi::goodFeaturesToTrack() kernel is implemented
- tests (for exact check with cv::goodFeaturesToTrack() and for internal cases) are implemented
- a custom comparison function for vectors and a custom test fixture implemented
  - some posiible issues as wrong/inexact sorting of two compared vectors are
 not taken into account
- initializations of an input Mat using a picture from opencv_extra implemented (function from gapi_streaming_test used)

modules/gapi/include/opencv2/gapi/imgproc.hpp
modules/gapi/perf/common/gapi_imgproc_perf_tests.hpp
modules/gapi/perf/common/gapi_imgproc_perf_tests_inl.hpp
modules/gapi/perf/cpu/gapi_imgproc_perf_tests_cpu.cpp
modules/gapi/src/api/kernels_imgproc.cpp
modules/gapi/src/backends/cpu/gcpuimgproc.cpp
modules/gapi/test/common/gapi_core_tests.hpp
modules/gapi/test/common/gapi_imgproc_tests.hpp
modules/gapi/test/common/gapi_imgproc_tests_inl.hpp
modules/gapi/test/common/gapi_tests_common.hpp
modules/gapi/test/cpu/gapi_imgproc_tests_cpu.cpp

index 775c30a..1485398 100644 (file)
@@ -2,7 +2,7 @@
 // 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.
 //
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
 
 
 #ifndef OPENCV_GAPI_IMGPROC_HPP
@@ -102,6 +102,14 @@ namespace imgproc {
         }
     };
 
+    G_TYPED_KERNEL(GGoodFeatures,
+                   <cv::GArray<cv::Point2f>(GMat,int,double,double,Mat,int,bool,double)>,
+                   "org.opencv.imgproc.goodFeaturesToTrack") {
+        static GArrayDesc outMeta(GMatDesc, int, double, double, const Mat&, int, bool, double) {
+            return empty_array_desc();
+        }
+    };
+
     G_TYPED_KERNEL(GRGB2YUV, <GMat(GMat)>, "org.opencv.imgproc.colorconvert.rgb2yuv") {
         static GMatDesc outMeta(GMatDesc in) {
             return in; // type still remains CV_8UC3;
@@ -251,7 +259,7 @@ namespace imgproc {
         }
     };
 
-}
+} //namespace imgproc
 
 
 //! @addtogroup gapi_filters
@@ -657,6 +665,59 @@ L2gradient=false ).
 GAPI_EXPORTS GMat Canny(const GMat& image, double threshold1, double threshold2,
                         int apertureSize = 3, bool L2gradient = false);
 
+/** @brief Determines strong corners on an image.
+
+The function finds the most prominent corners in the image or in the specified image region, as
+described in @cite Shi94
+
+-   Function calculates the corner quality measure at every source image pixel using the
+    #cornerMinEigenVal or #cornerHarris .
+-   Function performs a non-maximum suppression (the local maximums in *3 x 3* neighborhood are
+    retained).
+-   The corners with the minimal eigenvalue less than
+    \f$\texttt{qualityLevel} \cdot \max_{x,y} qualityMeasureMap(x,y)\f$ are rejected.
+-   The remaining corners are sorted by the quality measure in the descending order.
+-   Function throws away each corner for which there is a stronger corner at a distance less than
+    maxDistance.
+
+The function can be used to initialize a point-based tracker of an object.
+
+@note If the function is called with different values A and B of the parameter qualityLevel , and
+A \> B, the vector of returned corners with qualityLevel=A will be the prefix of the output vector
+with qualityLevel=B .
+
+@note Function textual ID is "org.opencv.imgproc.goodFeaturesToTrack"
+
+@param image Input 8-bit or floating-point 32-bit, single-channel image.
+@param maxCorners Maximum number of corners to return. If there are more corners than are found,
+the strongest of them is returned. `maxCorners <= 0` implies that no limit on the maximum is set
+and all detected corners are returned.
+@param qualityLevel Parameter characterizing the minimal accepted quality of image corners. The
+parameter value is multiplied by the best corner quality measure, which is the minimal eigenvalue
+(see #cornerMinEigenVal ) or the Harris function response (see #cornerHarris ). The corners with the
+quality measure less than the product are rejected. For example, if the best corner has the
+quality measure = 1500, and the qualityLevel=0.01 , then all the corners with the quality measure
+less than 15 are rejected.
+@param minDistance Minimum possible Euclidean distance between the returned corners.
+@param mask Optional region of interest. If the image is not empty (it needs to have the type
+CV_8UC1 and the same size as image ), it specifies the region in which the corners are detected.
+@param blockSize Size of an average block for computing a derivative covariation matrix over each
+pixel neighborhood. See cornerEigenValsAndVecs .
+@param useHarrisDetector Parameter indicating whether to use a Harris detector (see #cornerHarris)
+or #cornerMinEigenVal.
+@param k Free parameter of the Harris detector.
+
+@return vector of detected corners.
+ */
+GAPI_EXPORTS GArray<Point2f> goodFeaturesToTrack(const GMat  &image,
+                                                       int    maxCorners,
+                                                       double qualityLevel,
+                                                       double minDistance,
+                                                 const Mat   &mask = Mat(),
+                                                       int    blockSize = 3,
+                                                       bool   useHarrisDetector = false,
+                                                       double k = 0.04);
+
 /** @brief Equalizes the histogram of a grayscale image.
 
 The function equalizes the histogram of the input image using the following algorithm:
index c4e5bc6..9d3433d 100644 (file)
@@ -2,7 +2,7 @@
 // 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.
 //
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
 
 
 #ifndef OPENCV_GAPI_IMGPROC_PERF_TESTS_HPP
@@ -33,6 +33,9 @@ class Dilate3x3PerfTest : public TestPerfParams<tuple<compare_f, MatType,cv::Siz
 class SobelPerfTest : public TestPerfParams<tuple<compare_f, MatType,int,cv::Size,int,int,int, cv::GCompileArgs>> {};
 class SobelXYPerfTest : public TestPerfParams<tuple<compare_f, MatType,int,cv::Size,int,int, cv::GCompileArgs>> {};
 class CannyPerfTest : public TestPerfParams<tuple<compare_f, MatType,cv::Size,double,double,int,bool, cv::GCompileArgs>> {};
+class GoodFeaturesPerfTest : public TestPerfParams<tuple<compare_vector_f<cv::Point2f>, std::string,
+                                                         int,int,double,double,int,bool,
+                                                         cv::GCompileArgs>> {};
 class EqHistPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs >> {};
 class RGB2GrayPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs >> {};
 class BGR2GrayPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs >> {};
index 3fea552..cd70d02 100644 (file)
@@ -2,7 +2,7 @@
 // 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.
 //
-// Copyright (C) 2018-2019 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
 
 
 #ifndef OPENCV_GAPI_IMGPROC_PERF_TESTS_INL_HPP
@@ -622,6 +622,53 @@ PERF_TEST_P_(CannyPerfTest, TestPerformance)
 
 //------------------------------------------------------------------------------
 
+PERF_TEST_P_(GoodFeaturesPerfTest, TestPerformance)
+{
+    double k = 0.04;
+
+    compare_vector_f<cv::Point2f> cmpF;
+    std::string fileName = "";
+    int type = -1, maxCorners = -1, blockSize = -1;
+    double qualityLevel = 0.0, minDistance = 0.0;
+    bool useHarrisDetector = false;
+    cv::GCompileArgs compileArgs;
+    std::tie(cmpF, fileName, type, maxCorners, qualityLevel,
+             minDistance, blockSize, useHarrisDetector, compileArgs) = GetParam();
+
+    initMatFromImage(type, fileName);
+    std::vector<cv::Point2f> outVecOCV, outVecGAPI;
+
+    // OpenCV code /////////////////////////////////////////////////////////////
+    {
+        cv::goodFeaturesToTrack(in_mat1, outVecOCV, maxCorners, qualityLevel, minDistance,
+                                cv::noArray(), blockSize, useHarrisDetector, k);
+    }
+
+    // G-API code //////////////////////////////////////////////////////////////
+    cv::GMat in;
+    auto out = cv::gapi::goodFeaturesToTrack(in, maxCorners, qualityLevel, minDistance, cv::Mat(),
+                                             blockSize, useHarrisDetector, k);
+    cv::GComputation c(cv::GIn(in), cv::GOut(out));
+
+    // Warm-up graph engine:
+    c.apply(cv::gin(in_mat1), cv::gout(outVecGAPI), std::move(compileArgs));
+
+    TEST_CYCLE()
+    {
+        c.apply(cv::gin(in_mat1), cv::gout(outVecGAPI));
+    }
+
+    // Comparison //////////////////////////////////////////////////////////////
+    {
+        EXPECT_TRUE(cmpF(outVecGAPI, outVecOCV));
+    }
+
+    SANITY_CHECK_NOTHING();
+
+}
+
+//------------------------------------------------------------------------------
+
 PERF_TEST_P_(EqHistPerfTest, TestPerformance)
 {
     compare_f cmpF = get<0>(GetParam());
index b2e5b3d..3f22703 100644 (file)
@@ -2,7 +2,7 @@
 // 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.
 //
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
 
 
 #include "../perf_precomp.hpp"
@@ -134,6 +134,28 @@ INSTANTIATE_TEST_CASE_P(CannyPerfTestCPU, CannyPerfTest,
         Values(true, false),
         Values(cv::compile_args(IMGPROC_CPU))));
 
+INSTANTIATE_TEST_CASE_P(GoodFeaturesPerfTestCPU, GoodFeaturesPerfTest,
+    Combine(Values(AbsExactVector<cv::Point2f>().to_compare_f()),
+            Values("cv/shared/pic5.png", "stitching/a1.png"),
+            Values(CV_32FC1, CV_8UC1),
+            Values(100, 500),
+            Values(0.1, 0.01),
+            Values(1.0),
+            Values(3, 5),
+            Values(true, false),
+            Values(cv::compile_args(IMGPROC_CPU))));
+
+INSTANTIATE_TEST_CASE_P(GoodFeaturesInternalPerfTestCPU, GoodFeaturesPerfTest,
+    Combine(Values(AbsExactVector<cv::Point2f>().to_compare_f()),
+            Values("cv/cascadeandhog/images/audrybt1.png"),
+            Values(CV_32FC1, CV_8UC1),
+            Values(100),
+            Values(0.0000001),
+            Values(5.0),
+            Values(3),
+            Values(true),
+            Values(cv::compile_args(IMGPROC_CPU))));
+
 INSTANTIATE_TEST_CASE_P(EqHistPerfTestCPU, EqHistPerfTest,
     Combine(Values(AbsExact().to_compare_f()),
         Values(szVGA, sz720p, sz1080p),
index 8168c64..eba26bb 100644 (file)
@@ -2,7 +2,7 @@
 // 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.
 //
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
 
 
 #include "precomp.hpp"
@@ -97,6 +97,14 @@ GMat Canny(const GMat& src, double thr1, double thr2, int apertureSize, bool l2g
     return imgproc::GCanny::on(src, thr1, thr2, apertureSize, l2gradient);
 }
 
+cv::GArray<cv::Point2f> goodFeaturesToTrack(const GMat& image, int maxCorners, double qualityLevel,
+                                            double minDistance, const Mat& mask, int blockSize,
+                                            bool useHarrisDetector, double k)
+{
+    return imgproc::GGoodFeatures::on(image, maxCorners, qualityLevel, minDistance, mask, blockSize,
+                                      useHarrisDetector, k);
+}
+
 GMat RGB2Gray(const GMat& src)
 {
     return imgproc::GRGB2Gray::on(src);
index 29328c4..e10c13f 100644 (file)
@@ -2,7 +2,7 @@
 // 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.
 //
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
 
 
 #include "precomp.hpp"
@@ -182,6 +182,17 @@ GAPI_OCV_KERNEL(GCPUCanny, cv::gapi::imgproc::GCanny)
     }
 };
 
+GAPI_OCV_KERNEL(GCPUGoodFeatures, cv::gapi::imgproc::GGoodFeatures)
+{
+    static void run(const cv::Mat& image, int maxCorners, double qualityLevel, double minDistance,
+                    const cv::Mat& mask, int blockSize, bool useHarrisDetector, double k,
+                    std::vector<cv::Point2f> &out)
+    {
+        cv::goodFeaturesToTrack(image, out, maxCorners, qualityLevel, minDistance,
+                                mask, blockSize, useHarrisDetector, k);
+    }
+};
+
 GAPI_OCV_KERNEL(GCPURGB2YUV, cv::gapi::imgproc::GRGB2YUV)
 {
     static void run(const cv::Mat& in, cv::Mat &out)
@@ -412,6 +423,7 @@ cv::gapi::GKernelPackage cv::gapi::imgproc::cpu::kernels()
         , GCPUSobel
         , GCPUSobelXY
         , GCPUCanny
+        , GCPUGoodFeatures
         , GCPUEqualizeHist
         , GCPURGB2YUV
         , GCPUYUV2RGB
index 1d8bba9..8a786a9 100644 (file)
@@ -2,7 +2,7 @@
 // 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.
 //
-// Copyright (C) 2018-2019 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
 
 
 #ifndef OPENCV_GAPI_CORE_TESTS_HPP
@@ -128,7 +128,7 @@ GAPI_TEST_FIXTURE(PhaseTest, initMatsRandU, FIXTURE_API(bool), 1, angle_in_degre
 GAPI_TEST_FIXTURE(SqrtTest, initMatrixRandU, <>, 0)
 GAPI_TEST_FIXTURE(NormalizeTest, initNothing, FIXTURE_API(CompareMats,double,double,int,MatType2), 5,
     cmpF, a, b, norm_type, ddepth)
-struct BackendOutputAllocationTest : TestWithParamBase<>
+struct BackendOutputAllocationTest : TestWithParams<>
 {
     BackendOutputAllocationTest()
     {
index cba6b2a..165f5d3 100644 (file)
@@ -2,7 +2,7 @@
 // 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.
 //
-// Copyright (C) 2018-2019 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
 
 
 #ifndef OPENCV_GAPI_IMGPROC_TESTS_HPP
@@ -14,6 +14,7 @@
 
 namespace opencv_test
 {
+
 // Create new value-parameterized test fixture:
 // Filter2DTest - fixture name
 // initMatrixRandN - function that is used to initialize input/output data
@@ -52,6 +53,11 @@ GAPI_TEST_FIXTURE(SobelXYTest, initMatrixRandN, FIXTURE_API(CompareMats,int,int,
 GAPI_TEST_FIXTURE(EqHistTest, initMatrixRandN, FIXTURE_API(CompareMats), 1, cmpF)
 GAPI_TEST_FIXTURE(CannyTest, initMatrixRandN, FIXTURE_API(CompareMats,double,double,int,bool), 5,
     cmpF, thrLow, thrUp, apSize, l2gr)
+GAPI_TEST_FIXTURE_SPEC_PARAMS(GoodFeaturesTest,
+                              FIXTURE_API(CompareVectors<cv::Point2f>,std::string,int,int,double,
+                                          double,int,bool),
+                              8, cmpF, fileName, type, maxCorners, qualityLevel, minDistance,
+                              blockSize, useHarrisDetector)
 GAPI_TEST_FIXTURE(RGB2GrayTest, initMatrixRandN, FIXTURE_API(CompareMats), 1, cmpF)
 GAPI_TEST_FIXTURE(BGR2GrayTest, initMatrixRandN, FIXTURE_API(CompareMats), 1, cmpF)
 GAPI_TEST_FIXTURE(RGB2YUVTest, initMatrixRandN, FIXTURE_API(CompareMats), 1, cmpF)
index 3c62ff3..ecc7195 100644 (file)
@@ -2,7 +2,7 @@
 // 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.
 //
-// Copyright (C) 2018-2019 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
 
 
 #ifndef OPENCV_GAPI_IMGPROC_TESTS_INL_HPP
@@ -380,6 +380,34 @@ TEST_P(CannyTest, AccuracyTest)
     }
 }
 
+TEST_P(GoodFeaturesTest, AccuracyTest)
+{
+    double k = 0.04;
+
+    initMatFromImage(type, fileName);
+
+    std::vector<cv::Point2f> outVecOCV, outVecGAPI;
+
+    // G-API code //////////////////////////////////////////////////////////////
+    cv::GMat in;
+    auto out = cv::gapi::goodFeaturesToTrack(in, maxCorners, qualityLevel, minDistance, cv::Mat(),
+                                             blockSize, useHarrisDetector, k);
+
+    cv::GComputation c(cv::GIn(in), cv::GOut(out));
+    c.apply(cv::gin(in_mat1), cv::gout(outVecGAPI), getCompileArgs());
+
+    // OpenCV code /////////////////////////////////////////////////////////////
+    {
+        cv::goodFeaturesToTrack(in_mat1, outVecOCV, maxCorners, qualityLevel, minDistance,
+                                cv::noArray(), blockSize, useHarrisDetector, k);
+    }
+
+    // Comparison //////////////////////////////////////////////////////////////
+    {
+        EXPECT_TRUE(cmpF(outVecGAPI, outVecOCV));
+    }
+}
+
 TEST_P(RGB2GrayTest, AccuracyTest)
 {
     // G-API code //////////////////////////////////////////////////////////////
index 232616d..938a7f7 100644 (file)
@@ -2,7 +2,7 @@
 // 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.
 //
-// Copyright (C) 2018-2019 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
 
 #ifndef OPENCV_GAPI_TESTS_COMMON_HPP
 #define OPENCV_GAPI_TESTS_COMMON_HPP
@@ -56,7 +56,24 @@ namespace
 
         return o;
     }
-}
+
+    inline void initTestDataPath()
+    {
+#ifndef WINRT
+        static bool initialized = false;
+        if (!initialized)
+        {
+            // Since G-API has no own test data (yet), it is taken from the common space
+            const char* testDataPath = getenv("OPENCV_TEST_DATA_PATH");
+            GAPI_Assert(testDataPath != nullptr &&
+            "OPENCV_TEST_DATA_PATH environment variable is either not set or set incorrectly.");
+
+            cvtest::addDataSearchPath(testDataPath);
+            initialized = true;
+        }
+#endif // WINRT
+    }
+} // namespace
 
 namespace opencv_test
 {
@@ -155,6 +172,30 @@ public:
         }
     }
 
+    void initMatFromImage(int type, const std::string& fileName)
+    {
+        initTestDataPath();
+
+        int channels = (type >> CV_CN_SHIFT) + 1;
+        GAPI_Assert(channels == 1 || channels == 3 || channels == 4);
+        const int readFlags = (channels == 1) ? cv::IMREAD_GRAYSCALE : cv::IMREAD_COLOR;
+        cv::Mat mat = cv::imread(findDataFile(fileName), readFlags);
+        if (channels == 4)
+        {
+            cv::cvtColor(mat, in_mat1, cv::COLOR_BGR2BGRA);
+        }
+        else
+        {
+            in_mat1 = mat;
+        }
+
+        int depth = CV_MAT_DEPTH(type);
+        if (in_mat1.depth() != depth)
+        {
+            in_mat1.convertTo(in_mat1, depth);
+        }
+    }
+
     // empty function intended to show that nothing is to be initialized via TestFunctional methods
     void initNothing(int, cv::Size, int, bool = true) {}
 };
@@ -169,6 +210,11 @@ using compare_f = std::function<bool(const cv::Mat &a, const cv::Mat &b)>;
 
 using compare_scalar_f = std::function<bool(const cv::Scalar &a, const cv::Scalar &b)>;
 
+template<typename Elem>
+using compare_vector_f = std::function<bool(const std::vector<Elem> &a,
+                                            const std::vector<Elem> &b)>;
+
+
 // FIXME: re-use MatType. current problem: "special values" interpreted incorrectly (-1 is printed
 //        as 16FC512)
 struct MatType2
@@ -189,14 +235,16 @@ private:
 };
 
 // Universal parameter wrapper for common (pre-defined) and specific (user-defined) parameters
-template<typename ...SpecificParams>
-struct Params
+template<typename CommonParams, typename SpecificParams>
+struct ParamsBase;
+
+template<typename... CommonParams, typename... SpecificParams>
+struct ParamsBase<std::tuple<CommonParams...>, std::tuple<SpecificParams...>>
 {
-    using gcomp_args_function_t = cv::GCompileArgs(*)();
-    using common_params_t = std::tuple<MatType2, cv::Size, MatType2, gcomp_args_function_t>;
+    using common_params_t   = std::tuple<CommonParams...>;
     using specific_params_t = std::tuple<SpecificParams...>;
-    using params_t = std::tuple<MatType2, cv::Size, MatType2, gcomp_args_function_t, SpecificParams...>;
-    static constexpr const size_t common_params_size = std::tuple_size<common_params_t>::value;
+    using params_t          = std::tuple<CommonParams..., SpecificParams...>;
+    static constexpr const size_t common_params_size   = std::tuple_size<common_params_t>::value;
     static constexpr const size_t specific_params_size = std::tuple_size<specific_params_t>::value;
 
     template<size_t I>
@@ -218,17 +266,24 @@ struct Params
     }
 };
 
-// Base class for test fixtures
-template<typename ...SpecificParams>
-struct TestWithParamBase : TestFunctional,
-    TestWithParam<typename Params<SpecificParams...>::params_t>
+template<typename... SpecificParams>
+struct Params : public ParamsBase<std::tuple<MatType2,cv::Size,MatType2,cv::GCompileArgs(*)()>,
+                                  std::tuple<SpecificParams...>>
 {
-    using AllParams = Params<SpecificParams...>;
+    static constexpr const size_t compile_args_num = 3;
+};
 
-    MatType2 type = getCommonParam<0>();
-    cv::Size sz = getCommonParam<1>();
-    MatType2 dtype = getCommonParam<2>();
+template<typename ...SpecificParams>
+struct ParamsSpecific : public ParamsBase<std::tuple<cv::GCompileArgs(*)()>,
+                                          std::tuple<SpecificParams...>>
+{
+    static constexpr const size_t compile_args_num = 0;
+};
 
+// Base class for test fixtures
+template<typename AllParams>
+struct TestWithParamsBase : TestFunctional, TestWithParam<typename AllParams::params_t>
+{
     // Get common (pre-defined) parameter value by index
     template<size_t I>
     inline auto getCommonParam() const
@@ -248,13 +303,30 @@ struct TestWithParamBase : TestFunctional,
     // Return G-API compile arguments specified for test fixture
     inline cv::GCompileArgs getCompileArgs() const
     {
-        return getCommonParam<3>()();
+        return getCommonParam<AllParams::compile_args_num>()();
     }
 };
 
+template<typename... SpecificParams>
+struct TestWithParams : public TestWithParamsBase<Params<SpecificParams...>>
+{
+    using AllParams = Params<SpecificParams...>;
+
+    MatType2 type  = this->template getCommonParam<0>();
+    cv::Size sz    = this->template getCommonParam<1>();
+    MatType2 dtype = this->template getCommonParam<2>();
+};
+
+template<typename... SpecificParams>
+struct TestWithParamsSpecific : public TestWithParamsBase<ParamsSpecific<SpecificParams...>>
+{
+    using AllParams = ParamsSpecific<SpecificParams...>;
+};
+
+
 /**
  * @private
- * @brief Create G-API test fixture with TestWithParamBase base class
+ * @brief Create G-API test fixture with TestWithParams base class
  * @param Fixture   test fixture name
  * @param InitF     callable that will initialize default available members (from TestFunctional)
  * @param API       base class API. Specifies types of user-defined parameters. If there are no such
@@ -265,13 +337,33 @@ struct TestWithParamBase : TestFunctional,
  *                  must be empty.
  */
 #define GAPI_TEST_FIXTURE(Fixture, InitF, API, Number, ...) \
-    struct Fixture : public TestWithParamBase API { \
+    struct Fixture : public TestWithParams API { \
         static_assert(Number == AllParams::specific_params_size, \
             "Number of user-defined parameters doesn't match size of __VA_ARGS__"); \
         __WRAP_VAARGS(DEFINE_SPECIFIC_PARAMS_##Number(__VA_ARGS__)) \
         Fixture() { InitF(type, sz, dtype); } \
     };
 
+/**
+ * @private
+ * @brief Create G-API test fixture with TestWithParamsSpecific base class
+ *        This fixture has reduced number of common parameters and no initialization;
+ *        it should be used if you don't need common parameters of GAPI_TEST_FIXTURE.
+ * @param Fixture   test fixture name
+ * @param API       base class API. Specifies types of user-defined parameters. If there are no such
+ *                  parameters, empty angle brackets ("<>") must be specified.
+ * @param Number    number of user-defined parameters (corresponds to the number of types in API).
+ *                  if there are no such parameters, 0 must be specified.
+ * @param ...       list of names of user-defined parameters. if there are no parameters, the list
+ *                  must be empty.
+ */
+#define GAPI_TEST_FIXTURE_SPEC_PARAMS(Fixture, API, Number, ...) \
+    struct Fixture : public TestWithParamsSpecific API { \
+        static_assert(Number == AllParams::specific_params_size, \
+            "Number of user-defined parameters doesn't match size of __VA_ARGS__"); \
+        __WRAP_VAARGS(DEFINE_SPECIFIC_PARAMS_##Number(__VA_ARGS__)) \
+    };
+
 // Wrapper for test fixture API. Use to specify multiple types.
 // Example: FIXTURE_API(int, bool) expands to <int, bool>
 #define FIXTURE_API(...) <__VA_ARGS__>
@@ -298,6 +390,9 @@ private:
 using CompareMats = CompareF<cv::Mat, cv::Mat>;
 using CompareScalars = CompareF<cv::Scalar, cv::Scalar>;
 
+template<typename Elem>
+using CompareVectors = CompareF<std::vector<Elem>, std::vector<Elem>>;
+
 template<typename T>
 struct Wrappable
 {
@@ -340,6 +435,28 @@ struct WrappableScalar
     }
 };
 
+template<typename T, typename Elem>
+struct WrappableVector
+{
+    compare_vector_f<Elem> to_compare_f()
+    {
+        T t = *static_cast<T* const>(this);
+        return [t](const std::vector<Elem>& a,
+                   const std::vector<Elem>& b)
+        {
+            return t(a, b);
+        };
+    }
+
+    CompareVectors<Elem> to_compare_obj()
+    {
+        T t = *static_cast<T* const>(this);
+        std::stringstream ss;
+        ss << t;
+        return CompareVectors<Elem>(to_compare_f(), ss.str());
+    }
+};
+
 
 class AbsExact : public Wrappable<AbsExact>
 {
@@ -547,6 +664,31 @@ public:
 private:
     double _tol;
 };
+
+template<typename Elem>
+class AbsExactVector : public WrappableVector<AbsExactVector<Elem>, Elem>
+{
+public:
+    AbsExactVector() {}
+    bool operator() (const std::vector<Elem>& in1,
+                     const std::vector<Elem>& in2) const
+    {
+        if (cv::norm(in1, in2, NORM_INF, cv::noArray()) != 0)
+        {
+            std::cout << "AbsExact error: G-API output and reference output vectors are not"
+                         " bitexact equal." << std::endl;
+            return false;
+        }
+        else
+        {
+            return true;
+        }
+    }
+    friend std::ostream& operator<<(std::ostream& os, const AbsExactVector<Elem>&)
+    {
+        return os << "AbsExactVector()";
+    }
+};
 } // namespace opencv_test
 
 namespace
@@ -560,6 +702,12 @@ inline std::ostream& operator<<(std::ostream& os, const opencv_test::compare_sca
 {
     return os << "compare_scalar_f";
 }
+
+template<typename Elem>
+inline std::ostream& operator<<(std::ostream& os, const opencv_test::compare_vector_f<Elem>&)
+{
+    return os << "compare_vector_f";
+}
 }  // anonymous namespace
 
 // Note: namespace must match the namespace of the type of the printed object
index 5658c6d..937aef9 100644 (file)
@@ -2,7 +2,7 @@
 // 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.
 //
-// Copyright (C) 2018-2019 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
 
 
 #include "../test_precomp.hpp"
@@ -196,6 +196,29 @@ INSTANTIATE_TEST_CASE_P(CannyTestCPU, CannyTest,
                                 Values(3, 5),
                                 testing::Bool()));
 
+INSTANTIATE_TEST_CASE_P(GoodFeaturesTestCPU, GoodFeaturesTest,
+                        Combine(Values(IMGPROC_CPU),
+                                Values(AbsExactVector<cv::Point2f>().to_compare_obj()),
+                                Values("cv/shared/fruits.png"),
+                                Values(CV_32FC1, CV_8UC1),
+                                Values(50, 100),
+                                Values(0.01),
+                                Values(10.0),
+                                Values(3),
+                                testing::Bool()));
+
+INSTANTIATE_TEST_CASE_P(GoodFeaturesInternalTestCPU, GoodFeaturesTest,
+                        Combine(Values(IMGPROC_CPU),
+                                Values(AbsExactVector<cv::Point2f>().to_compare_obj()),
+                                Values("cv/cascadeandhog/images/audrybt1.png"),
+                                Values(CV_32FC1, CV_8UC1),
+                                Values(100),
+                                Values(0.0000001),
+                                Values(5.0),
+                                Values(3),
+                                Values(true)));
+
+
 INSTANTIATE_TEST_CASE_P(RGB2GrayTestCPU, RGB2GrayTest,
                         Combine(Values(CV_8UC3),
                                 Values(cv::Size(1280, 720),