From 4dd54bbec92ae399d98b41dcf7a167b2c6aa4c51 Mon Sep 17 00:00:00 2001 From: _Ayaka <33724737+Octopus136@users.noreply.github.com> Date: Fri, 19 Jul 2024 14:08:19 +0800 Subject: [PATCH] Merge pull request #25898 from Octopus136:issue-25853 Add a check for src == dst in ocl warpTransform #25898 As mentioned in #25853, when doing WarpAffine with Mat and UMat respectively, if you force the use of the in-place operation (so that src and dst are passed the same variables), Mat produces the correct results, but UMat produces unexpected results. Obviously in-place operations are not possible with this transformation. When Mat performs the operation, if dst and src are the same variable, the function inherently makes a copy of src without telling the user. https://github.com/opencv/opencv/blob/74b50c7af05c91194469a1f059f971dff00ef889/modules/imgproc/src/imgwarp.cpp#L2831-L2834 So I did the same check in UMat, but I'm not sure if it's appropriate, should we just do a copy operation without telling the user (even if the user thinks he's doing an in-place operation), or should we throw an exception to indicate that we shouldn't pass in two same variables here? The possible reason for this problem is that there is a create function here, so it gives the developer the false impression that this create function has allocated new memory for dst, however it does not. https://github.com/opencv/opencv/blob/74b50c7af05c91194469a1f059f971dff00ef889/modules/imgproc/src/imgwarp.cpp#L2607-L2609 Because by the time the check is done here, the function has returned back. https://github.com/opencv/opencv/blob/74b50c7af05c91194469a1f059f971dff00ef889/modules/core/src/umatrix.cpp#L668-L675 ### 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. - [x] The feature is well documented and sample code can be built with the project CMake --- modules/imgproc/src/imgwarp.cpp | 6 ++++++ modules/imgproc/test/ocl/test_warp.cpp | 20 ++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/modules/imgproc/src/imgwarp.cpp b/modules/imgproc/src/imgwarp.cpp index d7c9c64c3c..c0eaf8114c 100644 --- a/modules/imgproc/src/imgwarp.cpp +++ b/modules/imgproc/src/imgwarp.cpp @@ -2501,6 +2501,9 @@ static bool ocl_warpTransform_cols4(InputArray _src, OutputArray _dst, InputArra _dst.create( dsize.empty() ? src.size() : dsize, src.type() ); UMat dst = _dst.getUMat(); + if (src.u == dst.u) + src = src.clone(); + float M[9] = {0}; int matRows = (op_type == OCL_OP_AFFINE ? 2 : 3); Mat matM(matRows, 3, CV_32F, M), M1 = _M0.getMat(); @@ -2605,6 +2608,9 @@ static bool ocl_warpTransform(InputArray _src, OutputArray _dst, InputArray _M0, _dst.create( dsize.empty() ? src.size() : dsize, src.type() ); UMat dst = _dst.getUMat(); + if (src.u == dst.u) + src = src.clone(); + double M[9] = {0}; int matRows = (op_type == OCL_OP_AFFINE ? 2 : 3); Mat matM(matRows, 3, CV_64F, M), M1 = _M0.getMat(); diff --git a/modules/imgproc/test/ocl/test_warp.cpp b/modules/imgproc/test/ocl/test_warp.cpp index 852dc465ab..73d93bb41f 100644 --- a/modules/imgproc/test/ocl/test_warp.cpp +++ b/modules/imgproc/test/ocl/test_warp.cpp @@ -185,6 +185,26 @@ OCL_TEST_P(WarpAffine, Mat) } } +OCL_TEST_P(WarpAffine, inplace_25853) // when src and dst are the same variable, ocl on/off should produce consistent and correct results +{ + for (int j = 0; j < test_loop_times; j++) + { + double eps = depth < CV_32F ? 0.04 : 0.06; + random_roi(); + + Mat M = getRotationMatrix2D(Point2f(src_roi.cols / 2.0f, src_roi.rows / 2.0f), + rng.uniform(-180.f, 180.f), rng.uniform(0.4f, 2.0f)); + + OCL_OFF(cv::warpAffine(src_roi, src_roi, M, dsize, interpolation)); + OCL_ON(cv::warpAffine(usrc_roi, usrc_roi, M, dsize, interpolation)); + + dst_roi = src_roi.clone(); + udst_roi = usrc_roi.clone(); + + Near(eps); + } +} + typedef WarpTest_cols4_Base WarpAffine_cols4; OCL_TEST_P(WarpAffine_cols4, Mat)