From 9390c56831270a94af6480feb4cc330e4aa2ee5e Mon Sep 17 00:00:00 2001 From: Anatoliy Talamanov Date: Fri, 1 Apr 2022 00:00:45 +0300 Subject: [PATCH] Merge pull request #21782 from TolyaTalamanov:at/fix-1d-mat-problems [G-API] Fix problems with 1D cv::Mat as graph output * Fix issues with 1D cv::Mat * Fix cv::Mat::create * Fix standalone build * Add test on 1d mat * Fix warning * Add additional condition * Add more tests --- modules/core/src/matrix.cpp | 2 + modules/core/test/test_mat.cpp | 11 +++ .../pipeline_builder.hpp | 3 +- modules/gapi/src/api/gbackend.cpp | 6 ++ modules/gapi/test/gapi_sample_pipelines.cpp | 83 +++++++++++++++++++ 5 files changed, 104 insertions(+), 1 deletion(-) diff --git a/modules/core/src/matrix.cpp b/modules/core/src/matrix.cpp index 6a381c15a0..8111dc2230 100644 --- a/modules/core/src/matrix.cpp +++ b/modules/core/src/matrix.cpp @@ -664,6 +664,8 @@ void Mat::create(int d, const int* _sizes, int _type) if( data && (d == dims || (d == 1 && dims <= 2)) && _type == type() ) { + if ( dims == 1 && (d == 1 && _sizes[0] == size[0]) ) + return; if( d == 2 && rows == _sizes[0] && cols == _sizes[1] ) return; for( i = 0; i < d; i++ ) diff --git a/modules/core/test/test_mat.cpp b/modules/core/test/test_mat.cpp index 6c885a4dce..61ba306ba6 100644 --- a/modules/core/test/test_mat.cpp +++ b/modules/core/test/test_mat.cpp @@ -2461,5 +2461,16 @@ TEST(Mat, reverse_iterator_19967) } +TEST(Mat, Recreate1DMatWithSameMeta) +{ + std::vector dims = {100}; + auto depth = CV_8U; + cv::Mat m(dims, depth); + + // By default m has dims: [1, 100] + m.dims = 1; + + EXPECT_NO_THROW(m.create(dims, depth)); +} }} // namespace diff --git a/modules/gapi/samples/pipeline_modeling_tool/pipeline_builder.hpp b/modules/gapi/samples/pipeline_modeling_tool/pipeline_builder.hpp index 3906ae4f4c..a3f187249d 100644 --- a/modules/gapi/samples/pipeline_modeling_tool/pipeline_builder.hpp +++ b/modules/gapi/samples/pipeline_modeling_tool/pipeline_builder.hpp @@ -133,7 +133,8 @@ struct DummyCall { if (output.dims.size() == 2) { return cv::GMatDesc(output.precision, 1, - cv::Size(output.dims[0], output.dims[1])); + // NB: Dims[H, W] -> Size(W, H) + cv::Size(output.dims[1], output.dims[0])); } return cv::GMatDesc(output.precision, output.dims); } diff --git a/modules/gapi/src/api/gbackend.cpp b/modules/gapi/src/api/gbackend.cpp index f063dd0eb9..e3b1e7123d 100644 --- a/modules/gapi/src/api/gbackend.cpp +++ b/modules/gapi/src/api/gbackend.cpp @@ -411,6 +411,12 @@ void createMat(const cv::GMatDesc &desc, cv::Mat& mat) { GAPI_Assert(!desc.planar); mat.create(desc.dims, desc.depth); +#if !defined(GAPI_STANDALONE) + // NB: WA for 1D mats. + if (desc.dims.size() == 1u) { + mat.dims = 1; + } +#endif } } diff --git a/modules/gapi/test/gapi_sample_pipelines.cpp b/modules/gapi/test/gapi_sample_pipelines.cpp index b4d9f3e100..e48d36b3ac 100644 --- a/modules/gapi/test/gapi_sample_pipelines.cpp +++ b/modules/gapi/test/gapi_sample_pipelines.cpp @@ -49,6 +49,24 @@ namespace static GMatDesc outMeta(GMatDesc in) { return in; } }; + G_TYPED_KERNEL(GZeros, , "org.opencv.test.zeros") + { + static GMatDesc outMeta(GMatDesc /*in*/, GMatDesc user_desc) + { + return user_desc; + } + }; + + GAPI_OCV_KERNEL(GOCVZeros, GZeros) + { + static void run(const cv::Mat& /*in*/, + const cv::GMatDesc& /*desc*/, + cv::Mat& out) + { + out.setTo(0); + } + }; + // These definitons test the correct macro work if the kernel has multiple output values G_TYPED_KERNEL(GRetGArrayTupleOfGMat2Kernel, >(GMat, Scalar)>, "org.opencv.test.retarrayoftupleofgmat2kernel") {}; G_TYPED_KERNEL(GRetGArraTupleyOfGMat3Kernel, >(GMat)>, "org.opencv.test.retarrayoftupleofgmat3kernel") {}; @@ -430,4 +448,69 @@ TEST(GAPI_Pipeline, ReplaceDefaultByFunctor) EXPECT_TRUE(f.is_called); } +TEST(GAPI_Pipeline, GraphOutputIs1DMat) +{ + int dim = 100; + cv::Mat in_mat(1, 1, CV_8UC3); + cv::Mat out_mat; + + cv::GMat in; + auto cc = cv::GComputation(in, GZeros::on(in, cv::GMatDesc(CV_8U, {dim}))) + .compile(cv::descr_of(in_mat), cv::compile_args(cv::gapi::kernels())); + + // NB: Computation is able to write 1D output cv::Mat to empty out_mat. + ASSERT_NO_THROW(cc(cv::gin(in_mat), cv::gout(out_mat))); + ASSERT_EQ(1, out_mat.size.dims()); + ASSERT_EQ(dim, out_mat.size[0]); + + // NB: Computation is able to write 1D output cv::Mat + // to pre-allocated with the same meta out_mat. + ASSERT_NO_THROW(cc(cv::gin(in_mat), cv::gout(out_mat))); + ASSERT_EQ(1, out_mat.size.dims()); + ASSERT_EQ(dim, out_mat.size[0]); +} + +TEST(GAPI_Pipeline, 1DMatBetweenIslands) +{ + int dim = 100; + cv::Mat in_mat(1, 1, CV_8UC3); + cv::Mat out_mat; + + cv::Mat ref_mat({dim}, CV_8U); + ref_mat.dims = 1; + ref_mat.setTo(0); + + cv::GMat in; + auto out = cv::gapi::copy(GZeros::on(cv::gapi::copy(in), cv::GMatDesc(CV_8U, {dim}))); + auto cc = cv::GComputation(in, out) + .compile(cv::descr_of(in_mat), cv::compile_args(cv::gapi::kernels())); + + cc(cv::gin(in_mat), cv::gout(out_mat)); + + EXPECT_EQ(0, cv::norm(out_mat, ref_mat)); +} + +TEST(GAPI_Pipeline, 1DMatWithinSingleIsland) +{ + int dim = 100; + cv::Size blur_sz(3, 3); + cv::Mat in_mat(10, 10, CV_8UC3); + cv::randu(in_mat, 0, 255); + cv::Mat out_mat; + + cv::Mat ref_mat({dim}, CV_8U); + ref_mat.dims = 1; + ref_mat.setTo(0); + + cv::GMat in; + auto out = cv::gapi::blur( + GZeros::on(cv::gapi::blur(in, blur_sz), cv::GMatDesc(CV_8U, {dim})), blur_sz); + auto cc = cv::GComputation(in, out) + .compile(cv::descr_of(in_mat), cv::compile_args(cv::gapi::kernels())); + + cc(cv::gin(in_mat), cv::gout(out_mat)); + + EXPECT_EQ(0, cv::norm(out_mat, ref_mat)); +} + } // namespace opencv_test