diff --git a/modules/core/src/mathfuncs_core.simd.hpp b/modules/core/src/mathfuncs_core.simd.hpp index 8c4dbffe1d..ec0e948f3f 100644 --- a/modules/core/src/mathfuncs_core.simd.hpp +++ b/modules/core/src/mathfuncs_core.simd.hpp @@ -119,7 +119,7 @@ static void cartToPolar32f_(const float *X, const float *Y, float *mag, float *a // 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 ) + if( i == 0 || mag == X || mag == Y || angle == X || angle == Y ) break; i = len - VECSZ*2; } diff --git a/modules/core/test/test_arithm.cpp b/modules/core/test/test_arithm.cpp index 9da3f03586..ec120816ab 100644 --- a/modules/core/test/test_arithm.cpp +++ b/modules/core/test/test_arithm.cpp @@ -3358,6 +3358,35 @@ INSTANTIATE_TEST_CASE_P(Core_CartPolar, Core_CartToPolar_inplace, ) ); +typedef testing::TestWithParam Core_CartToPolar_inplace_mag; + +// only the magnitude overwrites an input, so the last elements must not be processed twice. +// CV_64F is not tested: it works on separate float buffers, so it can't hit this. +TEST_P(Core_CartToPolar_inplace_mag, accuracy) +{ + const int len = GetParam(); + cv::Mat x(1, len, CV_32F), y(1, len, CV_32F); + cv::randu(x, cv::Scalar::all(-1000), cv::Scalar::all(1000)); + cv::randu(y, cv::Scalar::all(-1000), cv::Scalar::all(1000)); + + cv::Mat expectedMag, expectedAngle; + cv::cartToPolar(x, y, expectedMag, expectedAngle); + + // magnitude into x + cv::Mat x1 = x.clone(), angle1; + cv::cartToPolar(x1, y, x1, angle1); + EXPECT_MAT_NEAR(expectedMag, x1, 1e-2); + EXPECT_MAT_NEAR(expectedAngle, angle1, 1e-2); + + // magnitude into y + cv::Mat y1 = y.clone(), angle2; + cv::cartToPolar(x, y1, y1, angle2); + EXPECT_MAT_NEAR(expectedMag, y1, 1e-2); + EXPECT_MAT_NEAR(expectedAngle, angle2, 1e-2); +} + +INSTANTIATE_TEST_CASE_P(Core_CartPolar, Core_CartToPolar_inplace_mag, testing::Range(1, 40)); + PARAM_TEST_CASE(Core_PolarToCart_inplace, int, bool, bool) { int depth;