Merge pull request #30715 from sshivensolanki:core-carttopolar-inplace-5x

core: fix in-place cartToPolar when only the magnitude overwrites an input (5.x) - #30715

5.x port of #30646, as requested in its review. Fixes #30645 on 5.x.

### Problem

`cv::cartToPolar` gives wrong results on `CV_32F` when only the magnitude output is the same `Mat` as `x` or `y`. The SIMD tail handling repeats the last full block, and `cartToPolar32f_` only skipped that for in-place calls when the angle was aliased.

### Fix

Same as #30646: added `mag == X || mag == Y` to the check, so these calls handle the leftover elements with the scalar code.

### Tests

Same `Core_CartToPolar_inplace_mag.accuracy` test as #30646 (`CV_32F`, lengths 1 to 39, magnitude overwriting `x`, then `y`). On Apple M1 Pro it fails without the fix on 5.x and passes with it. The full `opencv_test_core` passes.

### 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
This commit is contained in:
Shiven Solanki
2026-11-08 16:47:11 +08:00
committed by GitHub
parent 1780d20b80
commit bb8cbcdb0b
2 changed files with 30 additions and 1 deletions

View File

@@ -115,7 +115,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;
}

View File

@@ -4022,6 +4022,35 @@ INSTANTIATE_TEST_CASE_P(Core_CartPolar, Core_CartToPolar_inplace,
)
);
typedef testing::TestWithParam<int> 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;