diff --git a/modules/core/include/opencv2/core/hal/hal.hpp b/modules/core/include/opencv2/core/hal/hal.hpp index 24a6077101..deca4e9539 100644 --- a/modules/core/include/opencv2/core/hal/hal.hpp +++ b/modules/core/include/opencv2/core/hal/hal.hpp @@ -91,10 +91,14 @@ CV_EXPORTS void exp64f(const double* src, double* dst, int n); CV_EXPORTS void log32f(const float* src, float* dst, int n); CV_EXPORTS void log64f(const double* src, double* dst, int n); +CV_EXPORTS void cartToPolar32f(const float* x, const float* y, float* mag, float* angle, int n, bool angleInDegrees); +CV_EXPORTS void cartToPolar64f(const double* x, const double* y, double* mag, double* angle, int n, bool angleInDegrees); CV_EXPORTS void fastAtan32f(const float* y, const float* x, float* dst, int n, bool angleInDegrees); CV_EXPORTS void fastAtan64f(const double* y, const double* x, double* dst, int n, bool angleInDegrees); CV_EXPORTS void magnitude32f(const float* x, const float* y, float* dst, int n); CV_EXPORTS void magnitude64f(const double* x, const double* y, double* dst, int n); +CV_EXPORTS void polarToCart32f(const float* mag, const float* angle, float* x, float* y, int n, bool angleInDegrees); +CV_EXPORTS void polarToCart64f(const double* mag, const double* angle, double* x, double* y, int n, bool angleInDegrees); CV_EXPORTS void sqrt32f(const float* src, float* dst, int len); CV_EXPORTS void sqrt64f(const double* src, double* dst, int len); CV_EXPORTS void invSqrt32f(const float* src, float* dst, int len); diff --git a/modules/core/src/hal_replacement.hpp b/modules/core/src/hal_replacement.hpp index 1f2b259920..f0fd12ca35 100644 --- a/modules/core/src/hal_replacement.hpp +++ b/modules/core/src/hal_replacement.hpp @@ -413,6 +413,24 @@ inline int hal_ni_merge64s(const int64 **src_data, int64 *dst_data, int len, int #define cv_hal_merge64s hal_ni_merge64s //! @endcond +/** +@param x source X arrays +@param y source Y arrays +@param mag destination magnitude array +@param angle destination angle array +@param len length of arrays +@param angleInDegrees if set to true return angles in degrees, otherwise in radians +*/ +//! @addtogroup core_hal_interface_fastAtan Atan calculation +//! @{ +inline int hal_ni_cartToPolar32f(const float* x, const float* y, float* mag, float* angle, int len, bool angleInDegrees) { return CV_HAL_ERROR_NOT_IMPLEMENTED; } +inline int hal_ni_cartToPolar64f(const double* x, const double* y, double* mag, double* angle, int len, bool angleInDegrees) { return CV_HAL_ERROR_NOT_IMPLEMENTED; } +//! @} + +//! @cond IGNORED +#define cv_hal_cartToPolar32f hal_ni_cartToPolar32f +#define cv_hal_cartToPolar64f hal_ni_cartToPolar64f +//! @endcond /** @param y source Y arrays @@ -450,6 +468,24 @@ inline int hal_ni_magnitude64f(const double *x, const double *y, double *dst, i #define cv_hal_magnitude64f hal_ni_magnitude64f //! @endcond +/** +@param mag source magnitude arrays +@param mag source angle arrays +@param x destination X array +@param y destination Y array +@param len length of arrays +@param angleInDegrees if set to true interpret angles from degrees, otherwise from radians +*/ +//! @addtogroup core_hal_interface_fastAtan Atan calculation +//! @{ +inline int hal_ni_polarToCart32f(const float* mag, const float* angle, float* x, float* y, int len, bool angleInDegrees) { return CV_HAL_ERROR_NOT_IMPLEMENTED; } +inline int hal_ni_polarToCart64f(const double* mag, const double* angle, double* x, double* y, int len, bool angleInDegrees) { return CV_HAL_ERROR_NOT_IMPLEMENTED; } +//! @} + +//! @cond IGNORED +#define cv_hal_polarToCart32f hal_ni_polarToCart32f +#define cv_hal_polarToCart64f hal_ni_polarToCart64f +//! @endcond /** @param src source array diff --git a/modules/core/src/mathfuncs.cpp b/modules/core/src/mathfuncs.cpp index 04604e84c0..1aa16aaceb 100644 --- a/modules/core/src/mathfuncs.cpp +++ b/modules/core/src/mathfuncs.cpp @@ -233,16 +233,26 @@ static bool ocl_cartToPolar( InputArray _src1, InputArray _src2, rowsPerWI = d.isIntel() ? 4 : 1; bool doubleSupport = d.doubleFPConfig() > 0; + const bool _src1IsDstMag = (_src1.getObj() == _dst1.getObj()); + const bool _src1IsDstAngle = (_src1.getObj() == _dst2.getObj()); + const bool _src2IsDstMag = (_src2.getObj() == _dst1.getObj()); + const bool _src2IsDstAngle = (_src2.getObj() == _dst2.getObj()); + if ( !(_src1.dims() <= 2 && _src2.dims() <= 2 && (depth == CV_32F || depth == CV_64F) && type == _src2.type()) || (depth == CV_64F && !doubleSupport) ) return false; ocl::Kernel k("KF", ocl::core::arithm_oclsrc, - format("-D BINARY_OP -D dstT=%s -D DEPTH_dst=%d -D rowsPerWI=%d -D OP_CTP_%s%s", + format("-D BINARY_OP -D dstT=%s -D DEPTH_dst=%d -D rowsPerWI=%d -D OP_CTP_%s%s%s%s%s%s", ocl::typeToStr(CV_MAKE_TYPE(depth, 1)), depth, rowsPerWI, angleInDegrees ? "AD" : "AR", - doubleSupport ? " -D DOUBLE_SUPPORT" : "")); + doubleSupport ? " -D DOUBLE_SUPPORT" : "", + _src1IsDstMag ? " -D SRC1_IS_DST_MAG" : "", + _src1IsDstAngle ? " -D SRC1_IS_DST_ANGLE" : "", + _src2IsDstMag ? " -D SRC2_IS_DST_MAG" : "", + _src2IsDstAngle ? " -D SRC2_IS_DST_ANGLE" : "" + )); if (k.empty()) return false; @@ -254,8 +264,8 @@ static bool ocl_cartToPolar( InputArray _src1, InputArray _src2, _dst2.create(size, type); UMat dst1 = _dst1.getUMat(), dst2 = _dst2.getUMat(); - k.args(ocl::KernelArg::ReadOnlyNoSize(src1), - ocl::KernelArg::ReadOnlyNoSize(src2), + k.args(_src1IsDstMag || _src1IsDstAngle ? ocl::KernelArg::ReadWriteNoSize(src1) : ocl::KernelArg::ReadOnlyNoSize(src1), + _src2IsDstMag || _src2IsDstAngle ? ocl::KernelArg::ReadWriteNoSize(src2) : ocl::KernelArg::ReadOnlyNoSize(src2), ocl::KernelArg::WriteOnly(dst1, cn), ocl::KernelArg::WriteOnlyNoSize(dst2)); @@ -270,8 +280,7 @@ void cartToPolar( InputArray src1, InputArray src2, { CV_INSTRUMENT_REGION(); - CV_Assert(src1.getObj() != dst1.getObj() && src1.getObj() != dst2.getObj() && - src2.getObj() != dst1.getObj() && src2.getObj() != dst2.getObj()); + CV_Assert(dst1.getObj() != dst2.getObj()); CV_OCL_RUN(dst1.isUMat() && dst2.isUMat(), ocl_cartToPolar(src1, src2, dst1, dst2, angleInDegrees)) @@ -298,15 +307,13 @@ void cartToPolar( InputArray src1, InputArray src2, { const float *x = (const float*)ptrs[0], *y = (const float*)ptrs[1]; float *mag = (float*)ptrs[2], *angle = (float*)ptrs[3]; - hal::magnitude32f( x, y, mag, len ); - hal::fastAtan32f( y, x, angle, len, angleInDegrees ); + hal::cartToPolar32f( x, y, mag, angle, len, angleInDegrees ); } else { const double *x = (const double*)ptrs[0], *y = (const double*)ptrs[1]; - double *angle = (double*)ptrs[3]; - hal::magnitude64f(x, y, (double*)ptrs[2], len); - hal::fastAtan64f(y, x, angle, len, angleInDegrees); + double *mag = (double*)ptrs[2], *angle = (double*)ptrs[3]; + hal::cartToPolar64f(x, y, mag, angle, len, angleInDegrees); } ptrs[0] += len*esz1; ptrs[1] += len*esz1; @@ -474,15 +481,24 @@ static bool ocl_polarToCart( InputArray _mag, InputArray _angle, rowsPerWI = d.isIntel() ? 4 : 1; bool doubleSupport = d.doubleFPConfig() > 0; + const bool _src1IsDstX = (_mag.getObj() == _dst1.getObj()); + const bool _src1IsDstY = (_mag.getObj() == _dst2.getObj()); + const bool _src2IsDstX = (_angle.getObj() == _dst1.getObj()); + const bool _src2IsDstY = (_angle.getObj() == _dst2.getObj()); + if ( !doubleSupport && depth == CV_64F ) return false; ocl::Kernel k("KF", ocl::core::arithm_oclsrc, - format("-D dstT=%s -D DEPTH_dst=%d -D rowsPerWI=%d -D BINARY_OP -D OP_PTC_%s%s", + format("-D dstT=%s -D DEPTH_dst=%d -D rowsPerWI=%d -D BINARY_OP -D OP_PTC_%s%s%s%s%s%s", ocl::typeToStr(CV_MAKE_TYPE(depth, 1)), depth, rowsPerWI, angleInDegrees ? "AD" : "AR", - doubleSupport ? " -D DOUBLE_SUPPORT" : "")); + doubleSupport ? " -D DOUBLE_SUPPORT" : "", + _src1IsDstX ? " -D SRC1_IS_DST_X" : "", + _src1IsDstY ? " -D SRC1_IS_DST_Y" : "", + _src2IsDstX ? " -D SRC2_IS_DST_X" : "", + _src2IsDstY ? " -D SRC2_IS_DST_Y" : "")); if (k.empty()) return false; @@ -494,8 +510,10 @@ static bool ocl_polarToCart( InputArray _mag, InputArray _angle, _dst2.create(size, type); UMat dst1 = _dst1.getUMat(), dst2 = _dst2.getUMat(); - k.args(ocl::KernelArg::ReadOnlyNoSize(mag), ocl::KernelArg::ReadOnlyNoSize(angle), - ocl::KernelArg::WriteOnly(dst1, cn), ocl::KernelArg::WriteOnlyNoSize(dst2)); + k.args(_src1IsDstX || _src1IsDstY ? ocl::KernelArg::ReadWriteNoSize(mag) : ocl::KernelArg::ReadOnlyNoSize(mag), + _src2IsDstX || _src2IsDstY ? ocl::KernelArg::ReadWriteNoSize(angle) : ocl::KernelArg::ReadOnlyNoSize(angle), + ocl::KernelArg::WriteOnly(dst1, cn), + ocl::KernelArg::WriteOnlyNoSize(dst2)); size_t globalsize[2] = { (size_t)dst1.cols * cn, ((size_t)dst1.rows + rowsPerWI - 1) / rowsPerWI }; return k.run(2, globalsize, NULL, false); @@ -567,8 +585,13 @@ void polarToCart( InputArray src1, InputArray src2, { CV_INSTRUMENT_REGION(); - CV_Assert(src1.getObj() != dst1.getObj() && src1.getObj() != dst2.getObj() && - src2.getObj() != dst1.getObj() && src2.getObj() != dst2.getObj()); + CV_Assert(dst1.getObj() != dst2.getObj()); + + const bool isInPlace = + (src1.getObj() == dst1.getObj()) || + (src1.getObj() == dst2.getObj()) || + (src2.getObj() == dst1.getObj()) || + (src2.getObj() == dst2.getObj()); int type = src2.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type); CV_Assert((depth == CV_32F || depth == CV_64F) && (src1.empty() || src1.type() == type)); @@ -582,7 +605,7 @@ void polarToCart( InputArray src1, InputArray src2, dst2.create( Angle.dims, Angle.size, type ); Mat X = dst1.getMat(), Y = dst2.getMat(); - CV_IPP_RUN(!angleInDegrees, ipp_polarToCart(Mag, Angle, X, Y)); + CV_IPP_RUN(!angleInDegrees && !isInPlace, ipp_polarToCart(Mag, Angle, X, Y)); const Mat* arrays[] = {&Mag, &Angle, &X, &Y, 0}; uchar* ptrs[4] = {}; @@ -592,7 +615,7 @@ void polarToCart( InputArray src1, InputArray src2, int j, k, total = (int)(it.size*cn), blockSize = std::min(total, ((BLOCK_SIZE+cn-1)/cn)*cn); size_t esz1 = Angle.elemSize1(); - if( depth == CV_64F ) + if (( depth == CV_64F ) || isInPlace) { _buf.allocate(blockSize*2); buf[0] = _buf.data(); @@ -604,7 +627,7 @@ void polarToCart( InputArray src1, InputArray src2, for( j = 0; j < total; j += blockSize ) { int len = std::min(total - j, blockSize); - if( depth == CV_32F ) + if (( depth == CV_32F ) && !isInPlace) { const float *mag = (const float*)ptrs[0], *angle = (const float*)ptrs[1]; float *x = (float*)ptrs[2], *y = (float*)ptrs[3]; @@ -632,6 +655,27 @@ void polarToCart( InputArray src1, InputArray src2, } } } + else if (( depth == CV_32F ) && isInPlace) + { + const float *mag = (const float*)ptrs[0], *angle = (const float*)ptrs[1]; + float *x = (float*)ptrs[2], *y = (float*)ptrs[3]; + + for( k = 0; k < len; k++ ) + buf[0][k] = (float)angle[k]; + + SinCos_32f( buf[0], buf[1], buf[0], len, angleInDegrees ); + if( mag ) + for( k = 0; k < len; k++ ) + { + float m = mag[k]; + x[k] = buf[0][k]*m; y[k] = buf[1][k]*m; + } + else + { + std::memcpy(x, buf[0], sizeof(float) * len); + std::memcpy(y, buf[1], sizeof(float) * len); + } + } else { const double *mag = (const double*)ptrs[0], *angle = (const double*)ptrs[1]; @@ -649,8 +693,11 @@ void polarToCart( InputArray src1, InputArray src2, } else { - std::memcpy(x, buf[0], sizeof(float) * len); - std::memcpy(y, buf[1], sizeof(float) * len); + for( k = 0; k < len; k++ ) + { + x[k] = buf[0][k]; + y[k] = buf[1][k]; + } } } diff --git a/modules/core/src/mathfuncs_core.dispatch.cpp b/modules/core/src/mathfuncs_core.dispatch.cpp index e48f84ebbe..485eac27b4 100644 --- a/modules/core/src/mathfuncs_core.dispatch.cpp +++ b/modules/core/src/mathfuncs_core.dispatch.cpp @@ -9,7 +9,25 @@ namespace cv { namespace hal { -///////////////////////////////////// ATAN2 //////////////////////////////////// +void cartToPolar32f(const float* x, const float* y, float* mag, float* angle, int len, bool angleInDegrees) +{ + CV_INSTRUMENT_REGION(); + + CALL_HAL(cartToPolar32f, cv_hal_cartToPolar32f, x, y, mag, angle, len, angleInDegrees); + + CV_CPU_DISPATCH(cartToPolar32f, (x, y, mag, angle, len, angleInDegrees), + CV_CPU_DISPATCH_MODES_ALL); +} + +void cartToPolar64f(const double* x, const double* y, double* mag, double* angle, int len, bool angleInDegrees) +{ + CV_INSTRUMENT_REGION(); + + CALL_HAL(cartToPolar64f, cv_hal_cartToPolar64f, x, y, mag, angle, len, angleInDegrees); + + CV_CPU_DISPATCH(cartToPolar64f, (x, y, mag, angle, len, angleInDegrees), + CV_CPU_DISPATCH_MODES_ALL); +} void fastAtan32f(const float *Y, const float *X, float *angle, int len, bool angleInDegrees ) { diff --git a/modules/core/src/mathfuncs_core.simd.hpp b/modules/core/src/mathfuncs_core.simd.hpp index 2aa107b9be..cb21064041 100644 --- a/modules/core/src/mathfuncs_core.simd.hpp +++ b/modules/core/src/mathfuncs_core.simd.hpp @@ -9,6 +9,8 @@ namespace cv { namespace hal { CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN // forward declarations +void cartToPolar32f(const float *X, const float *Y, float* mag, float *angle, int len, bool angleInDegrees); +void cartToPolar64f(const double *X, const double *Y, double* mag, double *angle, int len, bool angleInDegrees); void fastAtan32f(const float *Y, const float *X, float *angle, int len, bool angleInDegrees); void fastAtan64f(const double *Y, const double *X, double *angle, int len, bool angleInDegrees); void fastAtan2(const float *Y, const float *X, float *angle, int len, bool angleInDegrees); @@ -118,7 +120,81 @@ struct v_atan_f32 } // anonymous:: -///////////////////////////////////// ATAN2 //////////////////////////////////// +static void cartToPolar32f_(const float *X, const float *Y, float *mag, float *angle, int len, bool angleInDegrees ) +{ + float scale = angleInDegrees ? 1.f : (float)(CV_PI/180); + int i = 0; +#if CV_SIMD + const int VECSZ = VTraits::vlanes(); + v_atan_f32 v(scale); + + for( ; i < len; i += VECSZ*2 ) + { + if( i + VECSZ*2 > len ) + { + // if it's inplace operation, we cannot repeatedly process + // the tail for the second time, so we have to use the + // scalar code + if( i == 0 || angle == X || angle == Y ) + break; + i = len - VECSZ*2; + } + + v_float32 x0 = vx_load(X + i); + v_float32 y0 = vx_load(Y + i); + v_float32 x1 = vx_load(X + i + VECSZ); + v_float32 y1 = vx_load(Y + i + VECSZ); + + v_float32 m0 = v_sqrt(v_muladd(x0, x0, v_mul(y0, y0))); + v_float32 m1 = v_sqrt(v_muladd(x1, x1, v_mul(y1, y1))); + + v_float32 r0 = v.compute(y0, x0); + v_float32 r1 = v.compute(y1, x1); + + v_store(mag + i, m0); + v_store(mag + i + VECSZ, m1); + + v_store(angle + i, r0); + v_store(angle + i + VECSZ, r1); + } + vx_cleanup(); +#endif + + for( ; i < len; i++ ) + { + float x0 = X[i], y0 = Y[i]; + mag[i] = std::sqrt(x0*x0 + y0*y0); + angle[i] = atan_f32(y0, x0)*scale; + } +} + +void cartToPolar32f(const float *X, const float *Y, float *mag, float *angle, int len, bool angleInDegrees ) +{ + CV_INSTRUMENT_REGION(); + cartToPolar32f_(X, Y, mag, angle, len, angleInDegrees ); +} + +void cartToPolar64f(const double *X, const double *Y, double *mag, double *angle, int len, bool angleInDegrees) +{ + CV_INSTRUMENT_REGION(); + + const int BLKSZ = 128; + float ybuf[BLKSZ], xbuf[BLKSZ], mbuf[BLKSZ], abuf[BLKSZ]; + for( int i = 0; i < len; i += BLKSZ ) + { + int j, blksz = std::min(BLKSZ, len - i); + for( j = 0; j < blksz; j++ ) + { + xbuf[j] = (float)X[i + j]; + ybuf[j] = (float)Y[i + j]; + } + cartToPolar32f_(xbuf, ybuf, mbuf, abuf, blksz, angleInDegrees); + for( j = 0; j < blksz; j++ ) + mag[i + j] = mbuf[j]; + for( j = 0; j < blksz; j++ ) + angle[i + j] = abuf[j]; + } +} static void fastAtan32f_(const float *Y, const float *X, float *angle, int len, bool angleInDegrees ) { diff --git a/modules/core/src/opencl/arithm.cl b/modules/core/src/opencl/arithm.cl index d4165faae3..301cea9f98 100644 --- a/modules/core/src/opencl/arithm.cl +++ b/modules/core/src/opencl/arithm.cl @@ -381,6 +381,20 @@ #elif defined OP_CTP_AR #define TO_DEGREE #endif +#ifdef SRC1_IS_DST_MAG +#define ADAPT_SRC1 dstptr = srcptr1; +#elif SRC1_IS_DST_ANGLE +#define ADAPT_SRC1 dstptr2 = srcptr1; +#else +#define ADAPT_SRC1 +#endif +#ifdef SRC2_IS_DST_MAG +#define ADAPT_SRC2 dstptr = srcptr2; +#elif SRC2_IS_DST_ANGLE +#define ADAPT_SRC2 dstptr2 = srcptr2; +#else +#define ADAPT_SRC2 +#endif #define PROCESS_ELEM \ dstT x = srcelem1, y = srcelem2; \ dstT x2 = x * x, y2 = y * y; \ @@ -390,6 +404,8 @@ dstT tmp1 = y >= 0 ? CV_PI * 0.5f : CV_PI * 1.5f; \ dstT cartToPolar = y2 <= x2 ? x * y / mad((dstT)(0.28f), y2, x2 + CV_EPSILON) + tmp : (tmp1 - x * y / mad((dstT)(0.28f), x2, y2 + CV_EPSILON)); \ TO_DEGREE \ + ADAPT_SRC1 \ + ADAPT_SRC2 \ storedst(magnitude); \ storedst2(cartToPolar) @@ -399,9 +415,25 @@ #else #define FROM_DEGREE #endif +#ifdef SRC1_IS_DST_X +#define ADAPT_SRC1 dstptr = srcptr1; +#elif SRC1_IS_DST_Y +#define ADAPT_SRC1 dstptr2 = srcptr1; +#else +#define ADAPT_SRC1 +#endif +#ifdef SRC2_IS_DST_X +#define ADAPT_SRC2 dstptr = srcptr2; +#elif SRC2_IS_DST_Y +#define ADAPT_SRC2 dstptr2 = srcptr2; +#else +#define ADAPT_SRC2 +#endif #define PROCESS_ELEM \ dstT x = srcelem1, y = srcelem2, cosval; \ FROM_DEGREE; \ + ADAPT_SRC1; \ + ADAPT_SRC2; \ storedst2(sincos(y, &cosval) * x); \ storedst(cosval * x); diff --git a/modules/core/test/test_arithm.cpp b/modules/core/test/test_arithm.cpp index 499c766a84..73c755b0fa 100644 --- a/modules/core/test/test_arithm.cpp +++ b/modules/core/test/test_arithm.cpp @@ -2819,12 +2819,26 @@ TEST(Core_Magnitude, regression_19506) } } -TEST(Core_CartPolar, inplace) +PARAM_TEST_CASE(Core_CartPolar_reverse, int, bool) { - RNG& rng = TS::ptr()->get_rng(); - cv::Mat1d A[2] = {cv::Mat1d(10, 10), cv::Mat1d(10, 10)}; - cv::Mat1d B[2], C[2]; + int depth; + bool angleInDegrees; + + virtual void SetUp() + { + depth = GET_PARAM(0); + angleInDegrees = GET_PARAM(1); + } +}; + +TEST_P(Core_CartPolar_reverse, reverse) +{ + const int type = CV_MAKETYPE(depth, 1); + cv::Mat A[2] = {cv::Mat(10, 10, type), cv::Mat(10, 10, type)}; + cv::Mat B[2], C[2]; cv::UMat uA[2]; + cv::UMat uB[2]; + cv::UMat uC[2]; for(int i = 0; i < 2; ++i) { @@ -2833,22 +2847,155 @@ TEST(Core_CartPolar, inplace) } // Reverse - cv::cartToPolar(A[0], A[1], B[0], B[1], false); - cv::polarToCart(B[0], B[1], C[0], C[1], false); + cv::cartToPolar(A[0], A[1], B[0], B[1], angleInDegrees); + cv::polarToCart(B[0], B[1], C[0], C[1], angleInDegrees); EXPECT_MAT_NEAR(A[0], C[0], 2); EXPECT_MAT_NEAR(A[1], C[1], 2); +} + +INSTANTIATE_TEST_CASE_P(Core_CartPolar, Core_CartPolar_reverse, + testing::Combine( + testing::Values(CV_32F, CV_64F), + testing::Values(false, true) + ) +); + +PARAM_TEST_CASE(Core_CartToPolar_inplace, int, bool) +{ + int depth; + bool angleInDegrees; + + virtual void SetUp() + { + depth = GET_PARAM(0); + angleInDegrees = GET_PARAM(1); + } +}; + +TEST_P(Core_CartToPolar_inplace, inplace) +{ + const int type = CV_MAKETYPE(depth, 1); + cv::Mat A[2] = {cv::Mat(10, 10, type), cv::Mat(10, 10, type)}; + cv::Mat B[2], C[2]; + cv::UMat uA[2]; + cv::UMat uB[2]; + cv::UMat uC[2]; - // Inplace - EXPECT_THROW(cv::polarToCart(B[0], B[1], B[0], B[1], false), cv::Exception); - EXPECT_THROW(cv::polarToCart(B[0], B[1], B[1], B[0], false), cv::Exception); - EXPECT_THROW(cv::cartToPolar(A[0], A[1], A[0], A[1], false), cv::Exception); - EXPECT_THROW(cv::cartToPolar(A[0], A[1], A[1], A[0], false), cv::Exception); - // Inplace OCL - EXPECT_THROW(cv::polarToCart(uA[0], uA[1], uA[0], uA[1]), cv::Exception); - EXPECT_THROW(cv::polarToCart(uA[0], uA[1], uA[1], uA[0]), cv::Exception); - EXPECT_THROW(cv::cartToPolar(uA[0], uA[1], uA[0], uA[1]), cv::Exception); - EXPECT_THROW(cv::cartToPolar(uA[0], uA[1], uA[0], uA[1]), cv::Exception); + for(int i = 0; i < 2; ++i) + { + cvtest::randUni(rng, A[i], Scalar::all(-1000), Scalar::all(1000)); + A[i].copyTo(uA[i]); + } + + // Inplace x<->mag y<->angle + for(int i = 0; i < 2; ++i) + A[i].copyTo(B[i]); + cv::cartToPolar(A[0], A[1], C[0], C[1], angleInDegrees); + cv::cartToPolar(B[0], B[1], B[0], B[1], angleInDegrees); + EXPECT_MAT_NEAR(C[0], B[0], 2); + EXPECT_MAT_NEAR(C[1], B[1], 2); + + // Inplace x<->angle y<->mag + for(int i = 0; i < 2; ++i) + A[i].copyTo(B[i]); + cv::cartToPolar(A[0], A[1], C[0], C[1], angleInDegrees); + cv::cartToPolar(B[0], B[1], B[1], B[0], angleInDegrees); + EXPECT_MAT_NEAR(C[0], B[1], 2); + EXPECT_MAT_NEAR(C[1], B[0], 2); + + // Inplace OCL x<->mag y<->angle + for(int i = 0; i < 2; ++i) + uA[i].copyTo(uB[i]); + cv::cartToPolar(uA[0], uA[1], uC[0], uC[1], angleInDegrees); + cv::cartToPolar(uB[0], uB[1], uB[0], uB[1], angleInDegrees); + EXPECT_MAT_NEAR(uC[0], uB[0], 2); + EXPECT_MAT_NEAR(uC[1], uB[1], 2); + // Inplace OCL x<->angle y<->mag + for(int i = 0; i < 2; ++i) + uA[i].copyTo(uB[i]); + cv::cartToPolar(uA[0], uA[1], uC[0], uC[1], angleInDegrees); + cv::cartToPolar(uB[0], uB[1], uB[1], uB[0], angleInDegrees); + EXPECT_MAT_NEAR(uC[0], uB[1], 2); + EXPECT_MAT_NEAR(uC[1], uB[0], 2); } +INSTANTIATE_TEST_CASE_P(Core_CartPolar, Core_CartToPolar_inplace, + testing::Combine( + testing::Values(CV_32F, CV_64F), + testing::Values(false, true) + ) +); + +PARAM_TEST_CASE(Core_PolarToCart_inplace, int, bool, bool) +{ + int depth; + bool angleInDegrees; + bool implicitMagnitude; + + virtual void SetUp() + { + depth = GET_PARAM(0); + angleInDegrees = GET_PARAM(1); + implicitMagnitude = GET_PARAM(2); + } +}; + +TEST_P(Core_PolarToCart_inplace, inplace) +{ + const int type = CV_MAKETYPE(depth, 1); + cv::Mat A[2] = {cv::Mat(10, 10, type), cv::Mat(10, 10, type)}; + cv::Mat B[2], C[2]; + cv::UMat uA[2]; + cv::UMat uB[2]; + cv::UMat uC[2]; + + for(int i = 0; i < 2; ++i) + { + cvtest::randUni(rng, A[i], Scalar::all(-1000), Scalar::all(1000)); + A[i].copyTo(uA[i]); + } + + // Inplace OCL x<->mag y<->angle + for(int i = 0; i < 2; ++i) + A[i].copyTo(B[i]); + cv::polarToCart(implicitMagnitude ? cv::noArray() : A[0], A[1], C[0], C[1], angleInDegrees); + cv::polarToCart(implicitMagnitude ? cv::noArray() : B[0], B[1], B[0], B[1], angleInDegrees); + EXPECT_MAT_NEAR(C[0], B[0], 2); + EXPECT_MAT_NEAR(C[1], B[1], 2); + + // Inplace OCL x<->angle y<->mag + for(int i = 0; i < 2; ++i) + A[i].copyTo(B[i]); + cv::polarToCart(implicitMagnitude ? cv::noArray() : A[0], A[1], C[0], C[1], angleInDegrees); + cv::polarToCart(implicitMagnitude ? cv::noArray() : B[0], B[1], B[1], B[0], angleInDegrees); + EXPECT_MAT_NEAR(C[0], B[1], 2); + EXPECT_MAT_NEAR(C[1], B[0], 2); + + // Inplace OCL x<->mag y<->angle + for(int i = 0; i < 2; ++i) + uA[i].copyTo(uB[i]); + cv::polarToCart(implicitMagnitude ? cv::noArray() : uA[0], uA[1], uC[0], uC[1], angleInDegrees); + cv::polarToCart(implicitMagnitude ? cv::noArray() : uB[0], uB[1], uB[0], uB[1], angleInDegrees); + EXPECT_MAT_NEAR(uC[0], uB[0], 2); + EXPECT_MAT_NEAR(uC[1], uB[1], 2); + + // Inplace OCL x<->angle y<->mag + for(int i = 0; i < 2; ++i) + uA[i].copyTo(uB[i]); + cv::polarToCart(implicitMagnitude ? cv::noArray() : uA[0], uA[1], uC[0], uC[1], angleInDegrees); + cv::polarToCart(implicitMagnitude ? cv::noArray() : uB[0], uB[1], uB[1], uB[0], angleInDegrees); + EXPECT_MAT_NEAR(uC[0], uB[1], 2); + EXPECT_MAT_NEAR(uC[1], uB[0], 2); +} + +INSTANTIATE_TEST_CASE_P(Core_CartPolar, Core_PolarToCart_inplace, + testing::Combine( + testing::Values(CV_32F, CV_64F), + testing::Values(false, true), + testing::Values(true, false) + ) +); + + }} // namespace