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