From cb7ee27cd9a2f06cf07c91eab1970be8d9232678 Mon Sep 17 00:00:00 2001 From: yuki takehara Date: Mon, 3 Sep 2018 23:18:10 +0900 Subject: [PATCH] Fix bug in distanceTransform (#12278) * fix 12218 * Update test_distancetransform.cpp marked the test as "BIGDATA_TEST" in order to skip it on low-mem platforms * modify test * use a smaller image in the test * fix test code --- modules/imgproc/src/distransform.cpp | 56 ++++++++++--------- .../imgproc/test/test_distancetransform.cpp | 19 +++++++ 2 files changed, 49 insertions(+), 26 deletions(-) diff --git a/modules/imgproc/src/distransform.cpp b/modules/imgproc/src/distransform.cpp index b573b3d552..173e79ed85 100644 --- a/modules/imgproc/src/distransform.cpp +++ b/modules/imgproc/src/distransform.cpp @@ -45,7 +45,8 @@ namespace cv { static const int DIST_SHIFT = 16; -static const int INIT_DIST0 = (INT_MAX >> 2); +static const int INIT_DIST0 = INT_MAX; +static const int DIST_MAX = (INT_MAX >> 2); #define CV_FLT_TO_FIX(x,n) cvRound((x)*(1<<(n))) static void @@ -71,8 +72,8 @@ distanceTransform_3x3( const Mat& _src, Mat& _temp, Mat& _dist, const float* met { const int BORDER = 1; int i, j; - const int HV_DIST = CV_FLT_TO_FIX( metrics[0], DIST_SHIFT ); - const int DIAG_DIST = CV_FLT_TO_FIX( metrics[1], DIST_SHIFT ); + const unsigned int HV_DIST = CV_FLT_TO_FIX( metrics[0], DIST_SHIFT ); + const unsigned int DIAG_DIST = CV_FLT_TO_FIX( metrics[1], DIST_SHIFT ); const float scale = 1.f/(1 << DIST_SHIFT); const uchar* src = _src.ptr(); @@ -89,7 +90,7 @@ distanceTransform_3x3( const Mat& _src, Mat& _temp, Mat& _dist, const float* met for( i = 0; i < size.height; i++ ) { const uchar* s = src + i*srcstep; - int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER; + unsigned int* tmp = (unsigned int*)(temp + (i+BORDER)*step) + BORDER; for( j = 0; j < BORDER; j++ ) tmp[-j-1] = tmp[size.width + j] = INIT_DIST0; @@ -100,8 +101,8 @@ distanceTransform_3x3( const Mat& _src, Mat& _temp, Mat& _dist, const float* met tmp[j] = 0; else { - int t0 = tmp[j-step-1] + DIAG_DIST; - int t = tmp[j-step] + HV_DIST; + unsigned int t0 = tmp[j-step-1] + DIAG_DIST; + unsigned int t = tmp[j-step] + HV_DIST; if( t0 > t ) t0 = t; t = tmp[j-step+1] + DIAG_DIST; if( t0 > t ) t0 = t; @@ -116,14 +117,14 @@ distanceTransform_3x3( const Mat& _src, Mat& _temp, Mat& _dist, const float* met for( i = size.height - 1; i >= 0; i-- ) { float* d = (float*)(dist + i*dststep); - int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER; + unsigned int* tmp = (unsigned int*)(temp + (i+BORDER)*step) + BORDER; for( j = size.width - 1; j >= 0; j-- ) { - int t0 = tmp[j]; + unsigned int t0 = tmp[j]; if( t0 > HV_DIST ) { - int t = tmp[j+step+1] + DIAG_DIST; + unsigned int t = tmp[j+step+1] + DIAG_DIST; if( t0 > t ) t0 = t; t = tmp[j+step] + HV_DIST; if( t0 > t ) t0 = t; @@ -133,6 +134,7 @@ distanceTransform_3x3( const Mat& _src, Mat& _temp, Mat& _dist, const float* met if( t0 > t ) t0 = t; tmp[j] = t0; } + t0 = (t0 > DIST_MAX) ? DIST_MAX : t0; d[j] = (float)(t0 * scale); } } @@ -144,9 +146,9 @@ distanceTransform_5x5( const Mat& _src, Mat& _temp, Mat& _dist, const float* met { const int BORDER = 2; int i, j; - const int HV_DIST = CV_FLT_TO_FIX( metrics[0], DIST_SHIFT ); - const int DIAG_DIST = CV_FLT_TO_FIX( metrics[1], DIST_SHIFT ); - const int LONG_DIST = CV_FLT_TO_FIX( metrics[2], DIST_SHIFT ); + const unsigned int HV_DIST = CV_FLT_TO_FIX( metrics[0], DIST_SHIFT ); + const unsigned int DIAG_DIST = CV_FLT_TO_FIX( metrics[1], DIST_SHIFT ); + const unsigned int LONG_DIST = CV_FLT_TO_FIX( metrics[2], DIST_SHIFT ); const float scale = 1.f/(1 << DIST_SHIFT); const uchar* src = _src.ptr(); @@ -163,7 +165,7 @@ distanceTransform_5x5( const Mat& _src, Mat& _temp, Mat& _dist, const float* met for( i = 0; i < size.height; i++ ) { const uchar* s = src + i*srcstep; - int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER; + unsigned int* tmp = (unsigned int*)(temp + (i+BORDER)*step) + BORDER; for( j = 0; j < BORDER; j++ ) tmp[-j-1] = tmp[size.width + j] = INIT_DIST0; @@ -174,8 +176,8 @@ distanceTransform_5x5( const Mat& _src, Mat& _temp, Mat& _dist, const float* met tmp[j] = 0; else { - int t0 = tmp[j-step*2-1] + LONG_DIST; - int t = tmp[j-step*2+1] + LONG_DIST; + unsigned int t0 = tmp[j-step*2-1] + LONG_DIST; + unsigned int t = tmp[j-step*2+1] + LONG_DIST; if( t0 > t ) t0 = t; t = tmp[j-step-2] + LONG_DIST; if( t0 > t ) t0 = t; @@ -198,14 +200,14 @@ distanceTransform_5x5( const Mat& _src, Mat& _temp, Mat& _dist, const float* met for( i = size.height - 1; i >= 0; i-- ) { float* d = (float*)(dist + i*dststep); - int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER; + unsigned int* tmp = (unsigned int*)(temp + (i+BORDER)*step) + BORDER; for( j = size.width - 1; j >= 0; j-- ) { - int t0 = tmp[j]; + unsigned int t0 = tmp[j]; if( t0 > HV_DIST ) { - int t = tmp[j+step*2+1] + LONG_DIST; + unsigned int t = tmp[j+step*2+1] + LONG_DIST; if( t0 > t ) t0 = t; t = tmp[j+step*2-1] + LONG_DIST; if( t0 > t ) t0 = t; @@ -223,6 +225,7 @@ distanceTransform_5x5( const Mat& _src, Mat& _temp, Mat& _dist, const float* met if( t0 > t ) t0 = t; tmp[j] = t0; } + t0 = (t0 > DIST_MAX) ? DIST_MAX : t0; d[j] = (float)(t0 * scale); } } @@ -235,9 +238,9 @@ distanceTransformEx_5x5( const Mat& _src, Mat& _temp, Mat& _dist, Mat& _labels, const int BORDER = 2; int i, j; - const int HV_DIST = CV_FLT_TO_FIX( metrics[0], DIST_SHIFT ); - const int DIAG_DIST = CV_FLT_TO_FIX( metrics[1], DIST_SHIFT ); - const int LONG_DIST = CV_FLT_TO_FIX( metrics[2], DIST_SHIFT ); + const unsigned int HV_DIST = CV_FLT_TO_FIX( metrics[0], DIST_SHIFT ); + const unsigned int DIAG_DIST = CV_FLT_TO_FIX( metrics[1], DIST_SHIFT ); + const unsigned int LONG_DIST = CV_FLT_TO_FIX( metrics[2], DIST_SHIFT ); const float scale = 1.f/(1 << DIST_SHIFT); const uchar* src = _src.ptr(); @@ -256,7 +259,7 @@ distanceTransformEx_5x5( const Mat& _src, Mat& _temp, Mat& _dist, Mat& _labels, for( i = 0; i < size.height; i++ ) { const uchar* s = src + i*srcstep; - int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER; + unsigned int* tmp = (unsigned int*)(temp + (i+BORDER)*step) + BORDER; int* lls = (int*)(labels + i*lstep); for( j = 0; j < BORDER; j++ ) @@ -271,7 +274,7 @@ distanceTransformEx_5x5( const Mat& _src, Mat& _temp, Mat& _dist, Mat& _labels, } else { - int t0 = INIT_DIST0, t; + unsigned int t0 = INIT_DIST0, t; int l0 = 0; t = tmp[j-step*2-1] + LONG_DIST; @@ -333,16 +336,16 @@ distanceTransformEx_5x5( const Mat& _src, Mat& _temp, Mat& _dist, Mat& _labels, for( i = size.height - 1; i >= 0; i-- ) { float* d = (float*)(dist + i*dststep); - int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER; + unsigned int* tmp = (unsigned int*)(temp + (i+BORDER)*step) + BORDER; int* lls = (int*)(labels + i*lstep); for( j = size.width - 1; j >= 0; j-- ) { - int t0 = tmp[j]; + unsigned int t0 = tmp[j]; int l0 = lls[j]; if( t0 > HV_DIST ) { - int t = tmp[j+step*2+1] + LONG_DIST; + unsigned int t = tmp[j+step*2+1] + LONG_DIST; if( t0 > t ) { t0 = t; @@ -393,6 +396,7 @@ distanceTransformEx_5x5( const Mat& _src, Mat& _temp, Mat& _dist, Mat& _labels, tmp[j] = t0; lls[j] = l0; } + t0 = (t0 > DIST_MAX) ? DIST_MAX : t0; d[j] = (float)(t0 * scale); } } diff --git a/modules/imgproc/test/test_distancetransform.cpp b/modules/imgproc/test/test_distancetransform.cpp index de99a08517..75ec5ec8fa 100644 --- a/modules/imgproc/test/test_distancetransform.cpp +++ b/modules/imgproc/test/test_distancetransform.cpp @@ -283,4 +283,23 @@ void CV_DisTransTest::prepare_to_validation( int /*test_case_idx*/ ) TEST(Imgproc_DistanceTransform, accuracy) { CV_DisTransTest test; test.safe_run(); } +BIGDATA_TEST(Imgproc_DistanceTransform, large_image_12218) +{ + const int lls_maxcnt = 79992000; // labels's maximum count + const int lls_mincnt = 1; // labels's minimum count + int i, j, nz; + Mat src(8000, 20000, CV_8UC1), dst, labels; + for( i = 0; i < src.rows; i++ ) + for( j = 0; j < src.cols; j++ ) + src.at(i, j) = (j > (src.cols / 2)) ? 0 : 255; + + distanceTransform(src, dst, labels, cv::DIST_L2, cv::DIST_MASK_3, DIST_LABEL_PIXEL); + + double scale = (double)lls_mincnt / (double)lls_maxcnt; + labels.convertTo(labels, CV_32SC1, scale); + Size size = labels.size(); + nz = cv::countNonZero(labels); + EXPECT_EQ(nz, (size.height*size.width / 2)); +} + }} // namespace