1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 // By downloading, copying, installing or using the software you agree to this license.
6 // If you do not agree to this license, do not download, install,
7 // copy or use the software.
8 //
9 //
10 // License Agreement
11 // For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Copyright (C) 2013, OpenCV Foundation, all rights reserved.
15 // Third party copyrights are property of their respective owners.
16 //
17 // Redistribution and use in source and binary forms, with or without modification,
18 // are permitted provided that the following conditions are met:
19 //
20 // * Redistribution's of source code must retain the above copyright notice,
21 // this list of conditions and the following disclaimer.
22 //
23 // * Redistribution's in binary form must reproduce the above copyright notice,
24 // this list of conditions and the following disclaimer in the documentation
25 // and/or other materials provided with the distribution.
26 //
27 // * The name of the copyright holders may not be used to endorse or promote products
28 // derived from this software without specific prior written permission.
29 //
30 // This software is provided by the copyright holders and contributors "as is" and
31 // any express or implied warranties, including, but not limited to, the implied
32 // warranties of merchantability and fitness for a particular purpose are disclaimed.
33 // In no event shall the Intel Corporation or contributors be liable for any direct,
34 // indirect, incidental, special, exemplary, or consequential damages
35 // (including, but not limited to, procurement of substitute goods or services;
36 // loss of use, data, or profits; or business interruption) however caused
37 // and on any theory of liability, whether in contract, strict liability,
38 // or tort (including negligence or otherwise) arising in any way out of
39 // the use of this software, even if advised of the possibility of such damage.
40 //
41 //M*/
42 #include "precomp.hpp"
43
44 namespace cv
45 {
46
47 static const int DIST_SHIFT = 16;
48 static const int INIT_DIST0 = (INT_MAX >> 2);
49 #define CV_FLT_TO_FIX(x,n) cvRound((x)*(1<<(n)))
50
51 static void
initTopBottom(Mat & temp,int border)52 initTopBottom( Mat& temp, int border )
53 {
54 Size size = temp.size();
55 for( int i = 0; i < border; i++ )
56 {
57 int* ttop = temp.ptr<int>(i);
58 int* tbottom = temp.ptr<int>(size.height - i - 1);
59
60 for( int j = 0; j < size.width; j++ )
61 {
62 ttop[j] = INIT_DIST0;
63 tbottom[j] = INIT_DIST0;
64 }
65 }
66 }
67
68
69 static void
distanceTransform_3x3(const Mat & _src,Mat & _temp,Mat & _dist,const float * metrics)70 distanceTransform_3x3( const Mat& _src, Mat& _temp, Mat& _dist, const float* metrics )
71 {
72 const int BORDER = 1;
73 int i, j;
74 const int HV_DIST = CV_FLT_TO_FIX( metrics[0], DIST_SHIFT );
75 const int DIAG_DIST = CV_FLT_TO_FIX( metrics[1], DIST_SHIFT );
76 const float scale = 1.f/(1 << DIST_SHIFT);
77
78 const uchar* src = _src.ptr();
79 int* temp = _temp.ptr<int>();
80 float* dist = _dist.ptr<float>();
81 int srcstep = (int)(_src.step/sizeof(src[0]));
82 int step = (int)(_temp.step/sizeof(temp[0]));
83 int dststep = (int)(_dist.step/sizeof(dist[0]));
84 Size size = _src.size();
85
86 initTopBottom( _temp, BORDER );
87
88 // forward pass
89 for( i = 0; i < size.height; i++ )
90 {
91 const uchar* s = src + i*srcstep;
92 int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER;
93
94 for( j = 0; j < BORDER; j++ )
95 tmp[-j-1] = tmp[size.width + j] = INIT_DIST0;
96
97 for( j = 0; j < size.width; j++ )
98 {
99 if( !s[j] )
100 tmp[j] = 0;
101 else
102 {
103 int t0 = tmp[j-step-1] + DIAG_DIST;
104 int t = tmp[j-step] + HV_DIST;
105 if( t0 > t ) t0 = t;
106 t = tmp[j-step+1] + DIAG_DIST;
107 if( t0 > t ) t0 = t;
108 t = tmp[j-1] + HV_DIST;
109 if( t0 > t ) t0 = t;
110 tmp[j] = t0;
111 }
112 }
113 }
114
115 // backward pass
116 for( i = size.height - 1; i >= 0; i-- )
117 {
118 float* d = (float*)(dist + i*dststep);
119 int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER;
120
121 for( j = size.width - 1; j >= 0; j-- )
122 {
123 int t0 = tmp[j];
124 if( t0 > HV_DIST )
125 {
126 int t = tmp[j+step+1] + DIAG_DIST;
127 if( t0 > t ) t0 = t;
128 t = tmp[j+step] + HV_DIST;
129 if( t0 > t ) t0 = t;
130 t = tmp[j+step-1] + DIAG_DIST;
131 if( t0 > t ) t0 = t;
132 t = tmp[j+1] + HV_DIST;
133 if( t0 > t ) t0 = t;
134 tmp[j] = t0;
135 }
136 d[j] = (float)(t0 * scale);
137 }
138 }
139 }
140
141
142 static void
distanceTransform_5x5(const Mat & _src,Mat & _temp,Mat & _dist,const float * metrics)143 distanceTransform_5x5( const Mat& _src, Mat& _temp, Mat& _dist, const float* metrics )
144 {
145 const int BORDER = 2;
146 int i, j;
147 const int HV_DIST = CV_FLT_TO_FIX( metrics[0], DIST_SHIFT );
148 const int DIAG_DIST = CV_FLT_TO_FIX( metrics[1], DIST_SHIFT );
149 const int LONG_DIST = CV_FLT_TO_FIX( metrics[2], DIST_SHIFT );
150 const float scale = 1.f/(1 << DIST_SHIFT);
151
152 const uchar* src = _src.ptr();
153 int* temp = _temp.ptr<int>();
154 float* dist = _dist.ptr<float>();
155 int srcstep = (int)(_src.step/sizeof(src[0]));
156 int step = (int)(_temp.step/sizeof(temp[0]));
157 int dststep = (int)(_dist.step/sizeof(dist[0]));
158 Size size = _src.size();
159
160 initTopBottom( _temp, BORDER );
161
162 // forward pass
163 for( i = 0; i < size.height; i++ )
164 {
165 const uchar* s = src + i*srcstep;
166 int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER;
167
168 for( j = 0; j < BORDER; j++ )
169 tmp[-j-1] = tmp[size.width + j] = INIT_DIST0;
170
171 for( j = 0; j < size.width; j++ )
172 {
173 if( !s[j] )
174 tmp[j] = 0;
175 else
176 {
177 int t0 = tmp[j-step*2-1] + LONG_DIST;
178 int t = tmp[j-step*2+1] + LONG_DIST;
179 if( t0 > t ) t0 = t;
180 t = tmp[j-step-2] + LONG_DIST;
181 if( t0 > t ) t0 = t;
182 t = tmp[j-step-1] + DIAG_DIST;
183 if( t0 > t ) t0 = t;
184 t = tmp[j-step] + HV_DIST;
185 if( t0 > t ) t0 = t;
186 t = tmp[j-step+1] + DIAG_DIST;
187 if( t0 > t ) t0 = t;
188 t = tmp[j-step+2] + LONG_DIST;
189 if( t0 > t ) t0 = t;
190 t = tmp[j-1] + HV_DIST;
191 if( t0 > t ) t0 = t;
192 tmp[j] = t0;
193 }
194 }
195 }
196
197 // backward pass
198 for( i = size.height - 1; i >= 0; i-- )
199 {
200 float* d = (float*)(dist + i*dststep);
201 int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER;
202
203 for( j = size.width - 1; j >= 0; j-- )
204 {
205 int t0 = tmp[j];
206 if( t0 > HV_DIST )
207 {
208 int t = tmp[j+step*2+1] + LONG_DIST;
209 if( t0 > t ) t0 = t;
210 t = tmp[j+step*2-1] + LONG_DIST;
211 if( t0 > t ) t0 = t;
212 t = tmp[j+step+2] + LONG_DIST;
213 if( t0 > t ) t0 = t;
214 t = tmp[j+step+1] + DIAG_DIST;
215 if( t0 > t ) t0 = t;
216 t = tmp[j+step] + HV_DIST;
217 if( t0 > t ) t0 = t;
218 t = tmp[j+step-1] + DIAG_DIST;
219 if( t0 > t ) t0 = t;
220 t = tmp[j+step-2] + LONG_DIST;
221 if( t0 > t ) t0 = t;
222 t = tmp[j+1] + HV_DIST;
223 if( t0 > t ) t0 = t;
224 tmp[j] = t0;
225 }
226 d[j] = (float)(t0 * scale);
227 }
228 }
229 }
230
231
232 static void
distanceTransformEx_5x5(const Mat & _src,Mat & _temp,Mat & _dist,Mat & _labels,const float * metrics)233 distanceTransformEx_5x5( const Mat& _src, Mat& _temp, Mat& _dist, Mat& _labels, const float* metrics )
234 {
235 const int BORDER = 2;
236
237 int i, j;
238 const int HV_DIST = CV_FLT_TO_FIX( metrics[0], DIST_SHIFT );
239 const int DIAG_DIST = CV_FLT_TO_FIX( metrics[1], DIST_SHIFT );
240 const int LONG_DIST = CV_FLT_TO_FIX( metrics[2], DIST_SHIFT );
241 const float scale = 1.f/(1 << DIST_SHIFT);
242
243 const uchar* src = _src.ptr();
244 int* temp = _temp.ptr<int>();
245 float* dist = _dist.ptr<float>();
246 int* labels = _labels.ptr<int>();
247 int srcstep = (int)(_src.step/sizeof(src[0]));
248 int step = (int)(_temp.step/sizeof(temp[0]));
249 int dststep = (int)(_dist.step/sizeof(dist[0]));
250 int lstep = (int)(_labels.step/sizeof(dist[0]));
251 Size size = _src.size();
252
253 initTopBottom( _temp, BORDER );
254
255 // forward pass
256 for( i = 0; i < size.height; i++ )
257 {
258 const uchar* s = src + i*srcstep;
259 int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER;
260 int* lls = (int*)(labels + i*lstep);
261
262 for( j = 0; j < BORDER; j++ )
263 tmp[-j-1] = tmp[size.width + j] = INIT_DIST0;
264
265 for( j = 0; j < size.width; j++ )
266 {
267 if( !s[j] )
268 {
269 tmp[j] = 0;
270 //assert( lls[j] != 0 );
271 }
272 else
273 {
274 int t0 = INIT_DIST0, t;
275 int l0 = 0;
276
277 t = tmp[j-step*2-1] + LONG_DIST;
278 if( t0 > t )
279 {
280 t0 = t;
281 l0 = lls[j-lstep*2-1];
282 }
283 t = tmp[j-step*2+1] + LONG_DIST;
284 if( t0 > t )
285 {
286 t0 = t;
287 l0 = lls[j-lstep*2+1];
288 }
289 t = tmp[j-step-2] + LONG_DIST;
290 if( t0 > t )
291 {
292 t0 = t;
293 l0 = lls[j-lstep-2];
294 }
295 t = tmp[j-step-1] + DIAG_DIST;
296 if( t0 > t )
297 {
298 t0 = t;
299 l0 = lls[j-lstep-1];
300 }
301 t = tmp[j-step] + HV_DIST;
302 if( t0 > t )
303 {
304 t0 = t;
305 l0 = lls[j-lstep];
306 }
307 t = tmp[j-step+1] + DIAG_DIST;
308 if( t0 > t )
309 {
310 t0 = t;
311 l0 = lls[j-lstep+1];
312 }
313 t = tmp[j-step+2] + LONG_DIST;
314 if( t0 > t )
315 {
316 t0 = t;
317 l0 = lls[j-lstep+2];
318 }
319 t = tmp[j-1] + HV_DIST;
320 if( t0 > t )
321 {
322 t0 = t;
323 l0 = lls[j-1];
324 }
325
326 tmp[j] = t0;
327 lls[j] = l0;
328 }
329 }
330 }
331
332 // backward pass
333 for( i = size.height - 1; i >= 0; i-- )
334 {
335 float* d = (float*)(dist + i*dststep);
336 int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER;
337 int* lls = (int*)(labels + i*lstep);
338
339 for( j = size.width - 1; j >= 0; j-- )
340 {
341 int t0 = tmp[j];
342 int l0 = lls[j];
343 if( t0 > HV_DIST )
344 {
345 int t = tmp[j+step*2+1] + LONG_DIST;
346 if( t0 > t )
347 {
348 t0 = t;
349 l0 = lls[j+lstep*2+1];
350 }
351 t = tmp[j+step*2-1] + LONG_DIST;
352 if( t0 > t )
353 {
354 t0 = t;
355 l0 = lls[j+lstep*2-1];
356 }
357 t = tmp[j+step+2] + LONG_DIST;
358 if( t0 > t )
359 {
360 t0 = t;
361 l0 = lls[j+lstep+2];
362 }
363 t = tmp[j+step+1] + DIAG_DIST;
364 if( t0 > t )
365 {
366 t0 = t;
367 l0 = lls[j+lstep+1];
368 }
369 t = tmp[j+step] + HV_DIST;
370 if( t0 > t )
371 {
372 t0 = t;
373 l0 = lls[j+lstep];
374 }
375 t = tmp[j+step-1] + DIAG_DIST;
376 if( t0 > t )
377 {
378 t0 = t;
379 l0 = lls[j+lstep-1];
380 }
381 t = tmp[j+step-2] + LONG_DIST;
382 if( t0 > t )
383 {
384 t0 = t;
385 l0 = lls[j+lstep-2];
386 }
387 t = tmp[j+1] + HV_DIST;
388 if( t0 > t )
389 {
390 t0 = t;
391 l0 = lls[j+1];
392 }
393 tmp[j] = t0;
394 lls[j] = l0;
395 }
396 d[j] = (float)(t0 * scale);
397 }
398 }
399 }
400
401
getDistanceTransformMask(int maskType,float * metrics)402 static void getDistanceTransformMask( int maskType, float *metrics )
403 {
404 CV_Assert( metrics != 0 );
405
406 switch (maskType)
407 {
408 case 30:
409 metrics[0] = 1.0f;
410 metrics[1] = 1.0f;
411 break;
412
413 case 31:
414 metrics[0] = 1.0f;
415 metrics[1] = 2.0f;
416 break;
417
418 case 32:
419 metrics[0] = 0.955f;
420 metrics[1] = 1.3693f;
421 break;
422
423 case 50:
424 metrics[0] = 1.0f;
425 metrics[1] = 1.0f;
426 metrics[2] = 2.0f;
427 break;
428
429 case 51:
430 metrics[0] = 1.0f;
431 metrics[1] = 2.0f;
432 metrics[2] = 3.0f;
433 break;
434
435 case 52:
436 metrics[0] = 1.0f;
437 metrics[1] = 1.4f;
438 metrics[2] = 2.1969f;
439 break;
440 default:
441 CV_Error(CV_StsBadArg, "Uknown metric type");
442 }
443 }
444
445 struct DTColumnInvoker : ParallelLoopBody
446 {
DTColumnInvokercv::DTColumnInvoker447 DTColumnInvoker( const Mat* _src, Mat* _dst, const int* _sat_tab, const float* _sqr_tab)
448 {
449 src = _src;
450 dst = _dst;
451 sat_tab = _sat_tab + src->rows*2 + 1;
452 sqr_tab = _sqr_tab;
453 }
454
operator ()cv::DTColumnInvoker455 void operator()( const Range& range ) const
456 {
457 int i, i1 = range.start, i2 = range.end;
458 int m = src->rows;
459 size_t sstep = src->step, dstep = dst->step/sizeof(float);
460 AutoBuffer<int> _d(m);
461 int* d = _d;
462
463 for( i = i1; i < i2; i++ )
464 {
465 const uchar* sptr = src->ptr(m-1) + i;
466 float* dptr = dst->ptr<float>() + i;
467 int j, dist = m-1;
468
469 for( j = m-1; j >= 0; j--, sptr -= sstep )
470 {
471 dist = (dist + 1) & (sptr[0] == 0 ? 0 : -1);
472 d[j] = dist;
473 }
474
475 dist = m-1;
476 for( j = 0; j < m; j++, dptr += dstep )
477 {
478 dist = dist + 1 - sat_tab[dist - d[j]];
479 d[j] = dist;
480 dptr[0] = sqr_tab[dist];
481 }
482 }
483 }
484
485 const Mat* src;
486 Mat* dst;
487 const int* sat_tab;
488 const float* sqr_tab;
489 };
490
491 struct DTRowInvoker : ParallelLoopBody
492 {
DTRowInvokercv::DTRowInvoker493 DTRowInvoker( Mat* _dst, const float* _sqr_tab, const float* _inv_tab )
494 {
495 dst = _dst;
496 sqr_tab = _sqr_tab;
497 inv_tab = _inv_tab;
498 }
499
operator ()cv::DTRowInvoker500 void operator()( const Range& range ) const
501 {
502 const float inf = 1e15f;
503 int i, i1 = range.start, i2 = range.end;
504 int n = dst->cols;
505 AutoBuffer<uchar> _buf((n+2)*2*sizeof(float) + (n+2)*sizeof(int));
506 float* f = (float*)(uchar*)_buf;
507 float* z = f + n;
508 int* v = alignPtr((int*)(z + n + 1), sizeof(int));
509
510 for( i = i1; i < i2; i++ )
511 {
512 float* d = dst->ptr<float>(i);
513 int p, q, k;
514
515 v[0] = 0;
516 z[0] = -inf;
517 z[1] = inf;
518 f[0] = d[0];
519
520 for( q = 1, k = 0; q < n; q++ )
521 {
522 float fq = d[q];
523 f[q] = fq;
524
525 for(;;k--)
526 {
527 p = v[k];
528 float s = (fq + sqr_tab[q] - d[p] - sqr_tab[p])*inv_tab[q - p];
529 if( s > z[k] )
530 {
531 k++;
532 v[k] = q;
533 z[k] = s;
534 z[k+1] = inf;
535 break;
536 }
537 }
538 }
539
540 for( q = 0, k = 0; q < n; q++ )
541 {
542 while( z[k+1] < q )
543 k++;
544 p = v[k];
545 d[q] = std::sqrt(sqr_tab[std::abs(q - p)] + f[p]);
546 }
547 }
548 }
549
550 Mat* dst;
551 const float* sqr_tab;
552 const float* inv_tab;
553 };
554
555 static void
trueDistTrans(const Mat & src,Mat & dst)556 trueDistTrans( const Mat& src, Mat& dst )
557 {
558 const float inf = 1e15f;
559
560 CV_Assert( src.size() == dst.size() );
561
562 CV_Assert( src.type() == CV_8UC1 && dst.type() == CV_32FC1 );
563 int i, m = src.rows, n = src.cols;
564
565 cv::AutoBuffer<uchar> _buf(std::max(m*2*sizeof(float) + (m*3+1)*sizeof(int), n*2*sizeof(float)));
566 // stage 1: compute 1d distance transform of each column
567 float* sqr_tab = (float*)(uchar*)_buf;
568 int* sat_tab = cv::alignPtr((int*)(sqr_tab + m*2), sizeof(int));
569 int shift = m*2;
570
571 for( i = 0; i < m; i++ )
572 sqr_tab[i] = (float)(i*i);
573 for( i = m; i < m*2; i++ )
574 sqr_tab[i] = inf;
575 for( i = 0; i < shift; i++ )
576 sat_tab[i] = 0;
577 for( ; i <= m*3; i++ )
578 sat_tab[i] = i - shift;
579
580 cv::parallel_for_(cv::Range(0, n), cv::DTColumnInvoker(&src, &dst, sat_tab, sqr_tab), src.total()/(double)(1<<16));
581
582 // stage 2: compute modified distance transform for each row
583 float* inv_tab = sqr_tab + n;
584
585 inv_tab[0] = sqr_tab[0] = 0.f;
586 for( i = 1; i < n; i++ )
587 {
588 inv_tab[i] = (float)(0.5/i);
589 sqr_tab[i] = (float)(i*i);
590 }
591
592 cv::parallel_for_(cv::Range(0, m), cv::DTRowInvoker(&dst, sqr_tab, inv_tab));
593 }
594
595
596 /****************************************************************************************\
597 Non-inplace and Inplace 8u->8u Distance Transform for CityBlock (a.k.a. L1) metric
598 (C) 2006 by Jay Stavinzky.
599 \****************************************************************************************/
600
601 //BEGIN ATS ADDITION
602 // 8-bit grayscale distance transform function
603 static void
distanceATS_L1_8u(const Mat & src,Mat & dst)604 distanceATS_L1_8u( const Mat& src, Mat& dst )
605 {
606 int width = src.cols, height = src.rows;
607
608 int a;
609 uchar lut[256];
610 int x, y;
611
612 const uchar *sbase = src.ptr();
613 uchar *dbase = dst.ptr();
614 int srcstep = (int)src.step;
615 int dststep = (int)dst.step;
616
617 CV_Assert( src.type() == CV_8UC1 && dst.type() == CV_8UC1 );
618 CV_Assert( src.size() == dst.size() );
619
620 ////////////////////// forward scan ////////////////////////
621 for( x = 0; x < 256; x++ )
622 lut[x] = cv::saturate_cast<uchar>(x+1);
623
624 //init first pixel to max (we're going to be skipping it)
625 dbase[0] = (uchar)(sbase[0] == 0 ? 0 : 255);
626
627 //first row (scan west only, skip first pixel)
628 for( x = 1; x < width; x++ )
629 dbase[x] = (uchar)(sbase[x] == 0 ? 0 : lut[dbase[x-1]]);
630
631 for( y = 1; y < height; y++ )
632 {
633 sbase += srcstep;
634 dbase += dststep;
635
636 //for left edge, scan north only
637 a = sbase[0] == 0 ? 0 : lut[dbase[-dststep]];
638 dbase[0] = (uchar)a;
639
640 for( x = 1; x < width; x++ )
641 {
642 a = sbase[x] == 0 ? 0 : lut[MIN(a, dbase[x - dststep])];
643 dbase[x] = (uchar)a;
644 }
645 }
646
647 ////////////////////// backward scan ///////////////////////
648
649 a = dbase[width-1];
650
651 // do last row east pixel scan here (skip bottom right pixel)
652 for( x = width - 2; x >= 0; x-- )
653 {
654 a = lut[a];
655 dbase[x] = (uchar)(CV_CALC_MIN_8U(a, dbase[x]));
656 }
657
658 // right edge is the only error case
659 for( y = height - 2; y >= 0; y-- )
660 {
661 dbase -= dststep;
662
663 // do right edge
664 a = lut[dbase[width-1+dststep]];
665 dbase[width-1] = (uchar)(MIN(a, dbase[width-1]));
666
667 for( x = width - 2; x >= 0; x-- )
668 {
669 int b = dbase[x+dststep];
670 a = lut[MIN(a, b)];
671 a = MIN(a, dbase[x]);
672 dbase[x] = (uchar)(a);
673 }
674 }
675 }
676 //END ATS ADDITION
677
678 }
679
680 namespace cv
681 {
distanceTransform_L1_8U(InputArray _src,OutputArray _dst)682 static void distanceTransform_L1_8U(InputArray _src, OutputArray _dst)
683 {
684 Mat src = _src.getMat();
685
686 CV_Assert( src.type() == CV_8UC1);
687
688 _dst.create( src.size(), CV_8UC1);
689 Mat dst = _dst.getMat();
690
691 #ifdef HAVE_IPP
692 CV_IPP_CHECK()
693 {
694 IppiSize roi = { src.cols, src.rows };
695 Ipp32s pMetrics[2] = { 1, 2 }; //L1, 3x3 mask
696 if (ippiDistanceTransform_3x3_8u_C1R(src.ptr<uchar>(), (int)src.step, dst.ptr<uchar>(), (int)dst.step, roi, pMetrics)>=0)
697 {
698 CV_IMPL_ADD(CV_IMPL_IPP);
699 return;
700 }
701 setIppErrorStatus();
702 }
703 #endif
704
705 distanceATS_L1_8u(src, dst);
706 }
707 }
708
709 // Wrapper function for distance transform group
distanceTransform(InputArray _src,OutputArray _dst,OutputArray _labels,int distType,int maskSize,int labelType)710 void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labels,
711 int distType, int maskSize, int labelType )
712 {
713 Mat src = _src.getMat(), labels;
714 bool need_labels = _labels.needed();
715
716 CV_Assert( src.type() == CV_8UC1);
717
718 _dst.create( src.size(), CV_32F);
719 Mat dst = _dst.getMat();
720
721 if( need_labels )
722 {
723 CV_Assert( labelType == DIST_LABEL_PIXEL || labelType == DIST_LABEL_CCOMP );
724
725 _labels.create(src.size(), CV_32S);
726 labels = _labels.getMat();
727 maskSize = CV_DIST_MASK_5;
728 }
729
730 float _mask[5] = {0};
731
732 if( maskSize != CV_DIST_MASK_3 && maskSize != CV_DIST_MASK_5 && maskSize != CV_DIST_MASK_PRECISE )
733 CV_Error( CV_StsBadSize, "Mask size should be 3 or 5 or 0 (presize)" );
734
735 if( distType == CV_DIST_C || distType == CV_DIST_L1 )
736 maskSize = !need_labels ? CV_DIST_MASK_3 : CV_DIST_MASK_5;
737 else if( distType == CV_DIST_L2 && need_labels )
738 maskSize = CV_DIST_MASK_5;
739
740 if( maskSize == CV_DIST_MASK_PRECISE )
741 {
742
743 #ifdef HAVE_IPP
744 CV_IPP_CHECK()
745 {
746 if ((currentParallelFramework()==NULL) || (src.total()<(int)(1<<14)))
747 {
748 IppStatus status;
749 IppiSize roi = { src.cols, src.rows };
750 Ipp8u *pBuffer;
751 int bufSize=0;
752
753 status = ippiTrueDistanceTransformGetBufferSize_8u32f_C1R(roi, &bufSize);
754 if (status>=0)
755 {
756 pBuffer = (Ipp8u *)ippMalloc( bufSize );
757 status = ippiTrueDistanceTransform_8u32f_C1R(src.ptr<uchar>(),(int)src.step, dst.ptr<float>(), (int)dst.step, roi, pBuffer);
758 ippFree( pBuffer );
759 if (status>=0)
760 {
761 CV_IMPL_ADD(CV_IMPL_IPP);
762 return;
763 }
764 setIppErrorStatus();
765 }
766 }
767 }
768 #endif
769
770 trueDistTrans( src, dst );
771 return;
772 }
773
774 CV_Assert( distType == CV_DIST_C || distType == CV_DIST_L1 || distType == CV_DIST_L2 );
775
776 getDistanceTransformMask( (distType == CV_DIST_C ? 0 :
777 distType == CV_DIST_L1 ? 1 : 2) + maskSize*10, _mask );
778
779 Size size = src.size();
780
781 int border = maskSize == CV_DIST_MASK_3 ? 1 : 2;
782 Mat temp( size.height + border*2, size.width + border*2, CV_32SC1 );
783
784 if( !need_labels )
785 {
786 if( maskSize == CV_DIST_MASK_3 )
787 {
788 #if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7)
789 CV_IPP_CHECK()
790 {
791 IppiSize roi = { src.cols, src.rows };
792 if (ippiDistanceTransform_3x3_8u32f_C1R(src.ptr<uchar>(), (int)src.step, dst.ptr<float>(), (int)dst.step, roi, _mask)>=0)
793 {
794 CV_IMPL_ADD(CV_IMPL_IPP);
795 return;
796 }
797 setIppErrorStatus();
798 }
799 #endif
800
801 distanceTransform_3x3(src, temp, dst, _mask);
802 }
803 else
804 {
805 #if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7)
806 CV_IPP_CHECK()
807 {
808 IppiSize roi = { src.cols, src.rows };
809 if (ippiDistanceTransform_5x5_8u32f_C1R(src.ptr<uchar>(), (int)src.step, dst.ptr<float>(), (int)dst.step, roi, _mask)>=0)
810 {
811 CV_IMPL_ADD(CV_IMPL_IPP);
812 return;
813 }
814 setIppErrorStatus();
815 }
816 #endif
817
818 distanceTransform_5x5(src, temp, dst, _mask);
819 }
820 }
821 else
822 {
823 labels.setTo(Scalar::all(0));
824
825 if( labelType == CV_DIST_LABEL_CCOMP )
826 {
827 Mat zpix = src == 0;
828 connectedComponents(zpix, labels, 8, CV_32S);
829 }
830 else
831 {
832 int k = 1;
833 for( int i = 0; i < src.rows; i++ )
834 {
835 const uchar* srcptr = src.ptr(i);
836 int* labelptr = labels.ptr<int>(i);
837
838 for( int j = 0; j < src.cols; j++ )
839 if( srcptr[j] == 0 )
840 labelptr[j] = k++;
841 }
842 }
843
844 distanceTransformEx_5x5( src, temp, dst, labels, _mask );
845 }
846 }
847
distanceTransform(InputArray _src,OutputArray _dst,int distanceType,int maskSize,int dstType)848 void cv::distanceTransform( InputArray _src, OutputArray _dst,
849 int distanceType, int maskSize, int dstType)
850 {
851 if (distanceType == CV_DIST_L1 && dstType==CV_8U)
852 distanceTransform_L1_8U(_src, _dst);
853 else
854 distanceTransform(_src, _dst, noArray(), distanceType, maskSize, DIST_LABEL_PIXEL);
855
856 }
857
858 CV_IMPL void
cvDistTransform(const void * srcarr,void * dstarr,int distType,int maskSize,const float *,void * labelsarr,int labelType)859 cvDistTransform( const void* srcarr, void* dstarr,
860 int distType, int maskSize,
861 const float * /*mask*/,
862 void* labelsarr, int labelType )
863 {
864 cv::Mat src = cv::cvarrToMat(srcarr);
865 const cv::Mat dst = cv::cvarrToMat(dstarr);
866 const cv::Mat labels = cv::cvarrToMat(labelsarr);
867
868 cv::distanceTransform(src, dst, labelsarr ? cv::_OutputArray(labels) : cv::_OutputArray(),
869 distType, maskSize, labelType);
870
871 }
872
873
874 /* End of file. */
875