Merge pull request #7443 from Tytan:akaze
[platform/upstream/opencv.git] / modules / imgproc / src / thresh.cpp
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-2008, Intel Corporation, all rights reserved.
14 // Copyright (C) 2009, Willow Garage Inc., 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
43 #include "precomp.hpp"
44 #include "opencl_kernels_imgproc.hpp"
45 #include "opencv2/core/hal/intrin.hpp"
46
47 namespace cv
48 {
49
50 static void
51 thresh_8u( const Mat& _src, Mat& _dst, uchar thresh, uchar maxval, int type )
52 {
53     Size roi = _src.size();
54     roi.width *= _src.channels();
55     size_t src_step = _src.step;
56     size_t dst_step = _dst.step;
57
58     if( _src.isContinuous() && _dst.isContinuous() )
59     {
60         roi.width *= roi.height;
61         roi.height = 1;
62         src_step = dst_step = roi.width;
63     }
64
65 #ifdef HAVE_TEGRA_OPTIMIZATION
66     if (tegra::useTegra() && tegra::thresh_8u(_src, _dst, roi.width, roi.height, thresh, maxval, type))
67         return;
68 #endif
69
70 #if defined(HAVE_IPP)
71     CV_IPP_CHECK()
72     {
73         IppiSize sz = { roi.width, roi.height };
74         CV_SUPPRESS_DEPRECATED_START
75         switch( type )
76         {
77         case THRESH_TRUNC:
78             if (_src.data == _dst.data && CV_INSTRUMENT_FUN_IPP(ippiThreshold_GT_8u_C1IR, _dst.ptr(), (int)dst_step, sz, thresh) >= 0)
79             {
80                 CV_IMPL_ADD(CV_IMPL_IPP);
81                 return;
82             }
83             if (CV_INSTRUMENT_FUN_IPP(ippiThreshold_GT_8u_C1R, _src.ptr(), (int)src_step, _dst.ptr(), (int)dst_step, sz, thresh) >= 0)
84             {
85                 CV_IMPL_ADD(CV_IMPL_IPP);
86                 return;
87             }
88             setIppErrorStatus();
89             break;
90         case THRESH_TOZERO:
91             if (_src.data == _dst.data && CV_INSTRUMENT_FUN_IPP(ippiThreshold_LTVal_8u_C1IR, _dst.ptr(), (int)dst_step, sz, thresh+1, 0) >= 0)
92             {
93                 CV_IMPL_ADD(CV_IMPL_IPP);
94                 return;
95             }
96             if (CV_INSTRUMENT_FUN_IPP(ippiThreshold_LTVal_8u_C1R, _src.ptr(), (int)src_step, _dst.ptr(), (int)dst_step, sz, thresh + 1, 0) >= 0)
97             {
98                 CV_IMPL_ADD(CV_IMPL_IPP);
99                 return;
100             }
101             setIppErrorStatus();
102             break;
103         case THRESH_TOZERO_INV:
104             if (_src.data == _dst.data && CV_INSTRUMENT_FUN_IPP(ippiThreshold_GTVal_8u_C1IR, _dst.ptr(), (int)dst_step, sz, thresh, 0) >= 0)
105             {
106                 CV_IMPL_ADD(CV_IMPL_IPP);
107                 return;
108             }
109             if (CV_INSTRUMENT_FUN_IPP(ippiThreshold_GTVal_8u_C1R, _src.ptr(), (int)src_step, _dst.ptr(), (int)dst_step, sz, thresh, 0) >= 0)
110             {
111                 CV_IMPL_ADD(CV_IMPL_IPP);
112                 return;
113             }
114             setIppErrorStatus();
115             break;
116         }
117         CV_SUPPRESS_DEPRECATED_END
118     }
119 #endif
120
121     int j = 0;
122     const uchar* src = _src.ptr();
123     uchar* dst = _dst.ptr();
124 #if CV_SIMD128
125     bool useSIMD = checkHardwareSupport( CV_CPU_SSE2 ) || checkHardwareSupport( CV_CPU_NEON );
126     if( useSIMD )
127     {
128         v_uint8x16 thresh_u = v_setall_u8( thresh );
129         v_uint8x16 maxval16 = v_setall_u8( maxval );
130
131         switch( type )
132         {
133         case THRESH_BINARY:
134             for( int i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
135             {
136                 for( j = 0; j <= roi.width - 16; j += 16 )
137                 {
138                     v_uint8x16 v0;
139                     v0 = v_load( src + j );
140                     v0 = thresh_u < v0;
141                     v0 = v0 & maxval16;
142                     v_store( dst + j, v0 );
143                 }
144             }
145             break;
146
147         case THRESH_BINARY_INV:
148             for( int i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
149             {
150                 for( j = 0; j <= roi.width - 16; j += 16 )
151                 {
152                     v_uint8x16 v0;
153                     v0 = v_load( src + j );
154                     v0 = v0 <= thresh_u;
155                     v0 = v0 & maxval16;
156                     v_store( dst + j, v0 );
157                 }
158             }
159             break;
160
161         case THRESH_TRUNC:
162             for( int i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
163             {
164                 for( j = 0; j <= roi.width - 16; j += 16 )
165                 {
166                     v_uint8x16 v0;
167                     v0 = v_load( src + j );
168                     v0 = v0 - ( v0 - thresh_u );
169                     v_store( dst + j, v0 );
170                 }
171             }
172             break;
173
174         case THRESH_TOZERO:
175             for( int i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
176             {
177                 for( j = 0; j <= roi.width - 16; j += 16 )
178                 {
179                     v_uint8x16 v0;
180                     v0 = v_load( src + j );
181                     v0 = ( thresh_u < v0 ) & v0;
182                     v_store( dst + j, v0 );
183                 }
184             }
185             break;
186
187         case THRESH_TOZERO_INV:
188             for( int i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
189             {
190                 for( j = 0; j <= roi.width - 16; j += 16 )
191                 {
192                     v_uint8x16 v0;
193                     v0 = v_load( src + j );
194                     v0 = ( v0 <= thresh_u ) & v0;
195                     v_store( dst + j, v0 );
196                 }
197             }
198             break;
199         }
200     }
201 #endif
202
203     int j_scalar = j;
204     if( j_scalar < roi.width )
205     {
206         const int thresh_pivot = thresh + 1;
207         uchar tab[256];
208         switch( type )
209         {
210         case THRESH_BINARY:
211             memset(tab, 0, thresh_pivot);
212             if (thresh_pivot < 256) {
213                 memset(tab + thresh_pivot, maxval, 256 - thresh_pivot);
214             }
215             break;
216         case THRESH_BINARY_INV:
217             memset(tab, maxval, thresh_pivot);
218             if (thresh_pivot < 256) {
219                 memset(tab + thresh_pivot, 0, 256 - thresh_pivot);
220             }
221             break;
222         case THRESH_TRUNC:
223             for( int i = 0; i <= thresh; i++ )
224                 tab[i] = (uchar)i;
225             if (thresh_pivot < 256) {
226                 memset(tab + thresh_pivot, thresh, 256 - thresh_pivot);
227             }
228             break;
229         case THRESH_TOZERO:
230             memset(tab, 0, thresh_pivot);
231             for( int i = thresh_pivot; i < 256; i++ )
232                 tab[i] = (uchar)i;
233             break;
234         case THRESH_TOZERO_INV:
235             for( int i = 0; i <= thresh; i++ )
236                 tab[i] = (uchar)i;
237             if (thresh_pivot < 256) {
238                 memset(tab + thresh_pivot, 0, 256 - thresh_pivot);
239             }
240             break;
241         }
242
243         src = _src.ptr();
244         dst = _dst.ptr();
245         for( int i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
246         {
247             j = j_scalar;
248 #if CV_ENABLE_UNROLLED
249             for( ; j <= roi.width - 4; j += 4 )
250             {
251                 uchar t0 = tab[src[j]];
252                 uchar t1 = tab[src[j+1]];
253
254                 dst[j] = t0;
255                 dst[j+1] = t1;
256
257                 t0 = tab[src[j+2]];
258                 t1 = tab[src[j+3]];
259
260                 dst[j+2] = t0;
261                 dst[j+3] = t1;
262             }
263 #endif
264             for( ; j < roi.width; j++ )
265                 dst[j] = tab[src[j]];
266         }
267     }
268 }
269
270
271 static void
272 thresh_16s( const Mat& _src, Mat& _dst, short thresh, short maxval, int type )
273 {
274     int i, j;
275     Size roi = _src.size();
276     roi.width *= _src.channels();
277     const short* src = _src.ptr<short>();
278     short* dst = _dst.ptr<short>();
279     size_t src_step = _src.step/sizeof(src[0]);
280     size_t dst_step = _dst.step/sizeof(dst[0]);
281
282     if( _src.isContinuous() && _dst.isContinuous() )
283     {
284         roi.width *= roi.height;
285         roi.height = 1;
286         src_step = dst_step = roi.width;
287     }
288
289 #ifdef HAVE_TEGRA_OPTIMIZATION
290     if (tegra::useTegra() && tegra::thresh_16s(_src, _dst, roi.width, roi.height, thresh, maxval, type))
291         return;
292 #endif
293
294 #if defined(HAVE_IPP)
295     CV_IPP_CHECK()
296     {
297         IppiSize sz = { roi.width, roi.height };
298         CV_SUPPRESS_DEPRECATED_START
299         switch( type )
300         {
301         case THRESH_TRUNC:
302             if (_src.data == _dst.data && CV_INSTRUMENT_FUN_IPP(ippiThreshold_GT_16s_C1IR, dst, (int)dst_step*sizeof(dst[0]), sz, thresh) >= 0)
303             {
304                 CV_IMPL_ADD(CV_IMPL_IPP);
305                 return;
306             }
307             if (CV_INSTRUMENT_FUN_IPP(ippiThreshold_GT_16s_C1R, src, (int)src_step*sizeof(src[0]), dst, (int)dst_step*sizeof(dst[0]), sz, thresh) >= 0)
308             {
309                 CV_IMPL_ADD(CV_IMPL_IPP);
310                 return;
311             }
312             setIppErrorStatus();
313             break;
314         case THRESH_TOZERO:
315             if (_src.data == _dst.data && CV_INSTRUMENT_FUN_IPP(ippiThreshold_LTVal_16s_C1IR, dst, (int)dst_step*sizeof(dst[0]), sz, thresh + 1, 0) >= 0)
316             {
317                 CV_IMPL_ADD(CV_IMPL_IPP);
318                 return;
319             }
320             if (CV_INSTRUMENT_FUN_IPP(ippiThreshold_LTVal_16s_C1R, src, (int)src_step*sizeof(src[0]), dst, (int)dst_step*sizeof(dst[0]), sz, thresh + 1, 0) >= 0)
321             {
322                 CV_IMPL_ADD(CV_IMPL_IPP);
323                 return;
324             }
325             setIppErrorStatus();
326             break;
327         case THRESH_TOZERO_INV:
328             if (_src.data == _dst.data && CV_INSTRUMENT_FUN_IPP(ippiThreshold_GTVal_16s_C1IR, dst, (int)dst_step*sizeof(dst[0]), sz, thresh, 0) >= 0)
329             {
330                 CV_IMPL_ADD(CV_IMPL_IPP);
331                 return;
332             }
333             if (CV_INSTRUMENT_FUN_IPP(ippiThreshold_GTVal_16s_C1R, src, (int)src_step*sizeof(src[0]), dst, (int)dst_step*sizeof(dst[0]), sz, thresh, 0) >= 0)
334             {
335                 CV_IMPL_ADD(CV_IMPL_IPP);
336                 return;
337             }
338             setIppErrorStatus();
339             break;
340         }
341         CV_SUPPRESS_DEPRECATED_END
342     }
343 #endif
344
345 #if CV_SIMD128
346     bool useSIMD = checkHardwareSupport( CV_CPU_SSE2 ) || checkHardwareSupport( CV_CPU_NEON );
347     if( useSIMD )
348     {
349         v_int16x8 thresh8 = v_setall_s16( thresh );
350         v_int16x8 maxval8 = v_setall_s16( maxval );
351
352         switch( type )
353         {
354         case THRESH_BINARY:
355             for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
356             {
357                 j = 0;
358                 for( ; j <= roi.width - 16; j += 16 )
359                 {
360                     v_int16x8 v0, v1;
361                     v0 = v_load( src + j );
362                     v1 = v_load( src + j + 8 );
363                     v0 = thresh8 < v0;
364                     v1 = thresh8 < v1;
365                     v0 = v0 & maxval8;
366                     v1 = v1 & maxval8;
367                     v_store( dst + j, v0 );
368                     v_store( dst + j + 8, v1 );
369                 }
370
371                 for( ; j < roi.width; j++ )
372                     dst[j] = src[j] > thresh ? maxval : 0;
373             }
374             break;
375
376         case THRESH_BINARY_INV:
377             for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
378             {
379                 j = 0;
380                 for( ; j <= roi.width - 16; j += 16 )
381                 {
382                     v_int16x8 v0, v1;
383                     v0 = v_load( src + j );
384                     v1 = v_load( src + j + 8 );
385                     v0 = v0 <= thresh8;
386                     v1 = v1 <= thresh8;
387                     v0 = v0 & maxval8;
388                     v1 = v1 & maxval8;
389                     v_store( dst + j, v0 );
390                     v_store( dst + j + 8, v1 );
391                 }
392
393                 for( ; j < roi.width; j++ )
394                     dst[j] = src[j] <= thresh ? maxval : 0;
395             }
396             break;
397
398         case THRESH_TRUNC:
399             for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
400             {
401                 j = 0;
402                 for( ; j <= roi.width - 16; j += 16 )
403                 {
404                     v_int16x8 v0, v1;
405                     v0 = v_load( src + j );
406                     v1 = v_load( src + j + 8 );
407                     v0 = v_min( v0, thresh8 );
408                     v1 = v_min( v1, thresh8 );
409                     v_store( dst + j, v0 );
410                     v_store( dst + j + 8, v1 );
411                 }
412
413                 for( ; j < roi.width; j++ )
414                     dst[j] = std::min( src[j], thresh );
415             }
416             break;
417
418         case THRESH_TOZERO:
419             for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
420             {
421                 j = 0;
422                 for( ; j <= roi.width - 16; j += 16 )
423                 {
424                     v_int16x8 v0, v1;
425                     v0 = v_load( src + j );
426                     v1 = v_load( src + j + 8 );
427                     v0 = ( thresh8 < v0 ) & v0;
428                     v1 = ( thresh8 < v1 ) & v1;
429                     v_store( dst + j, v0 );
430                     v_store( dst + j + 8, v1 );
431                 }
432
433                 for( ; j < roi.width; j++ )
434                 {
435                     short v = src[j];
436                     dst[j] = v > thresh ? v : 0;
437                 }
438             }
439             break;
440
441         case THRESH_TOZERO_INV:
442             for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
443             {
444                 j = 0;
445                 for( ; j <= roi.width - 16; j += 16 )
446                 {
447                     v_int16x8 v0, v1;
448                     v0 = v_load( src + j );
449                     v1 = v_load( src + j + 8 );
450                     v0 = ( v0 <= thresh8 ) & v0;
451                     v1 = ( v1 <= thresh8 ) & v1;
452                     v_store( dst + j, v0 );
453                     v_store( dst + j + 8, v1 );
454                 }
455
456                 for( ; j < roi.width; j++ )
457                 {
458                     short v = src[j];
459                     dst[j] = v <= thresh ? v : 0;
460                 }
461             }
462             break;
463         default:
464             return CV_Error( CV_StsBadArg, "" );
465         }
466     }
467     else
468 #endif
469     {
470         switch( type )
471         {
472         case THRESH_BINARY:
473             for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
474             {
475                 for( j = 0; j < roi.width; j++ )
476                     dst[j] = src[j] > thresh ? maxval : 0;
477             }
478             break;
479
480         case THRESH_BINARY_INV:
481             for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
482             {
483                 for( j = 0; j < roi.width; j++ )
484                     dst[j] = src[j] <= thresh ? maxval : 0;
485             }
486             break;
487
488         case THRESH_TRUNC:
489             for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
490             {
491                 for( j = 0; j < roi.width; j++ )
492                     dst[j] = std::min( src[j], thresh );
493             }
494             break;
495
496         case THRESH_TOZERO:
497             for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
498             {
499                 for( j = 0; j < roi.width; j++ )
500                 {
501                     short v = src[j];
502                     dst[j] = v > thresh ? v : 0;
503                 }
504             }
505             break;
506
507         case THRESH_TOZERO_INV:
508             for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
509             {
510                 for( j = 0; j < roi.width; j++ )
511                 {
512                     short v = src[j];
513                     dst[j] = v <= thresh ? v : 0;
514                 }
515             }
516             break;
517         default:
518             return CV_Error( CV_StsBadArg, "" );
519         }
520     }
521 }
522
523
524 static void
525 thresh_32f( const Mat& _src, Mat& _dst, float thresh, float maxval, int type )
526 {
527     int i, j;
528     Size roi = _src.size();
529     roi.width *= _src.channels();
530     const float* src = _src.ptr<float>();
531     float* dst = _dst.ptr<float>();
532     size_t src_step = _src.step/sizeof(src[0]);
533     size_t dst_step = _dst.step/sizeof(dst[0]);
534
535     if( _src.isContinuous() && _dst.isContinuous() )
536     {
537         roi.width *= roi.height;
538         roi.height = 1;
539     }
540
541 #ifdef HAVE_TEGRA_OPTIMIZATION
542     if (tegra::useTegra() && tegra::thresh_32f(_src, _dst, roi.width, roi.height, thresh, maxval, type))
543         return;
544 #endif
545
546 #if defined(HAVE_IPP)
547     CV_IPP_CHECK()
548     {
549         IppiSize sz = { roi.width, roi.height };
550         switch( type )
551         {
552         case THRESH_TRUNC:
553             if (0 <= CV_INSTRUMENT_FUN_IPP(ippiThreshold_GT_32f_C1R, src, (int)src_step*sizeof(src[0]), dst, (int)dst_step*sizeof(dst[0]), sz, thresh))
554             {
555                 CV_IMPL_ADD(CV_IMPL_IPP);
556                 return;
557             }
558             setIppErrorStatus();
559             break;
560         case THRESH_TOZERO:
561             if (0 <= CV_INSTRUMENT_FUN_IPP(ippiThreshold_LTVal_32f_C1R, src, (int)src_step*sizeof(src[0]), dst, (int)dst_step*sizeof(dst[0]), sz, thresh + FLT_EPSILON, 0))
562             {
563                 CV_IMPL_ADD(CV_IMPL_IPP);
564                 return;
565             }
566             setIppErrorStatus();
567             break;
568         case THRESH_TOZERO_INV:
569             if (0 <= CV_INSTRUMENT_FUN_IPP(ippiThreshold_GTVal_32f_C1R, src, (int)src_step*sizeof(src[0]), dst, (int)dst_step*sizeof(dst[0]), sz, thresh, 0))
570             {
571                 CV_IMPL_ADD(CV_IMPL_IPP);
572                 return;
573             }
574             setIppErrorStatus();
575             break;
576         }
577     }
578 #endif
579
580 #if CV_SIMD128
581     bool useSIMD = checkHardwareSupport( CV_CPU_SSE2 ) || checkHardwareSupport( CV_CPU_NEON );
582     if( useSIMD )
583     {
584         v_float32x4 thresh4 = v_setall_f32( thresh );
585         v_float32x4 maxval4 = v_setall_f32( maxval );
586
587         switch( type )
588         {
589             case THRESH_BINARY:
590                 for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
591                 {
592                     j = 0;
593                     for( ; j <= roi.width - 8; j += 8 )
594                     {
595                         v_float32x4 v0, v1;
596                         v0 = v_load( src + j );
597                         v1 = v_load( src + j + 4 );
598                         v0 = thresh4 < v0;
599                         v1 = thresh4 < v1;
600                         v0 = v0 & maxval4;
601                         v1 = v1 & maxval4;
602                         v_store( dst + j, v0 );
603                         v_store( dst + j + 4, v1 );
604                     }
605
606                     for( ; j < roi.width; j++ )
607                         dst[j] = src[j] > thresh ? maxval : 0;
608                 }
609                 break;
610
611             case THRESH_BINARY_INV:
612                 for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
613                 {
614                     j = 0;
615                     for( ; j <= roi.width - 8; j += 8 )
616                     {
617                         v_float32x4 v0, v1;
618                         v0 = v_load( src + j );
619                         v1 = v_load( src + j + 4 );
620                         v0 = v0 <= thresh4;
621                         v1 = v1 <= thresh4;
622                         v0 = v0 & maxval4;
623                         v1 = v1 & maxval4;
624                         v_store( dst + j, v0 );
625                         v_store( dst + j + 4, v1 );
626                     }
627
628                     for( ; j < roi.width; j++ )
629                         dst[j] = src[j] <= thresh ? maxval : 0;
630                 }
631                 break;
632
633             case THRESH_TRUNC:
634                 for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
635                 {
636                     j = 0;
637                     for( ; j <= roi.width - 8; j += 8 )
638                     {
639                         v_float32x4 v0, v1;
640                         v0 = v_load( src + j );
641                         v1 = v_load( src + j + 4 );
642                         v0 = v_min( v0, thresh4 );
643                         v1 = v_min( v1, thresh4 );
644                         v_store( dst + j, v0 );
645                         v_store( dst + j + 4, v1 );
646                     }
647
648                     for( ; j < roi.width; j++ )
649                         dst[j] = std::min( src[j], thresh );
650                 }
651                 break;
652
653             case THRESH_TOZERO:
654                 for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
655                 {
656                     j = 0;
657                     for( ; j <= roi.width - 8; j += 8 )
658                     {
659                         v_float32x4 v0, v1;
660                         v0 = v_load( src + j );
661                         v1 = v_load( src + j + 4 );
662                         v0 = ( thresh4 < v0 ) & v0;
663                         v1 = ( thresh4 < v1 ) & v1;
664                         v_store( dst + j, v0 );
665                         v_store( dst + j + 4, v1 );
666                     }
667
668                     for( ; j < roi.width; j++ )
669                     {
670                         float v = src[j];
671                         dst[j] = v > thresh ? v : 0;
672                     }
673                 }
674                 break;
675
676             case THRESH_TOZERO_INV:
677                 for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
678                 {
679                     j = 0;
680                     for( ; j <= roi.width - 8; j += 8 )
681                     {
682                         v_float32x4 v0, v1;
683                         v0 = v_load( src + j );
684                         v1 = v_load( src + j + 4 );
685                         v0 = ( v0 <= thresh4 ) & v0;
686                         v1 = ( v1 <= thresh4 ) & v1;
687                         v_store( dst + j, v0 );
688                         v_store( dst + j + 4, v1 );
689                     }
690
691                     for( ; j < roi.width; j++ )
692                     {
693                         float v = src[j];
694                         dst[j] = v <= thresh ? v : 0;
695                     }
696                 }
697                 break;
698             default:
699                 return CV_Error( CV_StsBadArg, "" );
700         }
701     }
702     else
703 #endif
704     {
705         switch( type )
706         {
707             case THRESH_BINARY:
708                 for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
709                 {
710                     for( j = 0; j < roi.width; j++ )
711                         dst[j] = src[j] > thresh ? maxval : 0;
712                 }
713                 break;
714
715             case THRESH_BINARY_INV:
716                 for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
717                 {
718                     for( j = 0; j < roi.width; j++ )
719                         dst[j] = src[j] <= thresh ? maxval : 0;
720                 }
721                 break;
722
723             case THRESH_TRUNC:
724                 for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
725                 {
726                     for( j = 0; j < roi.width; j++ )
727                         dst[j] = std::min( src[j], thresh );
728                 }
729                 break;
730
731             case THRESH_TOZERO:
732                 for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
733                 {
734                     for( j = 0; j < roi.width; j++ )
735                     {
736                         float v = src[j];
737                         dst[j] = v > thresh ? v : 0;
738                     }
739                 }
740                 break;
741
742             case THRESH_TOZERO_INV:
743                 for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
744                 {
745                     for( j = 0; j < roi.width; j++ )
746                     {
747                         float v = src[j];
748                         dst[j] = v <= thresh ? v : 0;
749                     }
750                 }
751                 break;
752             default:
753                 return CV_Error( CV_StsBadArg, "" );
754         }
755     }
756 }
757
758 static void
759 thresh_64f(const Mat& _src, Mat& _dst, double thresh, double maxval, int type)
760 {
761     int i, j;
762     Size roi = _src.size();
763     roi.width *= _src.channels();
764     const double* src = _src.ptr<double>();
765     double* dst = _dst.ptr<double>();
766     size_t src_step = _src.step / sizeof(src[0]);
767     size_t dst_step = _dst.step / sizeof(dst[0]);
768
769     if (_src.isContinuous() && _dst.isContinuous())
770     {
771         roi.width *= roi.height;
772         roi.height = 1;
773     }
774
775 #if CV_SIMD128_64F
776     bool useSIMD = checkHardwareSupport( CV_CPU_SSE2 ) || checkHardwareSupport( CV_CPU_NEON );
777     if( useSIMD )
778     {
779         v_float64x2 thresh2 = v_setall_f64( thresh );
780         v_float64x2 maxval2 = v_setall_f64( maxval );
781
782         switch( type )
783         {
784         case THRESH_BINARY:
785             for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
786             {
787                 j = 0;
788                 for( ; j <= roi.width - 4; j += 4 )
789                 {
790                     v_float64x2 v0, v1;
791                     v0 = v_load( src + j );
792                     v1 = v_load( src + j + 2 );
793                     v0 = thresh2 < v0;
794                     v1 = thresh2 < v1;
795                     v0 = v0 & maxval2;
796                     v1 = v1 & maxval2;
797                     v_store( dst + j, v0 );
798                     v_store( dst + j + 2, v1 );
799                 }
800
801                 for( ; j < roi.width; j++ )
802                     dst[j] = src[j] > thresh ? maxval : 0;
803             }
804             break;
805
806         case THRESH_BINARY_INV:
807             for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
808             {
809                 j = 0;
810                 for( ; j <= roi.width - 4; j += 4 )
811                 {
812                     v_float64x2 v0, v1;
813                     v0 = v_load( src + j );
814                     v1 = v_load( src + j + 2 );
815                     v0 = v0 <= thresh2;
816                     v1 = v1 <= thresh2;
817                     v0 = v0 & maxval2;
818                     v1 = v1 & maxval2;
819                     v_store( dst + j, v0 );
820                     v_store( dst + j + 2, v1 );
821                 }
822
823                 for( ; j < roi.width; j++ )
824                     dst[j] = src[j] <= thresh ? maxval : 0;
825             }
826             break;
827
828         case THRESH_TRUNC:
829             for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
830             {
831                 j = 0;
832                 for( ; j <= roi.width - 4; j += 4 )
833                 {
834                     v_float64x2 v0, v1;
835                     v0 = v_load( src + j );
836                     v1 = v_load( src + j + 2 );
837                     v0 = v_min( v0, thresh2 );
838                     v1 = v_min( v1, thresh2 );
839                     v_store( dst + j, v0 );
840                     v_store( dst + j + 2, v1 );
841                 }
842
843                 for( ; j < roi.width; j++ )
844                     dst[j] = std::min( src[j], thresh );
845             }
846             break;
847
848         case THRESH_TOZERO:
849             for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
850             {
851                 j = 0;
852                 for( ; j <= roi.width - 4; j += 4 )
853                 {
854                     v_float64x2 v0, v1;
855                     v0 = v_load( src + j );
856                     v1 = v_load( src + j + 2 );
857                     v0 = ( thresh2 < v0 ) & v0;
858                     v1 = ( thresh2 < v1 ) & v1;
859                     v_store( dst + j, v0 );
860                     v_store( dst + j + 2, v1 );
861                 }
862
863                 for( ; j < roi.width; j++ )
864                 {
865                     double v = src[j];
866                     dst[j] = v > thresh ? v : 0;
867                 }
868             }
869             break;
870
871         case THRESH_TOZERO_INV:
872             for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
873             {
874                 j = 0;
875                 for( ; j <= roi.width - 4; j += 4 )
876                 {
877                     v_float64x2 v0, v1;
878                     v0 = v_load( src + j );
879                     v1 = v_load( src + j + 2 );
880                     v0 = ( v0 <= thresh2 ) & v0;
881                     v1 = ( v1 <= thresh2 ) & v1;
882                     v_store( dst + j, v0 );
883                     v_store( dst + j + 2, v1 );
884                 }
885
886                 for( ; j < roi.width; j++ )
887                 {
888                     double v = src[j];
889                     dst[j] = v <= thresh ? v : 0;
890                 }
891             }
892             break;
893         default:
894             return CV_Error(CV_StsBadArg, "");
895         }
896     }
897     else
898 #endif
899     {
900         switch( type )
901         {
902         case THRESH_BINARY:
903             for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
904             {
905                 j = 0;
906                 for( ; j < roi.width; j++ )
907                     dst[j] = src[j] > thresh ? maxval : 0;
908             }
909             break;
910
911         case THRESH_BINARY_INV:
912             for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
913             {
914                 j = 0;
915                 for( ; j < roi.width; j++ )
916                     dst[j] = src[j] <= thresh ? maxval : 0;
917             }
918             break;
919
920         case THRESH_TRUNC:
921             for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
922             {
923                 j = 0;
924                 for( ; j < roi.width; j++ )
925                     dst[j] = std::min( src[j], thresh );
926             }
927             break;
928
929         case THRESH_TOZERO:
930             for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
931             {
932                 j = 0;
933                 for( ; j < roi.width; j++ )
934                 {
935                     double v = src[j];
936                     dst[j] = v > thresh ? v : 0;
937                 }
938             }
939             break;
940
941         case THRESH_TOZERO_INV:
942             for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
943             {
944                 j = 0;
945                 for( ; j < roi.width; j++ )
946                 {
947                     double v = src[j];
948                     dst[j] = v <= thresh ? v : 0;
949                 }
950             }
951             break;
952         default:
953             return CV_Error(CV_StsBadArg, "");
954         }
955     }
956 }
957
958 #ifdef HAVE_IPP
959 static bool ipp_getThreshVal_Otsu_8u( const unsigned char* _src, int step, Size size, unsigned char &thresh)
960 {
961     CV_INSTRUMENT_REGION_IPP()
962
963 #if IPP_VERSION_X100 >= 810
964     int ippStatus = -1;
965     IppiSize srcSize = { size.width, size.height };
966     CV_SUPPRESS_DEPRECATED_START
967     ippStatus = CV_INSTRUMENT_FUN_IPP(ippiComputeThreshold_Otsu_8u_C1R, _src, step, srcSize, &thresh);
968     CV_SUPPRESS_DEPRECATED_END
969
970     if(ippStatus >= 0)
971         return true;
972 #else
973     CV_UNUSED(_src); CV_UNUSED(step); CV_UNUSED(size); CV_UNUSED(thresh);
974 #endif
975     return false;
976 }
977 #endif
978
979 static double
980 getThreshVal_Otsu_8u( const Mat& _src )
981 {
982     Size size = _src.size();
983     int step = (int) _src.step;
984     if( _src.isContinuous() )
985     {
986         size.width *= size.height;
987         size.height = 1;
988         step = size.width;
989     }
990
991 #ifdef HAVE_IPP
992     unsigned char thresh;
993     CV_IPP_RUN(IPP_VERSION_X100 >= 810, ipp_getThreshVal_Otsu_8u(_src.ptr(), step, size, thresh), thresh);
994 #endif
995
996     const int N = 256;
997     int i, j, h[N] = {0};
998     for( i = 0; i < size.height; i++ )
999     {
1000         const uchar* src = _src.ptr() + step*i;
1001         j = 0;
1002         #if CV_ENABLE_UNROLLED
1003         for( ; j <= size.width - 4; j += 4 )
1004         {
1005             int v0 = src[j], v1 = src[j+1];
1006             h[v0]++; h[v1]++;
1007             v0 = src[j+2]; v1 = src[j+3];
1008             h[v0]++; h[v1]++;
1009         }
1010         #endif
1011         for( ; j < size.width; j++ )
1012             h[src[j]]++;
1013     }
1014
1015     double mu = 0, scale = 1./(size.width*size.height);
1016     for( i = 0; i < N; i++ )
1017         mu += i*(double)h[i];
1018
1019     mu *= scale;
1020     double mu1 = 0, q1 = 0;
1021     double max_sigma = 0, max_val = 0;
1022
1023     for( i = 0; i < N; i++ )
1024     {
1025         double p_i, q2, mu2, sigma;
1026
1027         p_i = h[i]*scale;
1028         mu1 *= q1;
1029         q1 += p_i;
1030         q2 = 1. - q1;
1031
1032         if( std::min(q1,q2) < FLT_EPSILON || std::max(q1,q2) > 1. - FLT_EPSILON )
1033             continue;
1034
1035         mu1 = (mu1 + i*p_i)/q1;
1036         mu2 = (mu - q1*mu1)/q2;
1037         sigma = q1*q2*(mu1 - mu2)*(mu1 - mu2);
1038         if( sigma > max_sigma )
1039         {
1040             max_sigma = sigma;
1041             max_val = i;
1042         }
1043     }
1044
1045     return max_val;
1046 }
1047
1048 static double
1049 getThreshVal_Triangle_8u( const Mat& _src )
1050 {
1051     Size size = _src.size();
1052     int step = (int) _src.step;
1053     if( _src.isContinuous() )
1054     {
1055         size.width *= size.height;
1056         size.height = 1;
1057         step = size.width;
1058     }
1059
1060     const int N = 256;
1061     int i, j, h[N] = {0};
1062     for( i = 0; i < size.height; i++ )
1063     {
1064         const uchar* src = _src.ptr() + step*i;
1065         j = 0;
1066         #if CV_ENABLE_UNROLLED
1067         for( ; j <= size.width - 4; j += 4 )
1068         {
1069             int v0 = src[j], v1 = src[j+1];
1070             h[v0]++; h[v1]++;
1071             v0 = src[j+2]; v1 = src[j+3];
1072             h[v0]++; h[v1]++;
1073         }
1074         #endif
1075         for( ; j < size.width; j++ )
1076             h[src[j]]++;
1077     }
1078
1079     int left_bound = 0, right_bound = 0, max_ind = 0, max = 0;
1080     int temp;
1081     bool isflipped = false;
1082
1083     for( i = 0; i < N; i++ )
1084     {
1085         if( h[i] > 0 )
1086         {
1087             left_bound = i;
1088             break;
1089         }
1090     }
1091     if( left_bound > 0 )
1092         left_bound--;
1093
1094     for( i = N-1; i > 0; i-- )
1095     {
1096         if( h[i] > 0 )
1097         {
1098             right_bound = i;
1099             break;
1100         }
1101     }
1102     if( right_bound < N-1 )
1103         right_bound++;
1104
1105     for( i = 0; i < N; i++ )
1106     {
1107         if( h[i] > max)
1108         {
1109             max = h[i];
1110             max_ind = i;
1111         }
1112     }
1113
1114     if( max_ind-left_bound < right_bound-max_ind)
1115     {
1116         isflipped = true;
1117         i = 0, j = N-1;
1118         while( i < j )
1119         {
1120             temp = h[i]; h[i] = h[j]; h[j] = temp;
1121             i++; j--;
1122         }
1123         left_bound = N-1-right_bound;
1124         max_ind = N-1-max_ind;
1125     }
1126
1127     double thresh = left_bound;
1128     double a, b, dist = 0, tempdist;
1129
1130     /*
1131      * We do not need to compute precise distance here. Distance is maximized, so some constants can
1132      * be omitted. This speeds up a computation a bit.
1133      */
1134     a = max; b = left_bound-max_ind;
1135     for( i = left_bound+1; i <= max_ind; i++ )
1136     {
1137         tempdist = a*i + b*h[i];
1138         if( tempdist > dist)
1139         {
1140             dist = tempdist;
1141             thresh = i;
1142         }
1143     }
1144     thresh--;
1145
1146     if( isflipped )
1147         thresh = N-1-thresh;
1148
1149     return thresh;
1150 }
1151
1152 class ThresholdRunner : public ParallelLoopBody
1153 {
1154 public:
1155     ThresholdRunner(Mat _src, Mat _dst, double _thresh, double _maxval, int _thresholdType)
1156     {
1157         src = _src;
1158         dst = _dst;
1159
1160         thresh = _thresh;
1161         maxval = _maxval;
1162         thresholdType = _thresholdType;
1163     }
1164
1165     void operator () ( const Range& range ) const
1166     {
1167         int row0 = range.start;
1168         int row1 = range.end;
1169
1170         Mat srcStripe = src.rowRange(row0, row1);
1171         Mat dstStripe = dst.rowRange(row0, row1);
1172
1173         if (srcStripe.depth() == CV_8U)
1174         {
1175             thresh_8u( srcStripe, dstStripe, (uchar)thresh, (uchar)maxval, thresholdType );
1176         }
1177         else if( srcStripe.depth() == CV_16S )
1178         {
1179             thresh_16s( srcStripe, dstStripe, (short)thresh, (short)maxval, thresholdType );
1180         }
1181         else if( srcStripe.depth() == CV_32F )
1182         {
1183             thresh_32f( srcStripe, dstStripe, (float)thresh, (float)maxval, thresholdType );
1184         }
1185         else if( srcStripe.depth() == CV_64F )
1186         {
1187             thresh_64f(srcStripe, dstStripe, thresh, maxval, thresholdType);
1188         }
1189     }
1190
1191 private:
1192     Mat src;
1193     Mat dst;
1194
1195     double thresh;
1196     double maxval;
1197     int thresholdType;
1198 };
1199
1200 #ifdef HAVE_OPENCL
1201
1202 static bool ocl_threshold( InputArray _src, OutputArray _dst, double & thresh, double maxval, int thresh_type )
1203 {
1204     int type = _src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type),
1205         kercn = ocl::predictOptimalVectorWidth(_src, _dst), ktype = CV_MAKE_TYPE(depth, kercn);
1206     bool doubleSupport = ocl::Device::getDefault().doubleFPConfig() > 0;
1207
1208     if ( !(thresh_type == THRESH_BINARY || thresh_type == THRESH_BINARY_INV || thresh_type == THRESH_TRUNC ||
1209            thresh_type == THRESH_TOZERO || thresh_type == THRESH_TOZERO_INV) ||
1210          (!doubleSupport && depth == CV_64F))
1211         return false;
1212
1213     const char * const thresholdMap[] = { "THRESH_BINARY", "THRESH_BINARY_INV", "THRESH_TRUNC",
1214                                           "THRESH_TOZERO", "THRESH_TOZERO_INV" };
1215     ocl::Device dev = ocl::Device::getDefault();
1216     int stride_size = dev.isIntel() && (dev.type() & ocl::Device::TYPE_GPU) ? 4 : 1;
1217
1218     ocl::Kernel k("threshold", ocl::imgproc::threshold_oclsrc,
1219                   format("-D %s -D T=%s -D T1=%s -D STRIDE_SIZE=%d%s", thresholdMap[thresh_type],
1220                          ocl::typeToStr(ktype), ocl::typeToStr(depth), stride_size,
1221                          doubleSupport ? " -D DOUBLE_SUPPORT" : ""));
1222     if (k.empty())
1223         return false;
1224
1225     UMat src = _src.getUMat();
1226     _dst.create(src.size(), type);
1227     UMat dst = _dst.getUMat();
1228
1229     if (depth <= CV_32S)
1230         thresh = cvFloor(thresh);
1231
1232     const double min_vals[] = { 0, CHAR_MIN, 0, SHRT_MIN, INT_MIN, -FLT_MAX, -DBL_MAX, 0 };
1233     double min_val = min_vals[depth];
1234
1235     k.args(ocl::KernelArg::ReadOnlyNoSize(src), ocl::KernelArg::WriteOnly(dst, cn, kercn),
1236            ocl::KernelArg::Constant(Mat(1, 1, depth, Scalar::all(thresh))),
1237            ocl::KernelArg::Constant(Mat(1, 1, depth, Scalar::all(maxval))),
1238            ocl::KernelArg::Constant(Mat(1, 1, depth, Scalar::all(min_val))));
1239
1240     size_t globalsize[2] = { (size_t)dst.cols * cn / kercn, (size_t)dst.rows };
1241     globalsize[1] = (globalsize[1] + stride_size - 1) / stride_size;
1242     return k.run(2, globalsize, NULL, false);
1243 }
1244
1245 #endif
1246
1247 }
1248
1249 double cv::threshold( InputArray _src, OutputArray _dst, double thresh, double maxval, int type )
1250 {
1251     CV_INSTRUMENT_REGION()
1252
1253     CV_OCL_RUN_(_src.dims() <= 2 && _dst.isUMat(),
1254                 ocl_threshold(_src, _dst, thresh, maxval, type), thresh)
1255
1256     Mat src = _src.getMat();
1257     int automatic_thresh = (type & ~CV_THRESH_MASK);
1258     type &= THRESH_MASK;
1259
1260     CV_Assert( automatic_thresh != (CV_THRESH_OTSU | CV_THRESH_TRIANGLE) );
1261     if( automatic_thresh == CV_THRESH_OTSU )
1262     {
1263         CV_Assert( src.type() == CV_8UC1 );
1264         thresh = getThreshVal_Otsu_8u( src );
1265     }
1266     else if( automatic_thresh == CV_THRESH_TRIANGLE )
1267     {
1268         CV_Assert( src.type() == CV_8UC1 );
1269         thresh = getThreshVal_Triangle_8u( src );
1270     }
1271
1272     _dst.create( src.size(), src.type() );
1273     Mat dst = _dst.getMat();
1274
1275     if( src.depth() == CV_8U )
1276     {
1277         int ithresh = cvFloor(thresh);
1278         thresh = ithresh;
1279         int imaxval = cvRound(maxval);
1280         if( type == THRESH_TRUNC )
1281             imaxval = ithresh;
1282         imaxval = saturate_cast<uchar>(imaxval);
1283
1284         if( ithresh < 0 || ithresh >= 255 )
1285         {
1286             if( type == THRESH_BINARY || type == THRESH_BINARY_INV ||
1287                 ((type == THRESH_TRUNC || type == THRESH_TOZERO_INV) && ithresh < 0) ||
1288                 (type == THRESH_TOZERO && ithresh >= 255) )
1289             {
1290                 int v = type == THRESH_BINARY ? (ithresh >= 255 ? 0 : imaxval) :
1291                         type == THRESH_BINARY_INV ? (ithresh >= 255 ? imaxval : 0) :
1292                         /*type == THRESH_TRUNC ? imaxval :*/ 0;
1293                 dst.setTo(v);
1294             }
1295             else
1296                 src.copyTo(dst);
1297             return thresh;
1298         }
1299         thresh = ithresh;
1300         maxval = imaxval;
1301     }
1302     else if( src.depth() == CV_16S )
1303     {
1304         int ithresh = cvFloor(thresh);
1305         thresh = ithresh;
1306         int imaxval = cvRound(maxval);
1307         if( type == THRESH_TRUNC )
1308             imaxval = ithresh;
1309         imaxval = saturate_cast<short>(imaxval);
1310
1311         if( ithresh < SHRT_MIN || ithresh >= SHRT_MAX )
1312         {
1313             if( type == THRESH_BINARY || type == THRESH_BINARY_INV ||
1314                ((type == THRESH_TRUNC || type == THRESH_TOZERO_INV) && ithresh < SHRT_MIN) ||
1315                (type == THRESH_TOZERO && ithresh >= SHRT_MAX) )
1316             {
1317                 int v = type == THRESH_BINARY ? (ithresh >= SHRT_MAX ? 0 : imaxval) :
1318                 type == THRESH_BINARY_INV ? (ithresh >= SHRT_MAX ? imaxval : 0) :
1319                 /*type == THRESH_TRUNC ? imaxval :*/ 0;
1320                 dst.setTo(v);
1321             }
1322             else
1323                 src.copyTo(dst);
1324             return thresh;
1325         }
1326         thresh = ithresh;
1327         maxval = imaxval;
1328     }
1329     else if( src.depth() == CV_32F )
1330         ;
1331     else if( src.depth() == CV_64F )
1332         ;
1333     else
1334         CV_Error( CV_StsUnsupportedFormat, "" );
1335
1336     parallel_for_(Range(0, dst.rows),
1337                   ThresholdRunner(src, dst, thresh, maxval, type),
1338                   dst.total()/(double)(1<<16));
1339     return thresh;
1340 }
1341
1342
1343 void cv::adaptiveThreshold( InputArray _src, OutputArray _dst, double maxValue,
1344                             int method, int type, int blockSize, double delta )
1345 {
1346     CV_INSTRUMENT_REGION()
1347
1348     Mat src = _src.getMat();
1349     CV_Assert( src.type() == CV_8UC1 );
1350     CV_Assert( blockSize % 2 == 1 && blockSize > 1 );
1351     Size size = src.size();
1352
1353     _dst.create( size, src.type() );
1354     Mat dst = _dst.getMat();
1355
1356     if( maxValue < 0 )
1357     {
1358         dst = Scalar(0);
1359         return;
1360     }
1361
1362     Mat mean;
1363
1364     if( src.data != dst.data )
1365         mean = dst;
1366
1367     if (method == ADAPTIVE_THRESH_MEAN_C)
1368         boxFilter( src, mean, src.type(), Size(blockSize, blockSize),
1369                    Point(-1,-1), true, BORDER_REPLICATE );
1370     else if (method == ADAPTIVE_THRESH_GAUSSIAN_C)
1371     {
1372         Mat srcfloat,meanfloat;
1373         src.convertTo(srcfloat,CV_32F);
1374         meanfloat=srcfloat;
1375         GaussianBlur(srcfloat, meanfloat, Size(blockSize, blockSize), 0, 0, BORDER_REPLICATE);
1376         meanfloat.convertTo(mean, src.type());
1377     }
1378     else
1379         CV_Error( CV_StsBadFlag, "Unknown/unsupported adaptive threshold method" );
1380
1381     int i, j;
1382     uchar imaxval = saturate_cast<uchar>(maxValue);
1383     int idelta = type == THRESH_BINARY ? cvCeil(delta) : cvFloor(delta);
1384     uchar tab[768];
1385
1386     if( type == CV_THRESH_BINARY )
1387         for( i = 0; i < 768; i++ )
1388             tab[i] = (uchar)(i - 255 > -idelta ? imaxval : 0);
1389     else if( type == CV_THRESH_BINARY_INV )
1390         for( i = 0; i < 768; i++ )
1391             tab[i] = (uchar)(i - 255 <= -idelta ? imaxval : 0);
1392     else
1393         CV_Error( CV_StsBadFlag, "Unknown/unsupported threshold type" );
1394
1395     if( src.isContinuous() && mean.isContinuous() && dst.isContinuous() )
1396     {
1397         size.width *= size.height;
1398         size.height = 1;
1399     }
1400
1401     for( i = 0; i < size.height; i++ )
1402     {
1403         const uchar* sdata = src.ptr(i);
1404         const uchar* mdata = mean.ptr(i);
1405         uchar* ddata = dst.ptr(i);
1406
1407         for( j = 0; j < size.width; j++ )
1408             ddata[j] = tab[sdata[j] - mdata[j] + 255];
1409     }
1410 }
1411
1412 CV_IMPL double
1413 cvThreshold( const void* srcarr, void* dstarr, double thresh, double maxval, int type )
1414 {
1415     cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr), dst0 = dst;
1416
1417     CV_Assert( src.size == dst.size && src.channels() == dst.channels() &&
1418         (src.depth() == dst.depth() || dst.depth() == CV_8U));
1419
1420     thresh = cv::threshold( src, dst, thresh, maxval, type );
1421     if( dst0.data != dst.data )
1422         dst.convertTo( dst0, dst0.depth() );
1423     return thresh;
1424 }
1425
1426
1427 CV_IMPL void
1428 cvAdaptiveThreshold( const void *srcIm, void *dstIm, double maxValue,
1429                      int method, int type, int blockSize, double delta )
1430 {
1431     cv::Mat src = cv::cvarrToMat(srcIm), dst = cv::cvarrToMat(dstIm);
1432     CV_Assert( src.size == dst.size && src.type() == dst.type() );
1433     cv::adaptiveThreshold( src, dst, maxValue, method, type, blockSize, delta );
1434 }
1435
1436 /* End of file. */