diff --git a/modules/gapi/include/opencv2/gapi/imgproc.hpp b/modules/gapi/include/opencv2/gapi/imgproc.hpp index 294b3b7842..cc091dfa8e 100644 --- a/modules/gapi/include/opencv2/gapi/imgproc.hpp +++ b/modules/gapi/include/opencv2/gapi/imgproc.hpp @@ -78,6 +78,14 @@ namespace imgproc { } }; + G_TYPED_KERNEL(GMorphologyEx, , + "org.opencv.imgproc.filters.morphologyEx") { + static GMatDesc outMeta(const GMatDesc &in, MorphTypes, Mat, Point, int, + BorderTypes, Scalar) { + return in; + } + }; + G_TYPED_KERNEL(GSobel, , "org.opencv.imgproc.filters.sobel") { static GMatDesc outMeta(GMatDesc in, int ddepth, int, int, int, double, double, int, Scalar) { return in.withDepth(ddepth); @@ -521,7 +529,7 @@ anchor is at the element center. @param iterations number of times erosion is applied. @param borderType pixel extrapolation method, see cv::BorderTypes @param borderValue border value in case of a constant border -@sa dilate +@sa dilate, morphologyEx */ GAPI_EXPORTS GMat erode(const GMat& src, const Mat& kernel, const Point& anchor = Point(-1,-1), int iterations = 1, int borderType = BORDER_CONSTANT, @@ -596,6 +604,37 @@ GAPI_EXPORTS GMat dilate3x3(const GMat& src, int iterations = 1, int borderType = BORDER_CONSTANT, const Scalar& borderValue = morphologyDefaultBorderValue()); +/** @brief Performs advanced morphological transformations. + +The function can perform advanced morphological transformations using an erosion and dilation as +basic operations. + +Any of the operations can be done in-place. In case of multi-channel images, each channel is +processed independently. + +@note Function textual ID is "org.opencv.imgproc.filters.morphologyEx" + +@param src Input image. +@param op Type of a morphological operation, see #MorphTypes +@param kernel Structuring element. It can be created using #getStructuringElement. +@param anchor Anchor position within the element. Both negative values mean that the anchor is at +the kernel center. +@param iterations Number of times erosion and dilation are applied. +@param borderType Pixel extrapolation method, see #BorderTypes. #BORDER_WRAP is not supported. +@param borderValue Border value in case of a constant border. The default value has a special +meaning. +@sa dilate, erode, getStructuringElement +@note The number of iterations is the number of times erosion or dilatation operation will be +applied. For instance, an opening operation (#MORPH_OPEN) with two iterations is equivalent to +apply successively: erode -> erode -> dilate -> dilate +(and not erode -> dilate -> erode -> dilate). + */ +GAPI_EXPORTS GMat morphologyEx(const GMat &src, const MorphTypes op, const Mat &kernel, + const Point &anchor = Point(-1,-1), + const int iterations = 1, + const BorderTypes borderType = BORDER_CONSTANT, + const Scalar &borderValue = morphologyDefaultBorderValue()); + /** @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 diff --git a/modules/gapi/src/api/kernels_imgproc.cpp b/modules/gapi/src/api/kernels_imgproc.cpp index 652f83935f..9a5b07c14a 100644 --- a/modules/gapi/src/api/kernels_imgproc.cpp +++ b/modules/gapi/src/api/kernels_imgproc.cpp @@ -73,6 +73,13 @@ GMat dilate3x3(const GMat& src, int iterations, return dilate(src, cv::Mat(), cv::Point(-1,-1), iterations, borderType, borderValue); } +GMat morphologyEx(const GMat &src, const MorphTypes op, const Mat &kernel, const Point &anchor, + const int iterations, const BorderTypes borderType, const Scalar &borderValue) +{ + return imgproc::GMorphologyEx::on(src, op, kernel, anchor, iterations, + borderType, borderValue); +} + GMat Sobel(const GMat& src, int ddepth, int dx, int dy, int ksize, double scale, double delta, int borderType, const Scalar& bordVal) diff --git a/modules/gapi/src/backends/cpu/gcpuimgproc.cpp b/modules/gapi/src/backends/cpu/gcpuimgproc.cpp index c07ed6785c..a3c4e1b60f 100644 --- a/modules/gapi/src/backends/cpu/gcpuimgproc.cpp +++ b/modules/gapi/src/backends/cpu/gcpuimgproc.cpp @@ -145,6 +145,16 @@ GAPI_OCV_KERNEL(GCPUDilate, cv::gapi::imgproc::GDilate) } }; +GAPI_OCV_KERNEL(GCPUMorphologyEx, cv::gapi::imgproc::GMorphologyEx) +{ + static void run(const cv::Mat &in, const cv::MorphTypes op, const cv::Mat &kernel, + const cv::Point &anchor, const int iterations, + const cv::BorderTypes borderType, const cv::Scalar &borderValue, cv::Mat &out) + { + cv::morphologyEx(in, out, op, kernel, anchor, iterations, borderType, borderValue); + } +}; + 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, @@ -478,6 +488,7 @@ cv::gapi::GKernelPackage cv::gapi::imgproc::cpu::kernels() , GCPUMedianBlur , GCPUErode , GCPUDilate + , GCPUMorphologyEx , GCPUSobel , GCPUSobelXY , GCPULaplacian diff --git a/modules/gapi/test/common/gapi_imgproc_tests.hpp b/modules/gapi/test/common/gapi_imgproc_tests.hpp index 38a02985e7..d562b306c2 100644 --- a/modules/gapi/test/common/gapi_imgproc_tests.hpp +++ b/modules/gapi/test/common/gapi_imgproc_tests.hpp @@ -46,6 +46,8 @@ GAPI_TEST_FIXTURE(Erode3x3Test, initMatrixRandN, FIXTURE_API(CompareMats,int), 2 GAPI_TEST_FIXTURE(DilateTest, initMatrixRandN, FIXTURE_API(CompareMats,int,int), 3, cmpF, kernSize, kernType) GAPI_TEST_FIXTURE(Dilate3x3Test, initMatrixRandN, FIXTURE_API(CompareMats,int), 2, cmpF, numIters) +GAPI_TEST_FIXTURE(MorphologyExTest, initMatrixRandN, FIXTURE_API(CompareMats,MorphTypes), + 2, cmpF, op) GAPI_TEST_FIXTURE(SobelTest, initMatrixRandN, FIXTURE_API(CompareMats,int,int,int), 4, cmpF, kernSize, dx, dy) GAPI_TEST_FIXTURE(SobelXYTest, initMatrixRandN, FIXTURE_API(CompareMats,int,int,int,int), 5, diff --git a/modules/gapi/test/common/gapi_imgproc_tests_inl.hpp b/modules/gapi/test/common/gapi_imgproc_tests_inl.hpp index 95728e87b7..c087733fa8 100644 --- a/modules/gapi/test/common/gapi_imgproc_tests_inl.hpp +++ b/modules/gapi/test/common/gapi_imgproc_tests_inl.hpp @@ -290,6 +290,29 @@ TEST_P(Dilate3x3Test, AccuracyTest) } } +TEST_P(MorphologyExTest, AccuracyTest) +{ + MorphShapes defShape = cv::MORPH_RECT; + int defKernSize = 3; + cv::Mat kernel = cv::getStructuringElement(defShape, cv::Size(defKernSize, defKernSize)); + + // G-API code ////////////////////////////////////////////////////////////// + cv::GMat in; + auto out = cv::gapi::morphologyEx(in, op, kernel); + + cv::GComputation c(in, out); + c.apply(in_mat1, out_mat_gapi, getCompileArgs()); + // OpenCV code ///////////////////////////////////////////////////////////// + { + cv::morphologyEx(in_mat1, out_mat_ocv, op, kernel); + } + // Comparison ////////////////////////////////////////////////////////////// + { + EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv)); + EXPECT_EQ(out_mat_gapi.size(), sz); + } +} + TEST_P(SobelTest, AccuracyTest) { // G-API code ////////////////////////////////////////////////////////////// diff --git a/modules/gapi/test/common/gapi_tests_common.hpp b/modules/gapi/test/common/gapi_tests_common.hpp index 113f3c73c0..bb045b83d1 100644 --- a/modules/gapi/test/common/gapi_tests_common.hpp +++ b/modules/gapi/test/common/gapi_tests_common.hpp @@ -848,6 +848,25 @@ inline std::ostream& operator<<(std::ostream& os, NormTypes op) #undef CASE return os; } + +inline std::ostream& operator<<(std::ostream& os, MorphTypes op) +{ +#define CASE(v) case MorphTypes::v: os << #v; break + switch (op) + { + CASE(MORPH_ERODE); + CASE(MORPH_DILATE); + CASE(MORPH_OPEN); + CASE(MORPH_CLOSE); + CASE(MORPH_GRADIENT); + CASE(MORPH_TOPHAT); + CASE(MORPH_BLACKHAT); + CASE(MORPH_HITMISS); + default: GAPI_Assert(false && "unknown MorphTypes value"); + } +#undef CASE + return os; +} } // namespace cv #endif //OPENCV_GAPI_TESTS_COMMON_HPP diff --git a/modules/gapi/test/cpu/gapi_imgproc_tests_cpu.cpp b/modules/gapi/test/cpu/gapi_imgproc_tests_cpu.cpp index e7f9667096..7cba6b05db 100644 --- a/modules/gapi/test/cpu/gapi_imgproc_tests_cpu.cpp +++ b/modules/gapi/test/cpu/gapi_imgproc_tests_cpu.cpp @@ -130,6 +130,30 @@ INSTANTIATE_TEST_CASE_P(Dilate3x3TestCPU, Dilate3x3Test, Values(AbsExact().to_compare_obj()), Values(1,2,4))); +INSTANTIATE_TEST_CASE_P(MorphologyExTestCPU, MorphologyExTest, + Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1), + Values(cv::Size(1280, 720), + cv::Size(640, 480)), + Values(-1), + Values(IMGPROC_CPU), + Values(AbsExact().to_compare_obj()), + Values(cv::MorphTypes::MORPH_ERODE, + cv::MorphTypes::MORPH_DILATE, + cv::MorphTypes::MORPH_OPEN, + cv::MorphTypes::MORPH_CLOSE, + cv::MorphTypes::MORPH_GRADIENT, + cv::MorphTypes::MORPH_TOPHAT, + cv::MorphTypes::MORPH_BLACKHAT))); + +INSTANTIATE_TEST_CASE_P(MorphologyExHitMissTestCPU, MorphologyExTest, + Combine(Values(CV_8UC1), + Values(cv::Size(1280, 720), + cv::Size(640, 480)), + Values(-1), + Values(IMGPROC_CPU), + Values(AbsExact().to_compare_obj()), + Values(cv::MorphTypes::MORPH_HITMISS))); + INSTANTIATE_TEST_CASE_P(SobelTestCPU, SobelTest, Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1), Values(cv::Size(1280, 720),