Merge pull request #24893 from chacha21:cart_polar_inplace

Added in-place support for cartToPolar and polarToCart #24893

- a fused hal::cartToPolar[32|64]f() is used instead of sequential hal::magnitude[32|64]f/hal::fastAtan[32|64]f
- ipp_polarToCart is skipped for in-place processing (it seems not to support it correctly)

relates to #24891
### Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

- [X] I agree to contribute to the project under Apache 2 License.
- [X] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
- [X] The PR is proposed to the proper branch
- [X] There is a reference to the original bug report and related work
- [X] There is accuracy test, performance test and test data in opencv_extra repository, if applicable
      Patch to opencv_extra has the same branch name.
- [ ] The feature is well documented and sample code can be built with the project CMake
pull/25276/head
Pierre Chatelier 8 months ago committed by GitHub
parent accf200408
commit 1a537ab98f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 4
      modules/core/include/opencv2/core/hal/hal.hpp
  2. 36
      modules/core/src/hal_replacement.hpp
  3. 91
      modules/core/src/mathfuncs.cpp
  4. 20
      modules/core/src/mathfuncs_core.dispatch.cpp
  5. 78
      modules/core/src/mathfuncs_core.simd.hpp
  6. 32
      modules/core/src/opencl/arithm.cl
  7. 179
      modules/core/test/test_arithm.cpp

@ -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);

@ -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

@ -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];
}
}
}

@ -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 )
{

@ -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<v_float32>::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 )
{

@ -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);

@ -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

Loading…
Cancel
Save