diff --git a/modules/gapi/include/opencv2/gapi/core.hpp b/modules/gapi/include/opencv2/gapi/core.hpp index eb6c5dc0d6..e29a0958d1 100644 --- a/modules/gapi/include/opencv2/gapi/core.hpp +++ b/modules/gapi/include/opencv2/gapi/core.hpp @@ -485,6 +485,14 @@ namespace core { return (ddepth < 0 ? in : in.withDepth(ddepth)); } }; + + 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"); + return in.withType(in.depth, in.chan).withSize(dsize); + } + }; } //! @addtogroup gapi_math @@ -1653,6 +1661,31 @@ 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 an affine transformation to an image. + +The function warpAffine transforms the source image using the specified matrix: + +\f[\texttt{dst} (x,y) = \texttt{src} ( \texttt{M} _{11} x + \texttt{M} _{12} y + \texttt{M} _{13}, \texttt{M} _{21} x + \texttt{M} _{22} y + \texttt{M} _{23})\f] + +when the flag #WARP_INVERSE_MAP is set. Otherwise, the transformation is first inverted +with #invertAffineTransform and then put in the formula above instead of M. The function cannot +operate in-place. + +@param src input image. +@param M \f$2\times 3\f$ transformation matrix. +@param dsize size of the output image. +@param flags combination of interpolation methods (see #InterpolationFlags) and the optional +flag #WARP_INVERSE_MAP that means that M is the inverse transformation ( +\f$\texttt{dst}\rightarrow\texttt{src}\f$ ). +@param borderMode pixel extrapolation method (see #BorderTypes); +borderMode=#BORDER_TRANSPARENT isn't supported +@param borderValue value used in case of a constant border; by default, it is 0. + +@sa warpPerspective, resize, remap, getRectSubPix, transform + */ +GAPI_EXPORTS GMat warpAffine(const GMat& src, const Mat& M, const Size& dsize, int flags = cv::INTER_LINEAR, + int borderMode = cv::BORDER_CONSTANT, const Scalar& borderValue = Scalar()); //! @} gapi_transform } //namespace gapi diff --git a/modules/gapi/src/api/kernels_core.cpp b/modules/gapi/src/api/kernels_core.cpp index ef15c93275..dfea04d353 100644 --- a/modules/gapi/src/api/kernels_core.cpp +++ b/modules/gapi/src/api/kernels_core.cpp @@ -371,5 +371,11 @@ GMat normalize(const GMat& _src, double a, double b, return core::GNormalize::on(_src, a, b, norm_type, ddepth); } +GMat warpAffine(const GMat& src, const Mat& M, const Size& dsize, int flags, + int borderMode, const Scalar& borderValue) +{ + return core::GWarpAffine::on(src, M, dsize, flags, borderMode, borderValue); +} + } //namespace gapi } //namespace cv diff --git a/modules/gapi/src/backends/cpu/gcpucore.cpp b/modules/gapi/src/backends/cpu/gcpucore.cpp index 24e612aa78..321e12cf98 100644 --- a/modules/gapi/src/backends/cpu/gcpucore.cpp +++ b/modules/gapi/src/backends/cpu/gcpucore.cpp @@ -558,6 +558,16 @@ GAPI_OCV_KERNEL(GCPUNormalize, cv::gapi::core::GNormalize) } }; +GAPI_OCV_KERNEL(GCPUWarpAffine, cv::gapi::core::GWarpAffine) +{ + 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::warpAffine(src, out, M, dsize, flags, borderMode, borderValue); + } +}; + + cv::gapi::GKernelPackage cv::gapi::core::cpu::kernels() { static auto pkg = cv::gapi::kernels @@ -626,6 +636,7 @@ cv::gapi::GKernelPackage cv::gapi::core::cpu::kernels() , GCPUConvertTo , GCPUSqrt , GCPUNormalize + , GCPUWarpAffine >(); return pkg; } diff --git a/modules/gapi/test/common/gapi_core_tests.hpp b/modules/gapi/test/common/gapi_core_tests.hpp index 8f6f573112..7bc96eada2 100644 --- a/modules/gapi/test/common/gapi_core_tests.hpp +++ b/modules/gapi/test/common/gapi_core_tests.hpp @@ -141,6 +141,9 @@ struct BackendOutputAllocationTest : TestWithParamBase<> // FIXME: move all tests from this fixture to the base class once all issues are resolved 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) } // 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 20e3d3834b..0c47e648fa 100644 --- a/modules/gapi/test/common/gapi_core_tests_inl.hpp +++ b/modules/gapi/test/common/gapi_core_tests_inl.hpp @@ -1266,6 +1266,27 @@ TEST_P(SqrtTest, AccuracyTest) } } +TEST_P(WarpAffineTest, AccuracyTest) +{ + cv::Point center{in_mat1.size() / 2}; + cv::Mat warp_mat = cv::getRotationMatrix2D(center, angle, scale); + + // G-API code ////////////////////////////////////////////////////////////// + cv::GMat in; + auto out = cv::gapi::warpAffine(in, warp_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::warpAffine(in_mat1, out_mat_ocv, warp_mat, in_mat1.size(), flags, border_mode, border_value); + + // Comparison ////////////////////////////////////////////////////////////// + { + EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv)); + } +} + TEST_P(NormalizeTest, Test) { initMatrixRandN(type, sz, CV_MAKETYPE(ddepth, CV_MAT_CN(type))); diff --git a/modules/gapi/test/cpu/gapi_core_tests_cpu.cpp b/modules/gapi/test/cpu/gapi_core_tests_cpu.cpp index e7e60bc695..d10ce0dce5 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(WarpAffineTestCPU, WarpAffineTest, + 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(NormalizeTestCPU, NormalizeTest, Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1), Values(cv::Size(1280, 720),