1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-29 23:33:05 +04:00

Merge pull request #27432 from dkurt:d.kurtaev/ipp_distTransform

Correct IPP distanceTransform results with single thread #27432

### Pull Request Readiness Checklist

resolves #24082

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
This commit is contained in:
Dmitry Kurtaev
2025-06-11 17:37:18 +03:00
committed by GitHub
parent b395a2e307
commit d750d43aa2
2 changed files with 49 additions and 0 deletions
+16
View File
@@ -796,6 +796,22 @@ void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labe
ippFree( pBuffer );
if (status>=0)
{
// https://github.com/opencv/opencv/issues/24082
// There is probably a rounding issue that leads to non-deterministic behavior
// between runs on positions closer to zeros by x-axis in straight direction.
// As a workaround, we detect the distances that expected to be exact
// number of pixels and round manually.
static const float correctionDiff = 1.0f / (1 << 11);
for (int i = 0; i < dst.rows; ++i)
{
float* row = dst.ptr<float>(i);
for (int j = 0; j < dst.cols; ++j)
{
float rounded = static_cast<float>(cvRound(row[j]));
if (fabs(row[j] - rounded) <= correctionDiff)
row[j] = rounded;
}
}
CV_IMPL_ADD(CV_IMPL_IPP);
return;
}
@@ -416,4 +416,37 @@ TEST(Imgproc_DistanceTransform, precise_long_dist)
EXPECT_EQ(cv::norm(expected, dist, NORM_INF), 0);
}
TEST(Imgproc_DistanceTransform, ipp_deterministic_corner)
{
setNumThreads(1);
Mat src(1, 4096, CV_8U, Scalar(255)), dist;
src.at<uint8_t>(0, 0) = 0;
distanceTransform(src, dist, DIST_L2, DIST_MASK_PRECISE);
for (int i = 0; i < src.cols; ++i)
{
float expected = static_cast<float>(i);
ASSERT_EQ(expected, dist.at<float>(0, i)) << cv::format("diff: %e", expected - dist.at<float>(0, i));
}
}
TEST(Imgproc_DistanceTransform, ipp_deterministic)
{
setNumThreads(1);
RNG& rng = TS::ptr()->get_rng();
Mat src(1, 800, CV_8U, Scalar(255)), dist;
int p1 = cvtest::randInt(rng) % src.cols;
int p2 = cvtest::randInt(rng) % src.cols;
int p3 = cvtest::randInt(rng) % src.cols;
src.at<uint8_t>(0, p1) = 0;
src.at<uint8_t>(0, p2) = 0;
src.at<uint8_t>(0, p3) = 0;
distanceTransform(src, dist, DIST_L2, DIST_MASK_PRECISE);
for (int i = 0; i < src.cols; ++i)
{
float expected = static_cast<float>(min(min(abs(i - p1), abs(i - p2)), abs(i - p3)));
ASSERT_EQ(expected, dist.at<float>(0, i)) << cv::format("diff: %e", expected - dist.at<float>(0, i));
}
}
}} // namespace