Merge pull request #20107 from sivanov-work:gapi_transpose_op
authorSergey Ivanov <sergey.ivanov@intel.com>
Tue, 25 May 2021 17:36:01 +0000 (20:36 +0300)
committerGitHub <noreply@github.com>
Tue, 25 May 2021 17:36:01 +0000 (20:36 +0300)
G-API: Add transpose operation

* Add kernels decl & def

* Add draft for UT

* Fix UT for Transpose

* Add perf test

* Fix docs

* Apply comments

13 files changed:
modules/gapi/include/opencv2/gapi/core.hpp
modules/gapi/perf/common/gapi_core_perf_tests.hpp
modules/gapi/perf/common/gapi_core_perf_tests_inl.hpp
modules/gapi/perf/cpu/gapi_core_perf_tests_cpu.cpp
modules/gapi/perf/gpu/gapi_core_perf_tests_gpu.cpp
modules/gapi/src/api/kernels_core.cpp
modules/gapi/src/backends/cpu/gcpucore.cpp
modules/gapi/src/backends/ocl/goclcore.cpp
modules/gapi/test/common/gapi_core_tests.hpp
modules/gapi/test/common/gapi_core_tests_inl.hpp
modules/gapi/test/common/gapi_tests_common.hpp
modules/gapi/test/cpu/gapi_core_tests_cpu.cpp
modules/gapi/test/gpu/gapi_core_tests_gpu.cpp

index 5973151..cb8a612 100644 (file)
@@ -575,6 +575,12 @@ namespace core {
             return std::make_tuple(empty_gopaque_desc(), empty_array_desc(), empty_array_desc());
         }
     };
