Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of gr-peach-opencv-project-sd-card by
distransform.cpp
00001 /*M/////////////////////////////////////////////////////////////////////////////////////// 00002 // 00003 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. 00004 // 00005 // By downloading, copying, installing or using the software you agree to this license. 00006 // If you do not agree to this license, do not download, install, 00007 // copy or use the software. 00008 // 00009 // 00010 // License Agreement 00011 // For Open Source Computer Vision Library 00012 // 00013 // Copyright (C) 2000, Intel Corporation, all rights reserved. 00014 // Copyright (C) 2013, OpenCV Foundation, all rights reserved. 00015 // Third party copyrights are property of their respective owners. 00016 // 00017 // Redistribution and use in source and binary forms, with or without modification, 00018 // are permitted provided that the following conditions are met: 00019 // 00020 // * Redistribution's of source code must retain the above copyright notice, 00021 // this list of conditions and the following disclaimer. 00022 // 00023 // * Redistribution's in binary form must reproduce the above copyright notice, 00024 // this list of conditions and the following disclaimer in the documentation 00025 // and/or other materials provided with the distribution. 00026 // 00027 // * The name of the copyright holders may not be used to endorse or promote products 00028 // derived from this software without specific prior written permission. 00029 // 00030 // This software is provided by the copyright holders and contributors "as is" and 00031 // any express or implied warranties, including, but not limited to, the implied 00032 // warranties of merchantability and fitness for a particular purpose are disclaimed. 00033 // In no event shall the Intel Corporation or contributors be liable for any direct, 00034 // indirect, incidental, special, exemplary, or consequential damages 00035 // (including, but not limited to, procurement of substitute goods or services; 00036 // loss of use, data, or profits; or business interruption) however caused 00037 // and on any theory of liability, whether in contract, strict liability, 00038 // or tort (including negligence or otherwise) arising in any way out of 00039 // the use of this software, even if advised of the possibility of such damage. 00040 // 00041 //M*/ 00042 #include "precomp.hpp" 00043 00044 namespace cv 00045 { 00046 00047 static const int DIST_SHIFT = 16; 00048 static const int INIT_DIST0 = (INT_MAX >> 2); 00049 #define CV_FLT_TO_FIX(x,n) cvRound((x)*(1<<(n))) 00050 00051 static void 00052 initTopBottom( Mat& temp, int border ) 00053 { 00054 Size size = temp.size(); 00055 for( int i = 0; i < border; i++ ) 00056 { 00057 int* ttop = temp.ptr<int>(i); 00058 int* tbottom = temp.ptr<int>(size.height - i - 1); 00059 00060 for( int j = 0; j < size.width; j++ ) 00061 { 00062 ttop[j] = INIT_DIST0; 00063 tbottom[j] = INIT_DIST0; 00064 } 00065 } 00066 } 00067 00068 00069 static void 00070 distanceTransform_3x3( const Mat& _src, Mat& _temp, Mat& _dist, const float* metrics ) 00071 { 00072 const int BORDER = 1; 00073 int i, j; 00074 const int HV_DIST = CV_FLT_TO_FIX( metrics[0], DIST_SHIFT ); 00075 const int DIAG_DIST = CV_FLT_TO_FIX( metrics[1], DIST_SHIFT ); 00076 const float scale = 1.f/(1 << DIST_SHIFT); 00077 00078 const uchar* src = _src.ptr(); 00079 int* temp = _temp.ptr<int>(); 00080 float* dist = _dist.ptr<float>(); 00081 int srcstep = (int)(_src.step/sizeof(src[0])); 00082 int step = (int)(_temp.step/sizeof(temp[0])); 00083 int dststep = (int)(_dist.step/sizeof(dist[0])); 00084 Size size = _src.size(); 00085 00086 initTopBottom( _temp, BORDER ); 00087 00088 // forward pass 00089 for( i = 0; i < size.height; i++ ) 00090 { 00091 const uchar* s = src + i*srcstep; 00092 int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER; 00093 00094 for( j = 0; j < BORDER; j++ ) 00095 tmp[-j-1] = tmp[size.width + j] = INIT_DIST0; 00096 00097 for( j = 0; j < size.width; j++ ) 00098 { 00099 if( !s[j] ) 00100 tmp[j] = 0; 00101 else 00102 { 00103 int t0 = tmp[j-step-1] + DIAG_DIST; 00104 int t = tmp[j-step] + HV_DIST; 00105 if( t0 > t ) t0 = t; 00106 t = tmp[j-step+1] + DIAG_DIST; 00107 if( t0 > t ) t0 = t; 00108 t = tmp[j-1] + HV_DIST; 00109 if( t0 > t ) t0 = t; 00110 tmp[j] = t0; 00111 } 00112 } 00113 } 00114 00115 // backward pass 00116 for( i = size.height - 1; i >= 0; i-- ) 00117 { 00118 float* d = (float*)(dist + i*dststep); 00119 int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER; 00120 00121 for( j = size.width - 1; j >= 0; j-- ) 00122 { 00123 int t0 = tmp[j]; 00124 if( t0 > HV_DIST ) 00125 { 00126 int t = tmp[j+step+1] + DIAG_DIST; 00127 if( t0 > t ) t0 = t; 00128 t = tmp[j+step] + HV_DIST; 00129 if( t0 > t ) t0 = t; 00130 t = tmp[j+step-1] + DIAG_DIST; 00131 if( t0 > t ) t0 = t; 00132 t = tmp[j+1] + HV_DIST; 00133 if( t0 > t ) t0 = t; 00134 tmp[j] = t0; 00135 } 00136 d[j] = (float)(t0 * scale); 00137 } 00138 } 00139 } 00140 00141 00142 static void 00143 distanceTransform_5x5( const Mat& _src, Mat& _temp, Mat& _dist, const float* metrics ) 00144 { 00145 const int BORDER = 2; 00146 int i, j; 00147 const int HV_DIST = CV_FLT_TO_FIX( metrics[0], DIST_SHIFT ); 00148 const int DIAG_DIST = CV_FLT_TO_FIX( metrics[1], DIST_SHIFT ); 00149 const int LONG_DIST = CV_FLT_TO_FIX( metrics[2], DIST_SHIFT ); 00150 const float scale = 1.f/(1 << DIST_SHIFT); 00151 00152 const uchar* src = _src.ptr(); 00153 int* temp = _temp.ptr<int>(); 00154 float* dist = _dist.ptr<float>(); 00155 int srcstep = (int)(_src.step/sizeof(src[0])); 00156 int step = (int)(_temp.step/sizeof(temp[0])); 00157 int dststep = (int)(_dist.step/sizeof(dist[0])); 00158 Size size = _src.size(); 00159 00160 initTopBottom( _temp, BORDER ); 00161 00162 // forward pass 00163 for( i = 0; i < size.height; i++ ) 00164 { 00165 const uchar* s = src + i*srcstep; 00166 int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER; 00167 00168 for( j = 0; j < BORDER; j++ ) 00169 tmp[-j-1] = tmp[size.width + j] = INIT_DIST0; 00170 00171 for( j = 0; j < size.width; j++ ) 00172 { 00173 if( !s[j] ) 00174 tmp[j] = 0; 00175 else 00176 { 00177 int t0 = tmp[j-step*2-1] + LONG_DIST; 00178 int t = tmp[j-step*2+1] + LONG_DIST; 00179 if( t0 > t ) t0 = t; 00180 t = tmp[j-step-2] + LONG_DIST; 00181 if( t0 > t ) t0 = t; 00182 t = tmp[j-step-1] + DIAG_DIST; 00183 if( t0 > t ) t0 = t; 00184 t = tmp[j-step] + HV_DIST; 00185 if( t0 > t ) t0 = t; 00186 t = tmp[j-step+1] + DIAG_DIST; 00187 if( t0 > t ) t0 = t; 00188 t = tmp[j-step+2] + LONG_DIST; 00189 if( t0 > t ) t0 = t; 00190 t = tmp[j-1] + HV_DIST; 00191 if( t0 > t ) t0 = t; 00192 tmp[j] = t0; 00193 } 00194 } 00195 } 00196 00197 // backward pass 00198 for( i = size.height - 1; i >= 0; i-- ) 00199 { 00200 float* d = (float*)(dist + i*dststep); 00201 int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER; 00202 00203 for( j = size.width - 1; j >= 0; j-- ) 00204 { 00205 int t0 = tmp[j]; 00206 if( t0 > HV_DIST ) 00207 { 00208 int t = tmp[j+step*2+1] + LONG_DIST; 00209 if( t0 > t ) t0 = t; 00210 t = tmp[j+step*2-1] + LONG_DIST; 00211 if( t0 > t ) t0 = t; 00212 t = tmp[j+step+2] + LONG_DIST; 00213 if( t0 > t ) t0 = t; 00214 t = tmp[j+step+1] + DIAG_DIST; 00215 if( t0 > t ) t0 = t; 00216 t = tmp[j+step] + HV_DIST; 00217 if( t0 > t ) t0 = t; 00218 t = tmp[j+step-1] + DIAG_DIST; 00219 if( t0 > t ) t0 = t; 00220 t = tmp[j+step-2] + LONG_DIST; 00221 if( t0 > t ) t0 = t; 00222 t = tmp[j+1] + HV_DIST; 00223 if( t0 > t ) t0 = t; 00224 tmp[j] = t0; 00225 } 00226 d[j] = (float)(t0 * scale); 00227 } 00228 } 00229 } 00230 00231 00232 static void 00233 distanceTransformEx_5x5( const Mat& _src, Mat& _temp, Mat& _dist, Mat& _labels, const float* metrics ) 00234 { 00235 const int BORDER = 2; 00236 00237 int i, j; 00238 const int HV_DIST = CV_FLT_TO_FIX( metrics[0], DIST_SHIFT ); 00239 const int DIAG_DIST = CV_FLT_TO_FIX( metrics[1], DIST_SHIFT ); 00240 const int LONG_DIST = CV_FLT_TO_FIX( metrics[2], DIST_SHIFT ); 00241 const float scale = 1.f/(1 << DIST_SHIFT); 00242 00243 const uchar* src = _src.ptr(); 00244 int* temp = _temp.ptr<int>(); 00245 float* dist = _dist.ptr<float>(); 00246 int* labels = _labels.ptr<int>(); 00247 int srcstep = (int)(_src.step/sizeof(src[0])); 00248 int step = (int)(_temp.step/sizeof(temp[0])); 00249 int dststep = (int)(_dist.step/sizeof(dist[0])); 00250 int lstep = (int)(_labels.step/sizeof(dist[0])); 00251 Size size = _src.size(); 00252 00253 initTopBottom( _temp, BORDER ); 00254 00255 // forward pass 00256 for( i = 0; i < size.height; i++ ) 00257 { 00258 const uchar* s = src + i*srcstep; 00259 int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER; 00260 int* lls = (int*)(labels + i*lstep); 00261 00262 for( j = 0; j < BORDER; j++ ) 00263 tmp[-j-1] = tmp[size.width + j] = INIT_DIST0; 00264 00265 for( j = 0; j < size.width; j++ ) 00266 { 00267 if( !s[j] ) 00268 { 00269 tmp[j] = 0; 00270 //assert( lls[j] != 0 ); 00271 } 00272 else 00273 { 00274 int t0 = INIT_DIST0, t; 00275 int l0 = 0; 00276 00277 t = tmp[j-step*2-1] + LONG_DIST; 00278 if( t0 > t ) 00279 { 00280 t0 = t; 00281 l0 = lls[j-lstep*2-1]; 00282 } 00283 t = tmp[j-step*2+1] + LONG_DIST; 00284 if( t0 > t ) 00285 { 00286 t0 = t; 00287 l0 = lls[j-lstep*2+1]; 00288 } 00289 t = tmp[j-step-2] + LONG_DIST; 00290 if( t0 > t ) 00291 { 00292 t0 = t; 00293 l0 = lls[j-lstep-2]; 00294 } 00295 t = tmp[j-step-1] + DIAG_DIST; 00296 if( t0 > t ) 00297 { 00298 t0 = t; 00299 l0 = lls[j-lstep-1]; 00300 } 00301 t = tmp[j-step] + HV_DIST; 00302 if( t0 > t ) 00303 { 00304 t0 = t; 00305 l0 = lls[j-lstep]; 00306 } 00307 t = tmp[j-step+1] + DIAG_DIST; 00308 if( t0 > t ) 00309 { 00310 t0 = t; 00311 l0 = lls[j-lstep+1]; 00312 } 00313 t = tmp[j-step+2] + LONG_DIST; 00314 if( t0 > t ) 00315 { 00316 t0 = t; 00317 l0 = lls[j-lstep+2]; 00318 } 00319 t = tmp[j-1] + HV_DIST; 00320 if( t0 > t ) 00321 { 00322 t0 = t; 00323 l0 = lls[j-1]; 00324 } 00325 00326 tmp[j] = t0; 00327 lls[j] = l0; 00328 } 00329 } 00330 } 00331 00332 // backward pass 00333 for( i = size.height - 1; i >= 0; i-- ) 00334 { 00335 float* d = (float*)(dist + i*dststep); 00336 int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER; 00337 int* lls = (int*)(labels + i*lstep); 00338 00339 for( j = size.width - 1; j >= 0; j-- ) 00340 { 00341 int t0 = tmp[j]; 00342 int l0 = lls[j]; 00343 if( t0 > HV_DIST ) 00344 { 00345 int t = tmp[j+step*2+1] + LONG_DIST; 00346 if( t0 > t ) 00347 { 00348 t0 = t; 00349 l0 = lls[j+lstep*2+1]; 00350 } 00351 t = tmp[j+step*2-1] + LONG_DIST; 00352 if( t0 > t ) 00353 { 00354 t0 = t; 00355 l0 = lls[j+lstep*2-1]; 00356 } 00357 t = tmp[j+step+2] + LONG_DIST; 00358 if( t0 > t ) 00359 { 00360 t0 = t; 00361 l0 = lls[j+lstep+2]; 00362 } 00363 t = tmp[j+step+1] + DIAG_DIST; 00364 if( t0 > t ) 00365 { 00366 t0 = t; 00367 l0 = lls[j+lstep+1]; 00368 } 00369 t = tmp[j+step] + HV_DIST; 00370 if( t0 > t ) 00371 { 00372 t0 = t; 00373 l0 = lls[j+lstep]; 00374 } 00375 t = tmp[j+step-1] + DIAG_DIST; 00376 if( t0 > t ) 00377 { 00378 t0 = t; 00379 l0 = lls[j+lstep-1]; 00380 } 00381 t = tmp[j+step-2] + LONG_DIST; 00382 if( t0 > t ) 00383 { 00384 t0 = t; 00385 l0 = lls[j+lstep-2]; 00386 } 00387 t = tmp[j+1] + HV_DIST; 00388 if( t0 > t ) 00389 { 00390 t0 = t; 00391 l0 = lls[j+1]; 00392 } 00393 tmp[j] = t0; 00394 lls[j] = l0; 00395 } 00396 d[j] = (float)(t0 * scale); 00397 } 00398 } 00399 } 00400 00401 00402 static void getDistanceTransformMask( int maskType, float *metrics ) 00403 { 00404 CV_Assert( metrics != 0 ); 00405 00406 switch (maskType) 00407 { 00408 case 30: 00409 metrics[0] = 1.0f; 00410 metrics[1] = 1.0f; 00411 break; 00412 00413 case 31: 00414 metrics[0] = 1.0f; 00415 metrics[1] = 2.0f; 00416 break; 00417 00418 case 32: 00419 metrics[0] = 0.955f; 00420 metrics[1] = 1.3693f; 00421 break; 00422 00423 case 50: 00424 metrics[0] = 1.0f; 00425 metrics[1] = 1.0f; 00426 metrics[2] = 2.0f; 00427 break; 00428 00429 case 51: 00430 metrics[0] = 1.0f; 00431 metrics[1] = 2.0f; 00432 metrics[2] = 3.0f; 00433 break; 00434 00435 case 52: 00436 metrics[0] = 1.0f; 00437 metrics[1] = 1.4f; 00438 metrics[2] = 2.1969f; 00439 break; 00440 default: 00441 CV_Error(CV_StsBadArg, "Unknown metric type"); 00442 } 00443 } 00444 00445 struct DTColumnInvoker : ParallelLoopBody 00446 { 00447 DTColumnInvoker( const Mat* _src, Mat* _dst, const int* _sat_tab, const float* _sqr_tab) 00448 { 00449 src = _src; 00450 dst = _dst; 00451 sat_tab = _sat_tab + src->rows*2 + 1; 00452 sqr_tab = _sqr_tab; 00453 } 00454 00455 void operator()( const Range& range ) const 00456 { 00457 int i, i1 = range.start, i2 = range.end; 00458 int m = src->rows; 00459 size_t sstep = src->step, dstep = dst->step/sizeof(float); 00460 AutoBuffer<int> _d(m); 00461 int* d = _d; 00462 00463 for( i = i1; i < i2; i++ ) 00464 { 00465 const uchar* sptr = src->ptr(m-1) + i; 00466 float* dptr = dst->ptr<float>() + i; 00467 int j, dist = m-1; 00468 00469 for( j = m-1; j >= 0; j--, sptr -= sstep ) 00470 { 00471 dist = (dist + 1) & (sptr[0] == 0 ? 0 : -1); 00472 d[j] = dist; 00473 } 00474 00475 dist = m-1; 00476 for( j = 0; j < m; j++, dptr += dstep ) 00477 { 00478 dist = dist + 1 - sat_tab[dist - d[j]]; 00479 d[j] = dist; 00480 dptr[0] = sqr_tab[dist]; 00481 } 00482 } 00483 } 00484 00485 const Mat* src; 00486 Mat* dst; 00487 const int* sat_tab; 00488 const float* sqr_tab; 00489 }; 00490 00491 struct DTRowInvoker : ParallelLoopBody 00492 { 00493 DTRowInvoker( Mat* _dst, const float* _sqr_tab, const float* _inv_tab ) 00494 { 00495 dst = _dst; 00496 sqr_tab = _sqr_tab; 00497 inv_tab = _inv_tab; 00498 } 00499 00500 void operator()( const Range& range ) const 00501 { 00502 const float inf = 1e15f; 00503 int i, i1 = range.start, i2 = range.end; 00504 int n = dst->cols; 00505 AutoBuffer<uchar> _buf((n+2)*2*sizeof(float) + (n+2)*sizeof(int)); 00506 float* f = (float*)(uchar*)_buf; 00507 float* z = f + n; 00508 int* v = alignPtr((int*)(z + n + 1), sizeof(int)); 00509 00510 for( i = i1; i < i2; i++ ) 00511 { 00512 float* d = dst->ptr<float>(i); 00513 int p, q, k; 00514 00515 v[0] = 0; 00516 z[0] = -inf; 00517 z[1] = inf; 00518 f[0] = d[0]; 00519 00520 for( q = 1, k = 0; q < n; q++ ) 00521 { 00522 float fq = d[q]; 00523 f[q] = fq; 00524 00525 for(;;k--) 00526 { 00527 p = v[k]; 00528 float s = (fq + sqr_tab[q] - d[p] - sqr_tab[p])*inv_tab[q - p]; 00529 if( s > z[k] ) 00530 { 00531 k++; 00532 v[k] = q; 00533 z[k] = s; 00534 z[k+1] = inf; 00535 break; 00536 } 00537 } 00538 } 00539 00540 for( q = 0, k = 0; q < n; q++ ) 00541 { 00542 while( z[k+1] < q ) 00543 k++; 00544 p = v[k]; 00545 d[q] = std::sqrt(sqr_tab[std::abs(q - p)] + f[p]); 00546 } 00547 } 00548 } 00549 00550 Mat* dst; 00551 const float* sqr_tab; 00552 const float* inv_tab; 00553 }; 00554 00555 static void 00556 trueDistTrans( const Mat& src, Mat& dst ) 00557 { 00558 const float inf = 1e15f; 00559 00560 CV_Assert( src.size() == dst.size() ); 00561 00562 CV_Assert( src.type() == CV_8UC1 && dst.type() == CV_32FC1 ); 00563 int i, m = src.rows, n = src.cols; 00564 00565 cv::AutoBuffer<uchar> _buf(std::max(m*2*sizeof(float) + (m*3+1)*sizeof(int), n*2*sizeof(float))); 00566 // stage 1: compute 1d distance transform of each column 00567 float* sqr_tab = (float*)(uchar*)_buf; 00568 int* sat_tab = cv::alignPtr((int*)(sqr_tab + m*2), sizeof(int)); 00569 int shift = m*2; 00570 00571 for( i = 0; i < m; i++ ) 00572 sqr_tab[i] = (float)(i*i); 00573 for( i = m; i < m*2; i++ ) 00574 sqr_tab[i] = inf; 00575 for( i = 0; i < shift; i++ ) 00576 sat_tab[i] = 0; 00577 for( ; i <= m*3; i++ ) 00578 sat_tab[i] = i - shift; 00579 00580 cv::parallel_for_(cv::Range(0, n), cv::DTColumnInvoker(&src, &dst, sat_tab, sqr_tab), src.total()/(double)(1<<16)); 00581 00582 // stage 2: compute modified distance transform for each row 00583 float* inv_tab = sqr_tab + n; 00584 00585 inv_tab[0] = sqr_tab[0] = 0.f; 00586 for( i = 1; i < n; i++ ) 00587 { 00588 inv_tab[i] = (float)(0.5/i); 00589 sqr_tab[i] = (float)(i*i); 00590 } 00591 00592 cv::parallel_for_(cv::Range(0, m), cv::DTRowInvoker(&dst, sqr_tab, inv_tab)); 00593 } 00594 00595 00596 /****************************************************************************************\ 00597 Non-inplace and Inplace 8u->8u Distance Transform for CityBlock (a.k.a. L1) metric 00598 (C) 2006 by Jay Stavinzky. 00599 \****************************************************************************************/ 00600 00601 //BEGIN ATS ADDITION 00602 // 8-bit grayscale distance transform function 00603 static void 00604 distanceATS_L1_8u( const Mat& src, Mat& dst ) 00605 { 00606 int width = src.cols, height = src.rows; 00607 00608 int a; 00609 uchar lut[256]; 00610 int x, y; 00611 00612 const uchar *sbase = src.ptr(); 00613 uchar *dbase = dst.ptr(); 00614 int srcstep = (int)src.step; 00615 int dststep = (int)dst.step; 00616 00617 CV_Assert( src.type() == CV_8UC1 && dst.type() == CV_8UC1 ); 00618 CV_Assert( src.size() == dst.size() ); 00619 00620 ////////////////////// forward scan //////////////////////// 00621 for( x = 0; x < 256; x++ ) 00622 lut[x] = cv::saturate_cast<uchar>(x+1); 00623 00624 //init first pixel to max (we're going to be skipping it) 00625 dbase[0] = (uchar)(sbase[0] == 0 ? 0 : 255); 00626 00627 //first row (scan west only, skip first pixel) 00628 for( x = 1; x < width; x++ ) 00629 dbase[x] = (uchar)(sbase[x] == 0 ? 0 : lut[dbase[x-1]]); 00630 00631 for( y = 1; y < height; y++ ) 00632 { 00633 sbase += srcstep; 00634 dbase += dststep; 00635 00636 //for left edge, scan north only 00637 a = sbase[0] == 0 ? 0 : lut[dbase[-dststep]]; 00638 dbase[0] = (uchar)a; 00639 00640 for( x = 1; x < width; x++ ) 00641 { 00642 a = sbase[x] == 0 ? 0 : lut[MIN(a, dbase[x - dststep])]; 00643 dbase[x] = (uchar)a; 00644 } 00645 } 00646 00647 ////////////////////// backward scan /////////////////////// 00648 00649 a = dbase[width-1]; 00650 00651 // do last row east pixel scan here (skip bottom right pixel) 00652 for( x = width - 2; x >= 0; x-- ) 00653 { 00654 a = lut[a]; 00655 dbase[x] = (uchar)(CV_CALC_MIN_8U(a, dbase[x])); 00656 } 00657 00658 // right edge is the only error case 00659 for( y = height - 2; y >= 0; y-- ) 00660 { 00661 dbase -= dststep; 00662 00663 // do right edge 00664 a = lut[dbase[width-1+dststep]]; 00665 a = dbase[width-1] = (uchar)(MIN(a, dbase[width-1])); 00666 00667 for( x = width - 2; x >= 0; x-- ) 00668 { 00669 int b = dbase[x+dststep]; 00670 a = lut[MIN(a, b)]; 00671 a = MIN(a, dbase[x]); 00672 dbase[x] = (uchar)(a); 00673 } 00674 } 00675 } 00676 //END ATS ADDITION 00677 00678 } 00679 00680 namespace cv 00681 { 00682 static void distanceTransform_L1_8U(InputArray _src, OutputArray _dst) 00683 { 00684 Mat src = _src.getMat(); 00685 00686 CV_Assert( src.type() == CV_8UC1); 00687 00688 _dst.create( src.size(), CV_8UC1); 00689 Mat dst = _dst.getMat(); 00690 00691 #ifdef HAVE_IPP 00692 CV_IPP_CHECK() 00693 { 00694 IppiSize roi = { src.cols, src.rows }; 00695 Ipp32s pMetrics[2] = { 1, 2 }; //L1, 3x3 mask 00696 if (ippiDistanceTransform_3x3_8u_C1R(src.ptr<uchar>(), (int)src.step, dst.ptr<uchar>(), (int)dst.step, roi, pMetrics)>=0) 00697 { 00698 CV_IMPL_ADD(CV_IMPL_IPP); 00699 return; 00700 } 00701 setIppErrorStatus(); 00702 } 00703 #endif 00704 00705 distanceATS_L1_8u(src, dst); 00706 } 00707 } 00708 00709 // Wrapper function for distance transform group 00710 void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labels, 00711 int distType, int maskSize, int labelType ) 00712 { 00713 Mat src = _src.getMat(), labels; 00714 bool need_labels = _labels.needed(); 00715 00716 CV_Assert( src.type() == CV_8UC1); 00717 00718 _dst.create( src.size(), CV_32F); 00719 Mat dst = _dst.getMat(); 00720 00721 if( need_labels ) 00722 { 00723 CV_Assert( labelType == DIST_LABEL_PIXEL || labelType == DIST_LABEL_CCOMP ); 00724 00725 _labels.create(src.size(), CV_32S); 00726 labels = _labels.getMat(); 00727 maskSize = CV_DIST_MASK_5; 00728 } 00729 00730 float _mask[5] = {0}; 00731 00732 if( maskSize != CV_DIST_MASK_3 && maskSize != CV_DIST_MASK_5 && maskSize != CV_DIST_MASK_PRECISE ) 00733 CV_Error( CV_StsBadSize, "Mask size should be 3 or 5 or 0 (precise)" ); 00734 00735 if( distType == CV_DIST_C || distType == CV_DIST_L1 ) 00736 maskSize = !need_labels ? CV_DIST_MASK_3 : CV_DIST_MASK_5; 00737 else if( distType == CV_DIST_L2 && need_labels ) 00738 maskSize = CV_DIST_MASK_5; 00739 00740 if( maskSize == CV_DIST_MASK_PRECISE ) 00741 { 00742 00743 #ifdef HAVE_IPP 00744 CV_IPP_CHECK() 00745 { 00746 if ((currentParallelFramework()==NULL) || (src.total()<(int)(1<<14))) 00747 { 00748 IppStatus status; 00749 IppiSize roi = { src.cols, src.rows }; 00750 Ipp8u *pBuffer; 00751 int bufSize=0; 00752 00753 status = ippiTrueDistanceTransformGetBufferSize_8u32f_C1R(roi, &bufSize); 00754 if (status>=0) 00755 { 00756 pBuffer = (Ipp8u *)ippMalloc( bufSize ); 00757 status = ippiTrueDistanceTransform_8u32f_C1R(src.ptr<uchar>(),(int)src.step, dst.ptr<float>(), (int)dst.step, roi, pBuffer); 00758 ippFree( pBuffer ); 00759 if (status>=0) 00760 { 00761 CV_IMPL_ADD(CV_IMPL_IPP); 00762 return; 00763 } 00764 setIppErrorStatus(); 00765 } 00766 } 00767 } 00768 #endif 00769 00770 trueDistTrans( src, dst ); 00771 return; 00772 } 00773 00774 CV_Assert( distType == CV_DIST_C || distType == CV_DIST_L1 || distType == CV_DIST_L2 ); 00775 00776 getDistanceTransformMask( (distType == CV_DIST_C ? 0 : 00777 distType == CV_DIST_L1 ? 1 : 2) + maskSize*10, _mask ); 00778 00779 Size size = src.size(); 00780 00781 int border = maskSize == CV_DIST_MASK_3 ? 1 : 2; 00782 Mat temp( size.height + border*2, size.width + border*2, CV_32SC1 ); 00783 00784 if( !need_labels ) 00785 { 00786 if( maskSize == CV_DIST_MASK_3 ) 00787 { 00788 #if defined (HAVE_IPP) && (IPP_VERSION_X100 >= 700) 00789 CV_IPP_CHECK() 00790 { 00791 IppiSize roi = { src.cols, src.rows }; 00792 if (ippiDistanceTransform_3x3_8u32f_C1R(src.ptr<uchar>(), (int)src.step, dst.ptr<float>(), (int)dst.step, roi, _mask)>=0) 00793 { 00794 CV_IMPL_ADD(CV_IMPL_IPP); 00795 return; 00796 } 00797 setIppErrorStatus(); 00798 } 00799 #endif 00800 00801 distanceTransform_3x3(src, temp, dst, _mask); 00802 } 00803 else 00804 { 00805 #if defined (HAVE_IPP) && (IPP_VERSION_X100 >= 700) 00806 CV_IPP_CHECK() 00807 { 00808 IppiSize roi = { src.cols, src.rows }; 00809 if (ippiDistanceTransform_5x5_8u32f_C1R(src.ptr<uchar>(), (int)src.step, dst.ptr<float>(), (int)dst.step, roi, _mask)>=0) 00810 { 00811 CV_IMPL_ADD(CV_IMPL_IPP); 00812 return; 00813 } 00814 setIppErrorStatus(); 00815 } 00816 #endif 00817 00818 distanceTransform_5x5(src, temp, dst, _mask); 00819 } 00820 } 00821 else 00822 { 00823 labels.setTo(Scalar::all(0)); 00824 00825 if( labelType == CV_DIST_LABEL_CCOMP ) 00826 { 00827 Mat zpix = src == 0; 00828 connectedComponents(zpix, labels, 8, CV_32S); 00829 } 00830 else 00831 { 00832 int k = 1; 00833 for( int i = 0; i < src.rows; i++ ) 00834 { 00835 const uchar* srcptr = src.ptr(i); 00836 int* labelptr = labels.ptr<int>(i); 00837 00838 for( int j = 0; j < src.cols; j++ ) 00839 if( srcptr[j] == 0 ) 00840 labelptr[j] = k++; 00841 } 00842 } 00843 00844 distanceTransformEx_5x5( src, temp, dst, labels, _mask ); 00845 } 00846 } 00847 00848 void cv::distanceTransform( InputArray _src, OutputArray _dst, 00849 int distanceType, int maskSize, int dstType) 00850 { 00851 if (distanceType == CV_DIST_L1 && dstType==CV_8U) 00852 distanceTransform_L1_8U(_src, _dst); 00853 else 00854 distanceTransform(_src, _dst, noArray(), distanceType, maskSize, DIST_LABEL_PIXEL); 00855 00856 } 00857 00858 CV_IMPL void 00859 cvDistTransform( const void* srcarr, void* dstarr, 00860 int distType, int maskSize, 00861 const float * /*mask*/, 00862 void* labelsarr, int labelType ) 00863 { 00864 cv::Mat src = cv::cvarrToMat(srcarr); 00865 const cv::Mat dst = cv::cvarrToMat(dstarr); 00866 const cv::Mat labels = cv::cvarrToMat(labelsarr); 00867 00868 cv::distanceTransform(src, dst, labelsarr ? cv::_OutputArray(labels) : cv::_OutputArray(), 00869 distType, maskSize, labelType); 00870 00871 } 00872 00873 00874 /* End of file. */ 00875
Generated on Tue Jul 12 2022 14:46:33 by
