diff --git a/modules/gapi/include/opencv2/gapi/core.hpp b/modules/gapi/include/opencv2/gapi/core.hpp index e29a0958d1..00400a8af3 100644 --- a/modules/gapi/include/opencv2/gapi/core.hpp +++ b/modules/gapi/include/opencv2/gapi/core.hpp @@ -486,10 +486,18 @@ namespace core { } }; + G_TYPED_KERNEL(GWarpPerspective, , "org.opencv.core.warpPerspective") { + static GMatDesc outMeta(GMatDesc in, const Mat&, Size dsize, int, int borderMode, const cv::Scalar&) { + GAPI_Assert((borderMode == cv::BORDER_CONSTANT || borderMode == cv::BORDER_REPLICATE) && + "cv::gapi::warpPerspective supports only cv::BORDER_CONSTANT and cv::BORDER_REPLICATE border modes"); + return in.withType(in.depth, in.chan).withSize(dsize); + } + }; + G_TYPED_KERNEL(GWarpAffine, , "org.opencv.core.warpAffine") { static GMatDesc outMeta(GMatDesc in, const Mat&, Size dsize, int, int border_mode, const cv::Scalar&) { GAPI_Assert(border_mode != cv::BORDER_TRANSPARENT && - "cv::BORDER_TRANSPARENT mode isn't support in G-API"); + "cv::BORDER_TRANSPARENT mode is not supported in cv::gapi::warpAffine"); return in.withType(in.depth, in.chan).withSize(dsize); } }; @@ -1662,6 +1670,30 @@ number of channels as src and the depth =ddepth. GAPI_EXPORTS GMat normalize(const GMat& src, double alpha, double beta, int norm_type, int ddepth = -1); +/** @brief Applies a perspective transformation to an image. + +The function warpPerspective transforms the source image using the specified matrix: + +\f[\texttt{dst} (x,y) = \texttt{src} \left ( \frac{M_{11} x + M_{12} y + M_{13}}{M_{31} x + M_{32} y + M_{33}} , + \frac{M_{21} x + M_{22} y + M_{23}}{M_{31} x + M_{32} y + M_{33}} \right )\f] + +when the flag #WARP_INVERSE_MAP is set. Otherwise, the transformation is first inverted with invert +and then put in the formula above instead of M. The function cannot operate in-place. + +@param src input image. +@param M \f$3\times 3\f$ transformation matrix. +@param dsize size of the output image. +@param flags combination of interpolation methods (#INTER_LINEAR or #INTER_NEAREST) and the +optional flag #WARP_INVERSE_MAP, that sets M as the inverse transformation ( +\f$\texttt{dst}\rightarrow\texttt{src}\f$ ). +@param borderMode pixel extrapolation method (#BORDER_CONSTANT or #BORDER_REPLICATE). +@param borderValue value used in case of a constant border; by default, it equals 0. + +@sa warpAffine, resize, remap, getRectSubPix, perspectiveTransform + */ +GAPI_EXPORTS GMat warpPerspective(const GMat& src, const Mat& M, const Size& dsize, int flags = cv::INTER_LINEAR, + int borderMode = cv::BORDER_CONSTANT, const Scalar& borderValue = Scalar()); + /** @brief Applies an affine transformation to an image. The function warpAffine transforms the source image using the specified matrix: diff --git a/modules/gapi/src/api/kernels_core.cpp b/modules/gapi/src/api/kernels_core.cpp index dfea04d353..13a04595ca 100644 --- a/modules/gapi/src/api/kernels_core.cpp +++ b/modules/gapi/src/api/kernels_core.cpp @@ -371,6 +371,12 @@ GMat normalize(const GMat& _src, double a, double b, return core::GNormalize::on(_src, a, b, norm_type, ddepth); } +GMat warpPerspective(const GMat& src, const Mat& M, const Size& dsize, int flags, + int borderMode, const Scalar& borderValue) +{ + return core::GWarpPerspective::on(src, M, dsize, flags, borderMode, borderValue); +} + GMat warpAffine(const GMat& src, const Mat& M, const Size& dsize, int flags, int borderMode, const Scalar& borderValue) { diff --git a/modules/gapi/src/backends/cpu/gcpucore.cpp b/modules/gapi/src/backends/cpu/gcpucore.cpp index 321e12cf98..bf2d034db9 100644 --- a/modules/gapi/src/backends/cpu/gcpucore.cpp +++ b/modules/gapi/src/backends/cpu/gcpucore.cpp @@ -558,6 +558,15 @@ GAPI_OCV_KERNEL(GCPUNormalize, cv::gapi::core::GNormalize) } }; +GAPI_OCV_KERNEL(GCPUWarpPerspective, cv::gapi::core::GWarpPerspective) +{ + static void run(const cv::Mat& src, const cv::Mat& M, const cv::Size& dsize, + int flags, int borderMode, const cv::Scalar& borderValue, cv::Mat& out) + { + cv::warpPerspective(src, out, M, dsize, flags, borderMode, borderValue); + } +}; + GAPI_OCV_KERNEL(GCPUWarpAffine, cv::gapi::core::GWarpAffine) { static void run(const cv::Mat& src, const cv::Mat& M, const cv::Size& dsize, @@ -636,6 +645,7 @@ cv::gapi::GKernelPackage cv::gapi::core::cpu::kernels() , GCPUConvertTo , GCPUSqrt , GCPUNormalize + , GCPUWarpPerspective , GCPUWarpAffine >(); return pkg; diff --git a/modules/gapi/test/common/gapi_core_tests.hpp b/modules/gapi/test/common/gapi_core_tests.hpp index 7bc96eada2..1d8bba969e 100644 --- a/modules/gapi/test/common/gapi_core_tests.hpp +++ b/modules/gapi/test/common/gapi_core_tests.hpp @@ -142,8 +142,13 @@ struct BackendOutputAllocationTest : TestWithParamBase<> struct BackendOutputAllocationLargeSizeWithCorrectSubmatrixTest : BackendOutputAllocationTest {}; GAPI_TEST_FIXTURE(ReInitOutTest, initNothing, , 1, out_sz) -GAPI_TEST_FIXTURE(WarpAffineTest, initMatrixRandU, FIXTURE_API(CompareMats, double , double, int, int, cv::Scalar), 6, - cmpF, angle, scale, flags, border_mode, border_value) +GAPI_TEST_FIXTURE(WarpPerspectiveTest, initMatrixRandU, + FIXTURE_API(CompareMats, double , double, int, int, cv::Scalar), + 6, cmpF, angle, scale, flags, border_mode, border_value) + +GAPI_TEST_FIXTURE(WarpAffineTest, initMatrixRandU, + FIXTURE_API(CompareMats, double , double, int, int, cv::Scalar), + 6, cmpF, angle, scale, flags, border_mode, border_value) } // opencv_test #endif //OPENCV_GAPI_CORE_TESTS_HPP diff --git a/modules/gapi/test/common/gapi_core_tests_inl.hpp b/modules/gapi/test/common/gapi_core_tests_inl.hpp index 0c47e648fa..b5ed58c703 100644 --- a/modules/gapi/test/common/gapi_core_tests_inl.hpp +++ b/modules/gapi/test/common/gapi_core_tests_inl.hpp @@ -1266,6 +1266,30 @@ TEST_P(SqrtTest, AccuracyTest) } } +TEST_P(WarpPerspectiveTest, AccuracyTest) +{ + cv::Point center{in_mat1.size() / 2}; + cv::Mat xy = cv::getRotationMatrix2D(center, angle, scale); + cv::Matx13d z (0, 0, 1); + cv::Mat transform_mat; + cv::vconcat(xy, z, transform_mat); + + // G-API code ////////////////////////////////////////////////////////////// + cv::GMat in; + auto out = cv::gapi::warpPerspective(in, transform_mat, in_mat1.size(), flags, border_mode, border_value); + + cv::GComputation c(in, out); + c.apply(in_mat1, out_mat_gapi, getCompileArgs()); + + // OpenCV code ///////////////////////////////////////////////////////////// + cv::warpPerspective(in_mat1, out_mat_ocv, cv::Mat(transform_mat), in_mat1.size(), flags, border_mode, border_value); + + // Comparison ////////////////////////////////////////////////////////////// + { + EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv)); + } +} + TEST_P(WarpAffineTest, AccuracyTest) { cv::Point center{in_mat1.size() / 2}; diff --git a/modules/gapi/test/cpu/gapi_core_tests_cpu.cpp b/modules/gapi/test/cpu/gapi_core_tests_cpu.cpp index d10ce0dce5..f7e9816c2c 100644 --- a/modules/gapi/test/cpu/gapi_core_tests_cpu.cpp +++ b/modules/gapi/test/cpu/gapi_core_tests_cpu.cpp @@ -435,6 +435,19 @@ INSTANTIATE_TEST_CASE_P(ConcatHorVecTestCPU, ConcatHorVecTest, Values(-1), Values(CORE_CPU))); +INSTANTIATE_TEST_CASE_P(WarpPerspectiveTestCPU, WarpPerspectiveTest, + Combine(Values(CV_8UC1, CV_8UC3), + Values(cv::Size(1280, 720), + cv::Size(640, 480)), + Values(-1), + Values(CORE_CPU), + Values(AbsExact().to_compare_obj()), + Values(-50.0, 90.0), + Values(0.6), + Values(cv::INTER_LINEAR), + Values(cv::BORDER_CONSTANT), + Values(cv::Scalar()))); + INSTANTIATE_TEST_CASE_P(WarpAffineTestCPU, WarpAffineTest, Combine(Values(CV_8UC1, CV_8UC3), Values(cv::Size(1280, 720),