+
+    G_TYPED_KERNEL(GTranspose, <GMat(GMat)>, "org.opencv.core.transpose") {
+        static GMatDesc outMeta(GMatDesc in) {
+            return in.withSize({in.size.height, in.size.width});
+        }
+    };
 } // namespace core
 
 namespace streaming {
@@ -1927,6 +1933,21 @@ GAPI_EXPORTS std::tuple<GOpaque<double>,GArray<int>,GArray<Point3f>>
 kmeans(const GArray<Point3f>& data, const int K, const GArray<int>& bestLabels,
        const TermCriteria& criteria, const int attempts, const KmeansFlags flags);
 
+
+/** @brief Transposes a matrix.
+
+The function transposes the matrix:
+\f[\texttt{dst} (i,j) =  \texttt{src} (j,i)\f]
+
+@note
+ - Function textual ID is "org.opencv.core.transpose"
+ - No complex conjugation is done in case of a complex matrix. It should be done separately if needed.
+
+@param src input array.
+*/
+GAPI_EXPORTS GMat transpose(const GMat& src);
+
+
 namespace streaming {
 /** @brief Gets dimensions from Mat.
 
index be88e5a..3fd543b 100644 (file)
@@ -79,6 +79,7 @@ namespace opencv_test
                                                          cv::GCompileArgs>> {};
     class KMeans3DPerfTest : public TestPerfParams<tuple<int, int, cv::KmeansFlags,
                                                          cv::GCompileArgs>> {};
+    class TransposePerfTest : public TestPerfParams<tuple<compare_f, cv::Size, MatType, cv::GCompileArgs>> {};
     class ResizePerfTest : public TestPerfParams<tuple<compare_f, MatType, int, cv::Size, cv::Size, cv::GCompileArgs>> {};
     class ResizeFxFyPerfTest : public TestPerfParams<tuple<compare_f, MatType, int, cv::Size, double, double, cv::GCompileArgs>> {};
     class ParseSSDBLPerfTest : public TestPerfParams<tuple<cv::Size, float, int, cv::GCompileArgs>>, public ParserSSDTest {};
index 7fe0ec4..6dfc0b2 100644 (file)
@@ -2036,6 +2036,42 @@ PERF_TEST_P_(KMeans3DPerfTest, TestPerformance)
 
 //------------------------------------------------------------------------------
 
+PERF_TEST_P_(TransposePerfTest, TestPerformance)
+{
+    compare_f cmpF;
+    cv::Size sz_in;
+    MatType type = -1;
+    cv::GCompileArgs compile_args;
+    std::tie(cmpF, sz_in, type, compile_args) = GetParam();
+
+    initMatrixRandU(type, sz_in, type, false);
+
+    // OpenCV code ///////////////////////////////////////////////////////////
+    cv::transpose(in_mat1, out_mat_ocv);
+
+    // G-API code ////////////////////////////////////////////////////////////
+    cv::GMat in;
+    auto out = cv::gapi::transpose(in);
+    cv::GComputation c(cv::GIn(in), cv::GOut(out));
+
+    // Warm-up graph engine:
+    c.apply(cv::gin(in_mat1), cv::gout(out_mat_gapi), std::move(compile_args));
+
+    TEST_CYCLE()
+    {
+        c.apply(cv::gin(in_mat1), cv::gout(out_mat_gapi));
+    }
+
+    // Comparison ////////////////////////////////////////////////////////////
+    {
+        EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
+    }
+
+    SANITY_CHECK_NOTHING();
+}
+
+//------------------------------------------------------------------------------
+
 PERF_TEST_P_(ResizePerfTest, TestPerformance)
 {
     compare_f cmpF = get<0>(GetParam());
index 8385169..871d417 100644 (file)
@@ -311,6 +311,14 @@ INSTANTIATE_TEST_CASE_P(KMeans3DPerfTestCPU, KMeans3DPerfTest,
                                        cv::KMEANS_PP_CENTERS     | cv::KMEANS_USE_INITIAL_LABELS),
                                 Values(cv::compile_args(CORE_CPU))));
 
+INSTANTIATE_TEST_CASE_P(TransposePerfTestCPU, TransposePerfTest,
+                        Combine(Values(AbsExact().to_compare_f()),
+                                Values(szSmall128, szVGA, sz720p, sz1080p),
+                                Values(CV_8UC1, CV_16UC1, CV_16SC1, CV_32FC1,
+                                       CV_8UC2, CV_16UC2, CV_16SC2, CV_32FC2,
+                                       CV_8UC3, CV_16UC3, CV_16SC3, CV_32FC3),
+                                Values(cv::compile_args(CORE_CPU))));
+
 INSTANTIATE_TEST_CASE_P(ResizePerfTestCPU, ResizePerfTest,
     Combine(Values(AbsExact().to_compare_f()),
         Values(CV_8UC1, CV_16UC1, CV_16SC1),
index 9557996..4a38fdb 100644 (file)
@@ -276,6 +276,14 @@ INSTANTIATE_TEST_CASE_P(ConvertToPerfTestGPU, ConvertToPerfTest,
                                 Values(0.0),
                                 Values(cv::compile_args(CORE_GPU))));
 
+INSTANTIATE_TEST_CASE_P(TransposePerfTestGPU, TransposePerfTest,
+                        Combine(Values(AbsExact().to_compare_f()),
+                                Values(szSmall128, szVGA, sz720p, sz1080p),
+                                Values(CV_8UC1, CV_16UC1, CV_16SC1, CV_32FC1,
+                                       CV_8UC2, CV_16UC2, CV_16SC2, CV_32FC2,
+                                       CV_8UC3, CV_16UC3, CV_16SC3, CV_32FC3),
+                                Values(cv::compile_args(CORE_GPU))));
+
 INSTANTIATE_TEST_CASE_P(ResizePerfTestGPU, ResizePerfTest,
                         Combine(Values(AbsSimilarPoints(2, 0.05).to_compare_f()),
                                 Values(CV_8UC1, CV_16UC1, CV_16SC1),
index 3196b5d..4485e36 100644 (file)
@@ -417,6 +417,12 @@ std::tuple<GOpaque<double>,GArray<int>,GArray<Point3f>> kmeans(const GArray<Poin
     return core::GKMeans3D::on(data, K, bestLabels, criteria, attempts, flags);
 }
 
+
+GMat transpose(const GMat& src)
+{
+    return core::GTranspose::on(src);
+}
+
 GOpaque<Size> streaming::size(const GMat& src)
 {
     return streaming::GSize::on(src);
index b0bce41..168a2f9 100644 (file)
@@ -634,6 +634,15 @@ GAPI_OCV_KERNEL(GCPUKMeans3D, cv::gapi::core::GKMeans3D)
     }
 };
 
+GAPI_OCV_KERNEL(GCPUTranspose, cv::gapi::core::GTranspose)
+{
+    static void run(const cv::Mat& in, cv::Mat& out)
+    {
+        cv::transpose(in, out);
+    }
+};
+
+
 GAPI_OCV_KERNEL(GCPUParseSSDBL, cv::gapi::nn::parsers::GParseSSDBL)
 {
     static void run(const cv::Mat&  in_ssd_result,
@@ -774,6 +783,7 @@ cv::gapi::GKernelPackage cv::gapi::core::cpu::kernels()
          , GCPUKMeansNDNoInit
          , GCPUKMeans2D
          , GCPUKMeans3D
+         , GCPUTranspose
          , GCPUParseSSDBL
          , GOCVParseSSD
          , GCPUParseYolo
index afe211d..d74d521 100644 (file)
@@ -522,6 +522,15 @@ GAPI_OCL_KERNEL(GOCLConvertTo, cv::gapi::core::GConvertTo)
     }
 };
 
+
+GAPI_OCL_KERNEL(GOCLTranspose, cv::gapi::core::GTranspose)
+{
+    static void run(const cv::UMat& in,  cv::UMat& out)
+    {
+        cv::transpose(in, out);
+    }
+};
+
 cv::gapi::GKernelPackage cv::gapi::core::ocl::kernels()
 {
     static auto pkg = cv::gapi::kernels
@@ -586,6 +595,7 @@ cv::gapi::GKernelPackage cv::gapi::core::ocl::kernels()
          , GOCLConcatVert
          , GOCLLUT
          , GOCLConvertTo
+         , GOCLTranspose
          >();
     return pkg;
 }
index e878282..0d8015e 100644 (file)
@@ -154,6 +154,8 @@ GAPI_TEST_FIXTURE(WarpAffineTest, initMatrixRandU,
 GAPI_TEST_FIXTURE(KMeansNDTest, initMatrixRandU, FIXTURE_API(CompareMats, int, cv::KmeansFlags), 3, cmpF, K, flags)
 GAPI_TEST_FIXTURE(KMeans2DTest, initNothing,     FIXTURE_API(int, cv::KmeansFlags), 2, K, flags)
 GAPI_TEST_FIXTURE(KMeans3DTest, initNothing,     FIXTURE_API(int, cv::KmeansFlags), 2, K, flags)
+GAPI_TEST_FIXTURE(TransposeTest, initMatrixRandU, FIXTURE_API(CompareMats), 1, cmpF)
+
 
 GAPI_TEST_EXT_BASE_FIXTURE(ParseSSDBLTest, ParserSSDTest, initNothing,
     FIXTURE_API(float, int), 2, confidence_threshold, filter_label)
index d4760e8..d9287a1 100644 (file)
@@ -1403,6 +1403,23 @@ TEST_P(KMeans3DTest, AccuracyTest)
     kmeansTestBody(in_vector, sz, type, K, flags, getCompileArgs());
 }
 
+TEST_P(TransposeTest, Test)
+{
+    // G-API code //////////////////////////////////////////////////////////////
+    cv::GMat in;
+    auto out = cv::gapi::transpose(in);
+
+    cv::GComputation c(in, out);
+    c.apply(in_mat1, out_mat_gapi, getCompileArgs());
+    // OpenCV code /////////////////////////////////////////////////////////////
+    {
+        cv::transpose(in_mat1, out_mat_ocv);
+    }
+    // Comparison //////////////////////////////////////////////////////////////
+    {
+        EXPECT_TRUE(cmpF(out_mat_ocv, out_mat_gapi));
+    }
+}
 // PLEASE DO NOT PUT NEW ACCURACY TESTS BELOW THIS POINT! //////////////////////
 
 TEST_P(BackendOutputAllocationTest, EmptyOutput)
index 7775749..463e994 100644 (file)
@@ -542,6 +542,7 @@ struct TestWithParamsSpecific : public TestWithParamsBase<ParamsSpecific<Specifi
  * @param ...       list of names of user-defined parameters. if there are no parameters, the list
  *                  must be empty.
  */
+ //TODO: Consider to remove `Number` and use `std::tuple_size<decltype(std::make_tuple(__VA_ARGS__))>::value`
 #define GAPI_TEST_FIXTURE(Fixture, InitF, API, Number, ...) \
     struct Fixture : public TestWithParams API { \
         static_assert(Number == AllParams::specific_params_size, \
index 5a06671..424cf1b 100644 (file)
@@ -551,6 +551,16 @@ INSTANTIATE_TEST_CASE_P(KMeans3DInitTestCPU, KMeans3DTest,
                                 Values(cv::KMEANS_RANDOM_CENTERS | cv::KMEANS_USE_INITIAL_LABELS,
                                        cv::KMEANS_PP_CENTERS     | cv::KMEANS_USE_INITIAL_LABELS)));
 
+INSTANTIATE_TEST_CASE_P(TransposeTestCPU, TransposeTest,
+                        Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1, CV_32FC1,
+                                       CV_8UC2, CV_16UC2, CV_16SC2, CV_32FC2,
+                                       CV_8UC3, CV_16UC3, CV_16SC3, CV_32FC3),
+                                Values(cv::Size(1280, 720),
+                                       cv::Size(640, 480),
+                                       cv::Size(128, 128)),
+                                Values(-1),
+                                Values(CORE_CPU),
+                                Values(AbsExact().to_compare_obj())));
 // PLEASE DO NOT PUT NEW ACCURACY TESTS BELOW THIS POINT! //////////////////////
 
 INSTANTIATE_TEST_CASE_P(BackendOutputAllocationTestCPU, BackendOutputAllocationTest,
index 4e5efe6..2cc859c 100644 (file)
@@ -402,6 +402,16 @@ INSTANTIATE_TEST_CASE_P(ConcatVertTestGPU, ConcatVertTest,
                                 Values(-1),
                                 Values(CORE_GPU)));
 
+INSTANTIATE_TEST_CASE_P(TransposeTestGPU, TransposeTest,
+                        Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1, CV_32FC1,
+                                       CV_8UC2, CV_16UC2, CV_16SC2, CV_32FC2,
+                                       CV_8UC3, CV_16UC3, CV_16SC3, CV_32FC3),
+                                Values(cv::Size(1280, 720),
+                                       cv::Size(640, 480),
+                                       cv::Size(128, 128)),
+                                Values(-1),
+                                Values(CORE_GPU),
+                                Values(AbsExact().to_compare_obj())));
 // PLEASE DO NOT PUT NEW ACCURACY TESTS BELOW THIS POINT! //////////////////////
 
 INSTANTIATE_TEST_CASE_P(BackendOutputAllocationTestGPU, BackendOutputAllocationTest,