diff --git a/modules/gapi/include/opencv2/gapi/imgproc.hpp b/modules/gapi/include/opencv2/gapi/imgproc.hpp index b5a2b82507..31dee7d11d 100644 --- a/modules/gapi/include/opencv2/gapi/imgproc.hpp +++ b/modules/gapi/include/opencv2/gapi/imgproc.hpp @@ -27,6 +27,7 @@ namespace cv { namespace gapi { namespace imgproc { + using GMat2 = std::tuple; using GMat3 = std::tuple; // FIXME: how to avoid this? G_TYPED_KERNEL(GFilter2D, ,"org.opencv.imgproc.filters.filter2D") { @@ -83,6 +84,12 @@ namespace imgproc { } }; + G_TYPED_KERNEL_M(GSobelXY, , "org.opencv.imgproc.filters.sobelxy") { + static std::tuple outMeta(GMatDesc in, int ddepth, int, int, double, double, int, Scalar) { + return std::make_tuple(in.withDepth(ddepth), in.withDepth(ddepth)); + } + }; + G_TYPED_KERNEL(GEqHist, , "org.opencv.imgproc.equalizeHist"){ static GMatDesc outMeta(GMatDesc in) { return in.withType(CV_8U, 1); @@ -487,6 +494,58 @@ GAPI_EXPORTS GMat Sobel(const GMat& src, int ddepth, int dx, int dy, int ksize = int borderType = BORDER_DEFAULT, const Scalar& borderValue = Scalar(0)); +/** @brief Calculates the first, second, third, or mixed image derivatives using an extended Sobel operator. + +In all cases except one, the \f$\texttt{ksize} \times \texttt{ksize}\f$ separable kernel is used to +calculate the derivative. When \f$\texttt{ksize = 1}\f$, the \f$3 \times 1\f$ or \f$1 \times 3\f$ +kernel is used (that is, no Gaussian smoothing is done). `ksize = 1` can only be used for the first +or the second x- or y- derivatives. + +There is also the special value `ksize = FILTER_SCHARR (-1)` that corresponds to the \f$3\times3\f$ Scharr +filter that may give more accurate results than the \f$3\times3\f$ Sobel. The Scharr aperture is + +\f[\vecthreethree{-3}{0}{3}{-10}{0}{10}{-3}{0}{3}\f] + +for the x-derivative, or transposed for the y-derivative. + +The function calculates an image derivative by convolving the image with the appropriate kernel: + +\f[\texttt{dst} = \frac{\partial^{xorder+yorder} \texttt{src}}{\partial x^{xorder} \partial y^{yorder}}\f] + +The Sobel operators combine Gaussian smoothing and differentiation, so the result is more or less +resistant to the noise. Most often, the function is called with ( xorder = 1, yorder = 0, ksize = 3) +or ( xorder = 0, yorder = 1, ksize = 3) to calculate the first x- or y- image derivative. The first +case corresponds to a kernel of: + +\f[\vecthreethree{-1}{0}{1}{-2}{0}{2}{-1}{0}{1}\f] + +The second case corresponds to a kernel of: + +\f[\vecthreethree{-1}{-2}{-1}{0}{0}{0}{1}{2}{1}\f] + +@note First returned matrix correspons to dx derivative while the second one to dy. + +@note Rounding to nearest even is procedeed if hardware supports it, if not - to nearest. + +@note Function textual ID is "org.opencv.imgproc.filters.sobelxy" + +@param src input image. +@param ddepth output image depth, see @ref filter_depths "combinations"; in the case of + 8-bit input images it will result in truncated derivatives. +@param order order of the derivatives. +@param ksize size of the extended Sobel kernel; it must be odd. +@param scale optional scale factor for the computed derivative values; by default, no scaling is +applied (see cv::getDerivKernels for details). +@param delta optional delta value that is added to the results prior to storing them in dst. +@param borderType pixel extrapolation method, see cv::BorderTypes +@param borderValue border value in case of constant border type +@sa filter2D, gaussianBlur, cartToPolar + */ +GAPI_EXPORTS std::tuple SobelXY(const GMat& src, int ddepth, int order, int ksize = 3, + double scale = 1, double delta = 0, + int borderType = BORDER_DEFAULT, + const Scalar& borderValue = Scalar(0)); + /** @brief Finds edges in an image using the Canny algorithm. The function finds edges in the input image and marks them in the output map edges using the diff --git a/modules/gapi/perf/common/gapi_imgproc_perf_tests.hpp b/modules/gapi/perf/common/gapi_imgproc_perf_tests.hpp index 750c0692c8..154f7d3151 100644 --- a/modules/gapi/perf/common/gapi_imgproc_perf_tests.hpp +++ b/modules/gapi/perf/common/gapi_imgproc_perf_tests.hpp @@ -31,6 +31,7 @@ class Erode3x3PerfTest : public TestPerfParams> {}; class Dilate3x3PerfTest : public TestPerfParams> {}; class SobelPerfTest : public TestPerfParams> {}; +class SobelXYPerfTest : public TestPerfParams> {}; class CannyPerfTest : public TestPerfParams> {}; class EqHistPerfTest : public TestPerfParams> {}; class RGB2GrayPerfTest : public TestPerfParams> {}; diff --git a/modules/gapi/perf/common/gapi_imgproc_perf_tests_inl.hpp b/modules/gapi/perf/common/gapi_imgproc_perf_tests_inl.hpp index 89ebf0405d..3f364d6d76 100644 --- a/modules/gapi/perf/common/gapi_imgproc_perf_tests_inl.hpp +++ b/modules/gapi/perf/common/gapi_imgproc_perf_tests_inl.hpp @@ -498,6 +498,52 @@ PERF_TEST_P_(SobelPerfTest, TestPerformance) //------------------------------------------------------------------------------ +PERF_TEST_P_(SobelXYPerfTest, TestPerformance) +{ + compare_f cmpF; + MatType type = 0; + int kernSize = 0, dtype = 0, order = 0; + cv::Size sz; + cv::GCompileArgs compile_args; + std::tie(cmpF, type, kernSize, sz, dtype, order, compile_args) = GetParam(); + + cv::Mat out_mat_ocv2 = cv::Mat(sz, dtype); + cv::Mat out_mat_gapi2 = cv::Mat(sz, dtype); + + initMatsRandN(type, sz, dtype, false); + + // OpenCV code ///////////////////////////////////////////////////////////// + { + cv::Sobel(in_mat1, out_mat_ocv, dtype, order, 0, kernSize); + cv::Sobel(in_mat1, out_mat_ocv2, dtype, 0, order, kernSize); + } + + // G-API code ////////////////////////////////////////////////////////////// + cv::GMat in; + auto out = cv::gapi::SobelXY(in, dtype, order, kernSize); + cv::GComputation c(cv::GIn(in), cv::GOut(std::get<0>(out), std::get<1>(out))); + + // Warm-up graph engine: + c.apply(cv::gin(in_mat1), cv::gout(out_mat_gapi, out_mat_gapi2), std::move(compile_args)); + + TEST_CYCLE() + { + c.apply(cv::gin(in_mat1), cv::gout(out_mat_gapi, out_mat_gapi2)); + } + + // Comparison ////////////////////////////////////////////////////////////// + { + EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv)); + EXPECT_TRUE(cmpF(out_mat_gapi2, out_mat_ocv2)); + EXPECT_EQ(out_mat_gapi.size(), sz); + EXPECT_EQ(out_mat_gapi2.size(), sz); + } + + SANITY_CHECK_NOTHING(); +} + +//------------------------------------------------------------------------------ + PERF_TEST_P_(CannyPerfTest, TestPerformance) { compare_f cmpF; diff --git a/modules/gapi/perf/cpu/gapi_imgproc_perf_tests_fluid.cpp b/modules/gapi/perf/cpu/gapi_imgproc_perf_tests_fluid.cpp index 12554bf4b1..635f2d0110 100644 --- a/modules/gapi/perf/cpu/gapi_imgproc_perf_tests_fluid.cpp +++ b/modules/gapi/perf/cpu/gapi_imgproc_perf_tests_fluid.cpp @@ -32,7 +32,7 @@ INSTANTIATE_TEST_CASE_P(SepFilterPerfTestFluid_other, SepFilterPerfTest, INSTANTIATE_TEST_CASE_P(Filter2DPerfTestFluid, Filter2DPerfTest, Combine(Values(ToleranceFilter(1e-4f, 0.01).to_compare_f()), Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1), - Values(3), // add 4, 5, 7 when kernel is ready + Values(3), // TODO: add 4, 5, 7 when kernel is ready Values(szVGA, sz720p, sz1080p), Values(cv::BORDER_DEFAULT), Values(-1, CV_32F), @@ -41,7 +41,7 @@ INSTANTIATE_TEST_CASE_P(Filter2DPerfTestFluid, Filter2DPerfTest, INSTANTIATE_TEST_CASE_P(BoxFilterPerfTestFluid, BoxFilterPerfTest, Combine(Values(ToleranceFilter(1e-4f, 0.01).to_compare_f()), Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1), - Values(3), // add size=5, when kernel is ready + Values(3), // TODO: add size=5, when kernel is ready Values(szVGA, sz720p, sz1080p), Values(cv::BORDER_DEFAULT), Values(-1, CV_32F), @@ -50,7 +50,7 @@ INSTANTIATE_TEST_CASE_P(BoxFilterPerfTestFluid, BoxFilterPerfTest, INSTANTIATE_TEST_CASE_P(BlurPerfTestFluid, BlurPerfTest, Combine(Values(ToleranceFilter(1e-4f, 0.01).to_compare_f()), Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1), - Values(3), // add size=5, when kernel is ready + Values(3), // TODO: add size=5, when kernel is ready Values(szVGA, sz720p, sz1080p), Values(cv::BORDER_DEFAULT), Values(cv::compile_args(IMGPROC_FLUID)))); @@ -58,21 +58,21 @@ INSTANTIATE_TEST_CASE_P(BlurPerfTestFluid, BlurPerfTest, INSTANTIATE_TEST_CASE_P(GaussianBlurPerfTestFluid, GaussianBlurPerfTest, Combine(Values(ToleranceFilter(1e-3f, 0.01).to_compare_f()), Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1), - Values(3), // add size=5, when kernel is ready + Values(3), // TODO: add size=5, when kernel is ready Values(szVGA, sz720p, sz1080p), Values(cv::compile_args(IMGPROC_FLUID)))); INSTANTIATE_TEST_CASE_P(MedianBlurPerfTestFluid, MedianBlurPerfTest, Combine(Values(AbsExact().to_compare_f()), Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1), - Values(3), // add size=5, when kernel is ready + Values(3), // TODO: add size=5, when kernel is ready Values(szVGA, sz720p, sz1080p), Values(cv::compile_args(IMGPROC_FLUID)))); INSTANTIATE_TEST_CASE_P(ErodePerfTestFluid, ErodePerfTest, Combine(Values(AbsExact().to_compare_f()), Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1), - Values(3), // add size=5, when kernel is ready + Values(3), // TODO: add size=5, when kernel is ready Values(szVGA, sz720p, sz1080p), Values(cv::MorphShapes::MORPH_RECT, cv::MorphShapes::MORPH_CROSS, @@ -90,7 +90,7 @@ INSTANTIATE_TEST_CASE_P(DISABLED_Erode3x3PerfTestFluid, Erode3x3PerfTest, INSTANTIATE_TEST_CASE_P(DilatePerfTestFluid, DilatePerfTest, Combine(Values(AbsExact().to_compare_f()), Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1), - Values(3), // add size=5, when kernel is ready + Values(3), // TODO: add size=5, when kernel is ready Values(szVGA, sz720p, sz1080p), Values(cv::MorphShapes::MORPH_RECT, cv::MorphShapes::MORPH_CROSS, @@ -108,7 +108,7 @@ INSTANTIATE_TEST_CASE_P(DISABLED_Dilate3x3PerfTestFluid, Dilate3x3PerfTest, INSTANTIATE_TEST_CASE_P(SobelPerfTestFluid, SobelPerfTest, Combine(Values(AbsExact().to_compare_f()), Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1), - Values(3), // add 5x5 once supported + Values(3), // TODO: add 5x5 once supported Values(szVGA, sz720p, sz1080p), Values(-1, CV_16S, CV_32F), Values(0, 1), @@ -118,13 +118,31 @@ INSTANTIATE_TEST_CASE_P(SobelPerfTestFluid, SobelPerfTest, INSTANTIATE_TEST_CASE_P(SobelPerfTestFluid32F, SobelPerfTest, Combine(Values(ToleranceFilter(1e-3f, 0.0).to_compare_f()), Values(CV_32FC1), - Values(3), // add 5x5 once supported + Values(3), // TODO: add 5x5 once supported Values(szVGA, sz720p, sz1080p), Values(CV_32F), Values(0, 1), Values(1, 2), Values(cv::compile_args(IMGPROC_FLUID)))); +INSTANTIATE_TEST_CASE_P(SobelXYPerfTestFluid, SobelXYPerfTest, + Combine(Values(AbsExact().to_compare_f()), + Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1), + Values(3), // TODO: add 5x5 once supported + Values(szVGA, sz720p, sz1080p), + Values(-1, CV_16S, CV_32F), + Values(1, 2), + Values(cv::compile_args(IMGPROC_FLUID)))); + +INSTANTIATE_TEST_CASE_P(SobelXYPerfTestFluid32F, SobelXYPerfTest, + Combine(Values(ToleranceFilter(1e-3f, 0.0).to_compare_f()), + Values(CV_32FC1), + Values(3), // TODO: add 5x5 once supported + Values(szVGA, sz720p, sz1080p), + Values(CV_32F), + Values(1, 2), + Values(cv::compile_args(IMGPROC_FLUID)))); + INSTANTIATE_TEST_CASE_P(RGB2GrayPerfTestFluid, RGB2GrayPerfTest, Combine(Values(ToleranceColor(1e-3).to_compare_f()), Values(szVGA, sz720p, sz1080p), diff --git a/modules/gapi/src/api/kernels_imgproc.cpp b/modules/gapi/src/api/kernels_imgproc.cpp index 7c4b522e94..7861de9a97 100644 --- a/modules/gapi/src/api/kernels_imgproc.cpp +++ b/modules/gapi/src/api/kernels_imgproc.cpp @@ -80,6 +80,13 @@ GMat Sobel(const GMat& src, int ddepth, int dx, int dy, int ksize, return imgproc::GSobel::on(src, ddepth, dx, dy, ksize, scale, delta, borderType, bordVal); } +std::tuple SobelXY(const GMat& src, int ddepth, int order, int ksize, + double scale, double delta, + int borderType, const Scalar& bordVal) +{ + return imgproc::GSobelXY::on(src, ddepth, order, ksize, scale, delta, borderType, bordVal); +} + GMat equalizeHist(const GMat& src) { return imgproc::GEqHist::on(src); diff --git a/modules/gapi/src/backends/cpu/gcpuimgproc.cpp b/modules/gapi/src/backends/cpu/gcpuimgproc.cpp index d14584bfac..ad57ff3841 100644 --- a/modules/gapi/src/backends/cpu/gcpuimgproc.cpp +++ b/modules/gapi/src/backends/cpu/gcpuimgproc.cpp @@ -11,6 +11,19 @@ #include "opencv2/gapi/cpu/imgproc.hpp" #include "backends/cpu/gcpuimgproc.hpp" +namespace { + cv::Mat add_border(const cv::Mat& in, const int ksize, const int borderType, const cv::Scalar& bordVal){ + if( borderType == cv::BORDER_CONSTANT ) + { + cv::Mat temp_in; + int add = (ksize - 1) / 2; + cv::copyMakeBorder(in, temp_in, add, add, add, add, borderType, bordVal); + return temp_in(cv::Rect(add, add, in.cols, in.rows)); + } + return in; + } +} + GAPI_OCV_KERNEL(GCPUSepFilter, cv::gapi::imgproc::GSepFilter) { static void run(const cv::Mat& in, int ddepth, const cv::Mat& kernX, const cv::Mat& kernY, const cv::Point& anchor, const cv::Scalar& delta, @@ -133,16 +146,19 @@ GAPI_OCV_KERNEL(GCPUSobel, cv::gapi::imgproc::GSobel) static void run(const cv::Mat& in, int ddepth, int dx, int dy, int ksize, double scale, double delta, int borderType, const cv::Scalar& bordVal, cv::Mat &out) { - if( borderType == cv::BORDER_CONSTANT ) - { - cv::Mat temp_in; - int add = (ksize - 1) / 2; - cv::copyMakeBorder(in, temp_in, add, add, add, add, borderType, bordVal ); - cv::Rect rect = cv::Rect(add, add, in.cols, in.rows); - cv::Sobel(temp_in(rect), out, ddepth, dx, dy, ksize, scale, delta, borderType); - } - else - cv::Sobel(in, out, ddepth, dx, dy, ksize, scale, delta, borderType); + cv::Mat temp_in = add_border(in, ksize, borderType, bordVal); + cv::Sobel(temp_in, out, ddepth, dx, dy, ksize, scale, delta, borderType); + } +}; + +GAPI_OCV_KERNEL(GCPUSobelXY, cv::gapi::imgproc::GSobelXY) +{ + static void run(const cv::Mat& in, int ddepth, int order, int ksize, double scale, double delta, int borderType, + const cv::Scalar& bordVal, cv::Mat &out_dx, cv::Mat &out_dy) + { + cv::Mat temp_in = add_border(in, ksize, borderType, bordVal); + cv::Sobel(temp_in, out_dx, ddepth, order, 0, ksize, scale, delta, borderType); + cv::Sobel(temp_in, out_dy, ddepth, 0, order, ksize, scale, delta, borderType); } }; @@ -256,6 +272,7 @@ cv::gapi::GKernelPackage cv::gapi::imgproc::cpu::kernels() , GCPUErode , GCPUDilate , GCPUSobel + , GCPUSobelXY , GCPUCanny , GCPUEqualizeHist , GCPURGB2YUV diff --git a/modules/gapi/src/backends/fluid/gfluidimgproc.cpp b/modules/gapi/src/backends/fluid/gfluidimgproc.cpp index de8beb1650..e8cd6bd7ee 100644 --- a/modules/gapi/src/backends/fluid/gfluidimgproc.cpp +++ b/modules/gapi/src/backends/fluid/gfluidimgproc.cpp @@ -1022,6 +1022,168 @@ GAPI_FLUID_KERNEL(GFluidSobel, cv::gapi::imgproc::GSobel, true) } }; +//--------------------- +// +// Fluid kernels: SobelXY +// +//--------------------- + +GAPI_FLUID_KERNEL(GFluidSobelXY, cv::gapi::imgproc::GSobelXY, true) +{ + static const int Window = 3; + + struct BufHelper + { + float *kx_dx, *ky_dx, + *kx_dy, *ky_dy; + float *buf_start; + int buf_width, buf_chan; + + static int length(int ksz, int width, int chan) + { + return ksz + ksz + ksz + ksz // kernels: kx_dx, ky_dx, kx_dy, ky_dy + + 2 * ksz * width * chan; + } + + BufHelper(int ksz, int width, int chan, Buffer& scratch) + { + kx_dx = scratch.OutLine(); + ky_dx = kx_dx + ksz; + kx_dy = ky_dx + ksz; + ky_dy = kx_dy + ksz; + buf_start = ky_dy + ksz; + buf_width = width; + buf_chan = chan; + } + + float* operator [](int i) { + return buf_start + i * buf_width * buf_chan; + } + }; + + static void run(const View & in, + int /* ddepth */, + int /* order */, + int ksize, + double _scale, + double _delta, + int /* borderType */, + const cv::Scalar& /* borderValue */, + Buffer& out_x, + Buffer& out_y, + Buffer& scratch) + { + // TODO: support kernel height 3, 5, 7, 9, ... + GAPI_Assert(ksize == 3 || ksize == FILTER_SCHARR); + + int ksz = (ksize == FILTER_SCHARR)? 3: ksize; + + GAPI_Assert(out_x.meta().size.width == out_y.meta().size.width); + GAPI_Assert(out_x.meta().chan == out_y.meta().chan); + + int width = out_x.meta().size.width; + int chan = out_x.meta().chan; + + BufHelper buf_helper(ksz, width, chan, scratch); + + auto *kx_dx = buf_helper.kx_dx; + auto *ky_dx = buf_helper.ky_dx; + auto *kx_dy = buf_helper.kx_dy; + auto *ky_dy = buf_helper.ky_dy; + + // Scratch buffer layout: + // |kx_dx|ky_dx|kx_dy|ky_dy|3 lines for horizontal kernel|3 lines for vertical kernel| + float *buf[3]; + buf[0] = buf_helper[0]; + buf[1] = buf_helper[1]; + buf[2] = buf_helper[2]; + + auto scale = static_cast(_scale); + auto delta = static_cast(_delta); + + auto calc = [&](const View& src, Buffer& dst, float* kx, float* ky) { + // DST SRC OP __VA_ARGS__ + UNARY_(uchar , uchar , run_sobel, dst, src, kx, ky, ksz, scale, delta, buf); + UNARY_(ushort, ushort, run_sobel, dst, src, kx, ky, ksz, scale, delta, buf); + UNARY_( short, uchar , run_sobel, dst, src, kx, ky, ksz, scale, delta, buf); + UNARY_( short, ushort, run_sobel, dst, src, kx, ky, ksz, scale, delta, buf); + UNARY_( short, short, run_sobel, dst, src, kx, ky, ksz, scale, delta, buf); + UNARY_( float, uchar , run_sobel, dst, src, kx, ky, ksz, scale, delta, buf); + UNARY_( float, ushort, run_sobel, dst, src, kx, ky, ksz, scale, delta, buf); + UNARY_( float, short, run_sobel, dst, src, kx, ky, ksz, scale, delta, buf); + UNARY_( float, float, run_sobel, dst, src, kx, ky, ksz, scale, delta, buf); + + CV_Error(cv::Error::StsBadArg, "unsupported combination of types"); + }; + + // calculate x-derivative + calc(in, out_x, kx_dx, ky_dx); + + // Move pointers to calculate dy(preventing buffer data corruption) + buf[0] = buf_helper[3]; + buf[1] = buf_helper[4]; + buf[2] = buf_helper[5]; + + // calculate y-derivative + calc(in, out_y, kx_dy, ky_dy); + } + + static void initScratch(const GMatDesc& in, + int /* ddepth */, + int order, + int ksize, + double /* scale */, + double /* delta */, + int /* borderType */, + const Scalar & /* borderValue */, + Buffer & scratch) + { + // TODO: support kernel height 3, 5, 7, 9, ... + GAPI_Assert(ksize == 3 || ksize == FILTER_SCHARR); + int ksz = (ksize == FILTER_SCHARR) ? 3 : ksize; + + int width = in.size.width; + int chan = in.chan; + int buflen = BufHelper::length(ksz, width, chan); + + cv::gapi::own::Size bufsize(buflen, 1); + GMatDesc bufdesc = {CV_32F, 1, bufsize}; + Buffer buffer(bufdesc); + scratch = std::move(buffer); + + BufHelper buf_helper(ksz, width, chan, scratch); + + auto *kx_dx = buf_helper.kx_dx; + auto *ky_dx = buf_helper.ky_dx; + auto *kx_dy = buf_helper.kx_dy; + auto *ky_dy = buf_helper.ky_dy; + + Mat kxmatX(1, ksize, CV_32FC1, kx_dx); + Mat kymatX(ksize, 1, CV_32FC1, ky_dx); + getDerivKernels(kxmatX, kymatX, order, 0, ksize); + + Mat kxmatY(1, ksize, CV_32FC1, kx_dy); + Mat kymatY(ksize, 1, CV_32FC1, ky_dy); + getDerivKernels(kxmatY, kymatY, 0, order, ksize); + } + + static void resetScratch(Buffer& /* scratch */) + { + } + + static Border getBorder(const cv::GMatDesc& /* src */, + int /* ddepth */, + int /* order */, + int /* ksize */, + double /* scale */, + double /* delta */, + int borderType, + const cv::Scalar & borderValue) + { + return {borderType, borderValue}; + } +}; + //------------------------ // // Fluid kernels: filter2D @@ -1546,6 +1708,7 @@ cv::gapi::GKernelPackage cv::gapi::imgproc::fluid::kernels() , GFluidMedianBlur , GFluidGaussBlur , GFluidSobel + , GFluidSobelXY #if 0 , GFluidCanny -- not fluid (?) , GFluidEqualizeHist -- not fluid diff --git a/modules/gapi/test/common/gapi_imgproc_tests.hpp b/modules/gapi/test/common/gapi_imgproc_tests.hpp index c21b26b686..82d41efcb2 100644 --- a/modules/gapi/test/common/gapi_imgproc_tests.hpp +++ b/modules/gapi/test/common/gapi_imgproc_tests.hpp @@ -26,6 +26,7 @@ struct Erode3x3Test : public TestParams > {}; struct Dilate3x3Test : public TestParams > {}; struct SobelTest : public TestParams > {}; +struct SobelXYTest : public TestParams > {}; struct EqHistTest : public TestParams > {}; struct CannyTest : public TestParams > {}; struct RGB2GrayTest : public TestParams> {}; diff --git a/modules/gapi/test/common/gapi_imgproc_tests_inl.hpp b/modules/gapi/test/common/gapi_imgproc_tests_inl.hpp index 0812191f0f..0ca038707e 100644 --- a/modules/gapi/test/common/gapi_imgproc_tests_inl.hpp +++ b/modules/gapi/test/common/gapi_imgproc_tests_inl.hpp @@ -353,6 +353,46 @@ TEST_P(SobelTest, AccuracyTest) } } +TEST_P(SobelXYTest, AccuracyTest) +{ + compare_f cmpF; + MatType type = 0; + int kernSize = 0, dtype = 0, order = 0, border_type = 0, border_val = 0; + cv::Size sz; + cv::GCompileArgs compile_args; + std::tie(cmpF, type, kernSize, sz, dtype, order, border_type, border_val, compile_args) = GetParam(); + initMatsRandN(type, sz, dtype); + cv::Mat out_mat_ocv2 = cv::Mat(sz, dtype); + cv::Mat out_mat_gapi2 = cv::Mat(sz, dtype); + + // G-API code ////////////////////////////////////////////////////////////// + cv::GMat in; + auto out = cv::gapi::SobelXY(in, dtype, order, kernSize, 1, 0, border_type, border_val); + + cv::GComputation c(cv::GIn(in), cv::GOut(std::get<0>(out), std::get<1>(out))); + c.apply(cv::gin(in_mat1), cv::gout(out_mat_gapi, out_mat_gapi2), std::move(compile_args)); + // OpenCV code ///////////////////////////////////////////////////////////// + { + // workaround for cv::Sobel + cv::Mat temp_in; + if(border_type == cv::BORDER_CONSTANT) + { + int n_pixels = (kernSize - 1) / 2; + cv::copyMakeBorder(in_mat1, temp_in, n_pixels, n_pixels, n_pixels, n_pixels, border_type, border_val); + in_mat1 = temp_in(cv::Rect(n_pixels, n_pixels, in_mat1.cols, in_mat1.rows)); + } + cv::Sobel(in_mat1, out_mat_ocv, dtype, order, 0, kernSize, 1, 0, border_type); + cv::Sobel(in_mat1, out_mat_ocv2, dtype, 0, order, kernSize, 1, 0, border_type); + } + // Comparison ////////////////////////////////////////////////////////////// + { + EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv)); + EXPECT_TRUE(cmpF(out_mat_gapi2, out_mat_ocv2)); + EXPECT_EQ(out_mat_gapi.size(), sz); + EXPECT_EQ(out_mat_gapi2.size(), sz); + } +} + TEST_P(EqHistTest, AccuracyTest) { compare_f cmpF; diff --git a/modules/gapi/test/cpu/gapi_imgproc_tests_cpu.cpp b/modules/gapi/test/cpu/gapi_imgproc_tests_cpu.cpp index beda022400..3dc916739f 100644 --- a/modules/gapi/test/cpu/gapi_imgproc_tests_cpu.cpp +++ b/modules/gapi/test/cpu/gapi_imgproc_tests_cpu.cpp @@ -153,6 +153,30 @@ INSTANTIATE_TEST_CASE_P(SobelTestCPU32F, SobelTest, /*init output matrices or not*/ testing::Bool(), Values(cv::compile_args(IMGPROC_CPU)))); +INSTANTIATE_TEST_CASE_P(SobelXYTestCPU, SobelXYTest, + Combine(Values(AbsExact().to_compare_f()), + Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1), + Values(3, 5), + Values(cv::Size(1280, 720), + cv::Size(640, 480)), + Values(-1, CV_16S, CV_32F), + Values(1, 2), + Values(BORDER_CONSTANT, BORDER_REPLICATE, BORDER_REFLECT), + Values(0, 1, 255), + Values(cv::compile_args(IMGPROC_CPU)))); + +INSTANTIATE_TEST_CASE_P(SobelXYTestCPU32F, SobelXYTest, + Combine(Values(AbsExact().to_compare_f()), + Values(CV_32FC1), + Values(3, 5), + Values(cv::Size(1280, 720), + cv::Size(640, 480)), + Values(CV_32F), + Values(1, 2), + Values(BORDER_CONSTANT, BORDER_REPLICATE, BORDER_REFLECT), + Values(0, 1, 255), + Values(cv::compile_args(IMGPROC_CPU)))); + INSTANTIATE_TEST_CASE_P(EqHistTestCPU, EqHistTest, Combine(Values(AbsExact().to_compare_f()), Values(cv::Size(1280, 720), diff --git a/modules/gapi/test/cpu/gapi_imgproc_tests_fluid.cpp b/modules/gapi/test/cpu/gapi_imgproc_tests_fluid.cpp index 5dca2092a2..f053565111 100644 --- a/modules/gapi/test/cpu/gapi_imgproc_tests_fluid.cpp +++ b/modules/gapi/test/cpu/gapi_imgproc_tests_fluid.cpp @@ -132,6 +132,30 @@ INSTANTIATE_TEST_CASE_P(SobelTestFluid32F, SobelTest, Values(true, false), Values(cv::compile_args(IMGPROC_FLUID)))); +INSTANTIATE_TEST_CASE_P(SobelXYTestFluid, SobelXYTest, + Combine(Values(AbsExact().to_compare_f()), + Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1), + Values(3), + Values(cv::Size(1280, 720), + cv::Size(640, 480)), + Values(-1, CV_16S, CV_32F), + Values(1, 2), + Values(BORDER_CONSTANT, BORDER_REPLICATE, BORDER_REFLECT_101), + Values(0, 1, 255), + Values(cv::compile_args(IMGPROC_FLUID)))); + +INSTANTIATE_TEST_CASE_P(SobelXYTestFluid32F, SobelXYTest, + Combine(Values(ToleranceFilter(1e-4f, 0.01).to_compare_f()), + Values(CV_32FC1), + Values(3), + Values(cv::Size(1280, 720), + cv::Size(640, 480)), + Values(CV_32F), + Values(1, 2), + Values(BORDER_CONSTANT, BORDER_REPLICATE, BORDER_REFLECT_101), + Values(0, 1, 255), + Values(cv::compile_args(IMGPROC_FLUID)))); + INSTANTIATE_TEST_CASE_P(boxFilterTestFluid32, BoxFilterTest, Combine(Values(ToleranceFilter(1e-4f, 0.01).to_compare_f()), Values(CV_8UC1, CV_16UC1, CV_16SC1),