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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user