the do / gr-peach-opencv-project

Fork of gr-peach-opencv-project by the do

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers thresh.cpp Source File

thresh.cpp

00001 /*M///////////////////////////////////////////////////////////////////////////////////////
00002 //
00003 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
00004 //
00005 //  By downloading, copying, installing or using the software you agree to this license.
00006 //  If you do not agree to this license, do not download, install,
00007 //  copy or use the software.
00008 //
00009 //
00010 //                           License Agreement
00011 //                For Open Source Computer Vision Library
00012 //
00013 // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
00014 // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
00015 // Third party copyrights are property of their respective owners.
00016 //
00017 // Redistribution and use in source and binary forms, with or without modification,
00018 // are permitted provided that the following conditions are met:
00019 //
00020 //   * Redistribution's of source code must retain the above copyright notice,
00021 //     this list of conditions and the following disclaimer.
00022 //
00023 //   * Redistribution's in binary form must reproduce the above copyright notice,
00024 //     this list of conditions and the following disclaimer in the documentation
00025 //     and/or other materials provided with the distribution.
00026 //
00027 //   * The name of the copyright holders may not be used to endorse or promote products
00028 //     derived from this software without specific prior written permission.
00029 //
00030 // This software is provided by the copyright holders and contributors "as is" and
00031 // any express or implied warranties, including, but not limited to, the implied
00032 // warranties of merchantability and fitness for a particular purpose are disclaimed.
00033 // In no event shall the Intel Corporation or contributors be liable for any direct,
00034 // indirect, incidental, special, exemplary, or consequential damages
00035 // (including, but not limited to, procurement of substitute goods or services;
00036 // loss of use, data, or profits; or business interruption) however caused
00037 // and on any theory of liability, whether in contract, strict liability,
00038 // or tort (including negligence or otherwise) arising in any way out of
00039 // the use of this software, even if advised of the possibility of such damage.
00040 //
00041 //M*/
00042 
00043 #include "precomp.hpp"
00044 #include "opencl_kernels_imgproc.hpp"
00045 
00046 namespace cv
00047 {
00048 
00049 static void
00050 thresh_8u( const Mat& _src, Mat& _dst, uchar thresh, uchar maxval, int type )
00051 {
00052     int i, j, j_scalar = 0;
00053     uchar tab[256];
00054     Size roi = _src.size();
00055     roi.width *= _src.channels();
00056     size_t src_step = _src.step;
00057     size_t dst_step = _dst.step;
00058 
00059     if( _src.isContinuous() && _dst.isContinuous() )
00060     {
00061         roi.width *= roi.height;
00062         roi.height = 1;
00063         src_step = dst_step = roi.width;
00064     }
00065 
00066 #ifdef HAVE_TEGRA_OPTIMIZATION
00067     if (tegra::useTegra() && tegra::thresh_8u(_src, _dst, roi.width, roi.height, thresh, maxval, type))
00068         return;
00069 #endif
00070 
00071 #if defined(HAVE_IPP)
00072     CV_IPP_CHECK()
00073     {
00074         IppiSize sz = { roi.width, roi.height };
00075         CV_SUPPRESS_DEPRECATED_START
00076         switch( type )
00077         {
00078         case THRESH_TRUNC :
00079 #ifndef HAVE_IPP_ICV_ONLY
00080             if (_src.data == _dst.data && ippiThreshold_GT_8u_C1IR(_dst.ptr(), (int)dst_step, sz, thresh) >= 0)
00081             {
00082                 CV_IMPL_ADD(CV_IMPL_IPP);
00083                 return;
00084             }
00085 #endif
00086             if (ippiThreshold_GT_8u_C1R(_src.ptr(), (int)src_step, _dst.ptr(), (int)dst_step, sz, thresh) >= 0)
00087             {
00088                 CV_IMPL_ADD(CV_IMPL_IPP);
00089                 return;
00090             }
00091             setIppErrorStatus();
00092             break;
00093         case THRESH_TOZERO :
00094 #ifndef HAVE_IPP_ICV_ONLY
00095             if (_src.data == _dst.data && ippiThreshold_LTVal_8u_C1IR(_dst.ptr(), (int)dst_step, sz, thresh+1, 0) >= 0)
00096             {
00097                 CV_IMPL_ADD(CV_IMPL_IPP);
00098                 return;
00099             }
00100 #endif
00101             if (ippiThreshold_LTVal_8u_C1R(_src.ptr(), (int)src_step, _dst.ptr(), (int)dst_step, sz, thresh+1, 0) >= 0)
00102             {
00103                 CV_IMPL_ADD(CV_IMPL_IPP);
00104                 return;
00105             }
00106             setIppErrorStatus();
00107             break;
00108         case THRESH_TOZERO_INV :
00109 #ifndef HAVE_IPP_ICV_ONLY
00110             if (_src.data == _dst.data && ippiThreshold_GTVal_8u_C1IR(_dst.ptr(), (int)dst_step, sz, thresh, 0) >= 0)
00111             {
00112                 CV_IMPL_ADD(CV_IMPL_IPP);
00113                 return;
00114             }
00115 #endif
00116             if (ippiThreshold_GTVal_8u_C1R(_src.ptr(), (int)src_step, _dst.ptr(), (int)dst_step, sz, thresh, 0) >= 0)
00117             {
00118                 CV_IMPL_ADD(CV_IMPL_IPP);
00119                 return;
00120             }
00121             setIppErrorStatus();
00122             break;
00123         }
00124         CV_SUPPRESS_DEPRECATED_END
00125     }
00126 #endif
00127 
00128     switch( type )
00129     {
00130     case THRESH_BINARY :
00131         for( i = 0; i <= thresh; i++ )
00132             tab[i] = 0;
00133         for( ; i < 256; i++ )
00134             tab[i] = maxval;
00135         break;
00136     case THRESH_BINARY_INV :
00137         for( i = 0; i <= thresh; i++ )
00138             tab[i] = maxval;
00139         for( ; i < 256; i++ )
00140             tab[i] = 0;
00141         break;
00142     case THRESH_TRUNC :
00143         for( i = 0; i <= thresh; i++ )
00144             tab[i] = (uchar)i;
00145         for( ; i < 256; i++ )
00146             tab[i] = thresh;
00147         break;
00148     case THRESH_TOZERO :
00149         for( i = 0; i <= thresh; i++ )
00150             tab[i] = 0;
00151         for( ; i < 256; i++ )
00152             tab[i] = (uchar)i;
00153         break;
00154     case THRESH_TOZERO_INV :
00155         for( i = 0; i <= thresh; i++ )
00156             tab[i] = (uchar)i;
00157         for( ; i < 256; i++ )
00158             tab[i] = 0;
00159         break;
00160     default:
00161         CV_Error( CV_StsBadArg, "Unknown threshold type" );
00162     }
00163 
00164 #if CV_SSE2
00165     if( checkHardwareSupport(CV_CPU_SSE2) )
00166     {
00167         __m128i _x80 = _mm_set1_epi8('\x80');
00168         __m128i thresh_u = _mm_set1_epi8(thresh);
00169         __m128i thresh_s = _mm_set1_epi8(thresh ^ 0x80);
00170         __m128i maxval_ = _mm_set1_epi8(maxval);
00171         j_scalar = roi.width & -8;
00172 
00173         for( i = 0; i < roi.height; i++ )
00174         {
00175             const uchar* src = _src.ptr() + src_step*i;
00176             uchar* dst = _dst.ptr() + dst_step*i;
00177 
00178             switch( type )
00179             {
00180             case THRESH_BINARY :
00181                 for( j = 0; j <= roi.width - 32; j += 32 )
00182                 {
00183                     __m128i v0, v1;
00184                     v0 = _mm_loadu_si128( (const __m128i*)(src + j) );
00185                     v1 = _mm_loadu_si128( (const __m128i*)(src + j + 16) );
00186                     v0 = _mm_cmpgt_epi8( _mm_xor_si128(v0, _x80), thresh_s );
00187                     v1 = _mm_cmpgt_epi8( _mm_xor_si128(v1, _x80), thresh_s );
00188                     v0 = _mm_and_si128( v0, maxval_ );
00189                     v1 = _mm_and_si128( v1, maxval_ );
00190                     _mm_storeu_si128( (__m128i*)(dst + j), v0 );
00191                     _mm_storeu_si128( (__m128i*)(dst + j + 16), v1 );
00192                 }
00193 
00194                 for( ; j <= roi.width - 8; j += 8 )
00195                 {
00196                     __m128i v0 = _mm_loadl_epi64( (const __m128i*)(src + j) );
00197                     v0 = _mm_cmpgt_epi8( _mm_xor_si128(v0, _x80), thresh_s );
00198                     v0 = _mm_and_si128( v0, maxval_ );
00199                     _mm_storel_epi64( (__m128i*)(dst + j), v0 );
00200                 }
00201                 break;
00202 
00203             case THRESH_BINARY_INV :
00204                 for( j = 0; j <= roi.width - 32; j += 32 )
00205                 {
00206                     __m128i v0, v1;
00207                     v0 = _mm_loadu_si128( (const __m128i*)(src + j) );
00208                     v1 = _mm_loadu_si128( (const __m128i*)(src + j + 16) );
00209                     v0 = _mm_cmpgt_epi8( _mm_xor_si128(v0, _x80), thresh_s );
00210                     v1 = _mm_cmpgt_epi8( _mm_xor_si128(v1, _x80), thresh_s );
00211                     v0 = _mm_andnot_si128( v0, maxval_ );
00212                     v1 = _mm_andnot_si128( v1, maxval_ );
00213                     _mm_storeu_si128( (__m128i*)(dst + j), v0 );
00214                     _mm_storeu_si128( (__m128i*)(dst + j + 16), v1 );
00215                 }
00216 
00217                 for( ; j <= roi.width - 8; j += 8 )
00218                 {
00219                     __m128i v0 = _mm_loadl_epi64( (const __m128i*)(src + j) );
00220                     v0 = _mm_cmpgt_epi8( _mm_xor_si128(v0, _x80), thresh_s );
00221                     v0 = _mm_andnot_si128( v0, maxval_ );
00222                     _mm_storel_epi64( (__m128i*)(dst + j), v0 );
00223                 }
00224                 break;
00225 
00226             case THRESH_TRUNC :
00227                 for( j = 0; j <= roi.width - 32; j += 32 )
00228                 {
00229                     __m128i v0, v1;
00230                     v0 = _mm_loadu_si128( (const __m128i*)(src + j) );
00231                     v1 = _mm_loadu_si128( (const __m128i*)(src + j + 16) );
00232                     v0 = _mm_subs_epu8( v0, _mm_subs_epu8( v0, thresh_u ));
00233                     v1 = _mm_subs_epu8( v1, _mm_subs_epu8( v1, thresh_u ));
00234                     _mm_storeu_si128( (__m128i*)(dst + j), v0 );
00235                     _mm_storeu_si128( (__m128i*)(dst + j + 16), v1 );
00236                 }
00237 
00238                 for( ; j <= roi.width - 8; j += 8 )
00239                 {
00240                     __m128i v0 = _mm_loadl_epi64( (const __m128i*)(src + j) );
00241                     v0 = _mm_subs_epu8( v0, _mm_subs_epu8( v0, thresh_u ));
00242                     _mm_storel_epi64( (__m128i*)(dst + j), v0 );
00243                 }
00244                 break;
00245 
00246             case THRESH_TOZERO :
00247                 for( j = 0; j <= roi.width - 32; j += 32 )
00248                 {
00249                     __m128i v0, v1;
00250                     v0 = _mm_loadu_si128( (const __m128i*)(src + j) );
00251                     v1 = _mm_loadu_si128( (const __m128i*)(src + j + 16) );
00252                     v0 = _mm_and_si128( v0, _mm_cmpgt_epi8(_mm_xor_si128(v0, _x80), thresh_s ));
00253                     v1 = _mm_and_si128( v1, _mm_cmpgt_epi8(_mm_xor_si128(v1, _x80), thresh_s ));
00254                     _mm_storeu_si128( (__m128i*)(dst + j), v0 );
00255                     _mm_storeu_si128( (__m128i*)(dst + j + 16), v1 );
00256                 }
00257 
00258                 for( ; j <= roi.width - 8; j += 8 )
00259                 {
00260                     __m128i v0 = _mm_loadl_epi64( (const __m128i*)(src + j) );
00261                     v0 = _mm_and_si128( v0, _mm_cmpgt_epi8(_mm_xor_si128(v0, _x80), thresh_s ));
00262                     _mm_storel_epi64( (__m128i*)(dst + j), v0 );
00263                 }
00264                 break;
00265 
00266             case THRESH_TOZERO_INV :
00267                 for( j = 0; j <= roi.width - 32; j += 32 )
00268                 {
00269                     __m128i v0, v1;
00270                     v0 = _mm_loadu_si128( (const __m128i*)(src + j) );
00271                     v1 = _mm_loadu_si128( (const __m128i*)(src + j + 16) );
00272                     v0 = _mm_andnot_si128( _mm_cmpgt_epi8(_mm_xor_si128(v0, _x80), thresh_s ), v0 );
00273                     v1 = _mm_andnot_si128( _mm_cmpgt_epi8(_mm_xor_si128(v1, _x80), thresh_s ), v1 );
00274                     _mm_storeu_si128( (__m128i*)(dst + j), v0 );
00275                     _mm_storeu_si128( (__m128i*)(dst + j + 16), v1 );
00276                 }
00277 
00278                 for( ; j <= roi.width - 8; j += 8 )
00279                 {
00280                     __m128i v0 = _mm_loadl_epi64( (const __m128i*)(src + j) );
00281                     v0 = _mm_andnot_si128( _mm_cmpgt_epi8(_mm_xor_si128(v0, _x80), thresh_s ), v0 );
00282                     _mm_storel_epi64( (__m128i*)(dst + j), v0 );
00283                 }
00284                 break;
00285             }
00286         }
00287     }
00288 #elif CV_NEON
00289     uint8x16_t v_thresh = vdupq_n_u8(thresh), v_maxval = vdupq_n_u8(maxval);
00290 
00291     switch( type )
00292     {
00293     case THRESH_BINARY :
00294         for( i = 0; i < roi.height; i++ )
00295         {
00296             const uchar* src = _src.ptr() + src_step*i;
00297             uchar* dst = _dst.ptr() + dst_step*i;
00298 
00299             for ( j_scalar = 0; j_scalar <= roi.width - 16; j_scalar += 16)
00300                 vst1q_u8(dst + j_scalar, vandq_u8(vcgtq_u8(vld1q_u8(src + j_scalar), v_thresh), v_maxval));
00301         }
00302         break;
00303 
00304     case THRESH_BINARY_INV :
00305         for( i = 0; i < roi.height; i++ )
00306         {
00307             const uchar* src = _src.ptr() + src_step*i;
00308             uchar* dst = _dst.ptr() + dst_step*i;
00309 
00310             for ( j_scalar = 0; j_scalar <= roi.width - 16; j_scalar += 16)
00311                 vst1q_u8(dst + j_scalar, vandq_u8(vcleq_u8(vld1q_u8(src + j_scalar), v_thresh), v_maxval));
00312         }
00313         break;
00314 
00315     case THRESH_TRUNC :
00316         for( i = 0; i < roi.height; i++ )
00317         {
00318             const uchar* src = _src.ptr() + src_step*i;
00319             uchar* dst = _dst.ptr() + dst_step*i;
00320 
00321             for ( j_scalar = 0; j_scalar <= roi.width - 16; j_scalar += 16)
00322                 vst1q_u8(dst + j_scalar, vminq_u8(vld1q_u8(src + j_scalar), v_thresh));
00323         }
00324         break;
00325 
00326     case THRESH_TOZERO :
00327         for( i = 0; i < roi.height; i++ )
00328         {
00329             const uchar* src = _src.ptr() + src_step*i;
00330             uchar* dst = _dst.ptr() + dst_step*i;
00331 
00332             for ( j_scalar = 0; j_scalar <= roi.width - 16; j_scalar += 16)
00333             {
00334                 uint8x16_t v_src = vld1q_u8(src + j_scalar), v_mask = vcgtq_u8(v_src, v_thresh);
00335                 vst1q_u8(dst + j_scalar, vandq_u8(v_mask, v_src));
00336             }
00337         }
00338         break;
00339 
00340     case THRESH_TOZERO_INV :
00341         for( i = 0; i < roi.height; i++ )
00342         {
00343             const uchar* src = _src.ptr() + src_step*i;
00344             uchar* dst = _dst.ptr() + dst_step*i;
00345 
00346             for ( j_scalar = 0; j_scalar <= roi.width - 16; j_scalar += 16)
00347             {
00348                 uint8x16_t v_src = vld1q_u8(src + j_scalar), v_mask = vcleq_u8(v_src, v_thresh);
00349                 vst1q_u8(dst + j_scalar, vandq_u8(v_mask, v_src));
00350             }
00351         }
00352         break;
00353     default:
00354         return CV_Error( CV_StsBadArg, "" );
00355     }
00356 #endif
00357 
00358     if( j_scalar < roi.width )
00359     {
00360         for( i = 0; i < roi.height; i++ )
00361         {
00362             const uchar* src = _src.ptr() + src_step*i;
00363             uchar* dst = _dst.ptr() + dst_step*i;
00364             j = j_scalar;
00365 #if CV_ENABLE_UNROLLED
00366             for( ; j <= roi.width - 4; j += 4 )
00367             {
00368                 uchar t0 = tab[src[j]];
00369                 uchar t1 = tab[src[j+1]];
00370 
00371                 dst[j] = t0;
00372                 dst[j+1] = t1;
00373 
00374                 t0 = tab[src[j+2]];
00375                 t1 = tab[src[j+3]];
00376 
00377                 dst[j+2] = t0;
00378                 dst[j+3] = t1;
00379             }
00380 #endif
00381             for( ; j < roi.width; j++ )
00382                 dst[j] = tab[src[j]];
00383         }
00384     }
00385 }
00386 
00387 
00388 static void
00389 thresh_16s( const Mat& _src, Mat& _dst, short thresh, short maxval, int type )
00390 {
00391     int i, j;
00392     Size roi = _src.size();
00393     roi.width *= _src.channels();
00394     const short* src = _src.ptr<short>();
00395     short* dst = _dst.ptr<short>();
00396     size_t src_step = _src.step/sizeof(src[0]);
00397     size_t dst_step = _dst.step/sizeof(dst[0]);
00398 
00399 #if CV_SSE2
00400     volatile bool useSIMD = checkHardwareSupport(CV_CPU_SSE);
00401 #endif
00402 
00403     if( _src.isContinuous() && _dst.isContinuous() )
00404     {
00405         roi.width *= roi.height;
00406         roi.height = 1;
00407         src_step = dst_step = roi.width;
00408     }
00409 
00410 #ifdef HAVE_TEGRA_OPTIMIZATION
00411     if (tegra::useTegra() && tegra::thresh_16s(_src, _dst, roi.width, roi.height, thresh, maxval, type))
00412         return;
00413 #endif
00414 
00415 #if defined(HAVE_IPP)
00416     CV_IPP_CHECK()
00417     {
00418         IppiSize sz = { roi.width, roi.height };
00419         CV_SUPPRESS_DEPRECATED_START
00420         switch( type )
00421         {
00422         case THRESH_TRUNC :
00423 #ifndef HAVE_IPP_ICV_ONLY
00424             if (_src.data == _dst.data && ippiThreshold_GT_16s_C1IR(dst, (int)dst_step*sizeof(dst[0]), sz, thresh) >= 0)
00425             {
00426                 CV_IMPL_ADD(CV_IMPL_IPP);
00427                 return;
00428             }
00429 #endif
00430             if (ippiThreshold_GT_16s_C1R(src, (int)src_step*sizeof(src[0]), dst, (int)dst_step*sizeof(dst[0]), sz, thresh) >= 0)
00431             {
00432                 CV_IMPL_ADD(CV_IMPL_IPP);
00433                 return;
00434             }
00435             setIppErrorStatus();
00436             break;
00437         case THRESH_TOZERO :
00438 #ifndef HAVE_IPP_ICV_ONLY
00439             if (_src.data == _dst.data && ippiThreshold_LTVal_16s_C1IR(dst, (int)dst_step*sizeof(dst[0]), sz, thresh + 1, 0) >= 0)
00440             {
00441                 CV_IMPL_ADD(CV_IMPL_IPP);
00442                 return;
00443             }
00444 #endif
00445             if (ippiThreshold_LTVal_16s_C1R(src, (int)src_step*sizeof(src[0]), dst, (int)dst_step*sizeof(dst[0]), sz, thresh+1, 0) >= 0)
00446             {
00447                 CV_IMPL_ADD(CV_IMPL_IPP);
00448                 return;
00449             }
00450             setIppErrorStatus();
00451             break;
00452         case THRESH_TOZERO_INV :
00453 #ifndef HAVE_IPP_ICV_ONLY
00454             if (_src.data == _dst.data && ippiThreshold_GTVal_16s_C1IR(dst, (int)dst_step*sizeof(dst[0]), sz, thresh, 0) >= 0)
00455             {
00456                 CV_IMPL_ADD(CV_IMPL_IPP);
00457                 return;
00458             }
00459 #endif
00460             if (ippiThreshold_GTVal_16s_C1R(src, (int)src_step*sizeof(src[0]), dst, (int)dst_step*sizeof(dst[0]), sz, thresh, 0) >= 0)
00461             {
00462                 CV_IMPL_ADD(CV_IMPL_IPP);
00463                 return;
00464             }
00465             setIppErrorStatus();
00466             break;
00467         }
00468         CV_SUPPRESS_DEPRECATED_END
00469     }
00470 #endif
00471 
00472     switch( type )
00473     {
00474     case THRESH_BINARY :
00475         for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
00476         {
00477             j = 0;
00478         #if CV_SSE2
00479             if( useSIMD )
00480             {
00481                 __m128i thresh8 = _mm_set1_epi16(thresh), maxval8 = _mm_set1_epi16(maxval);
00482                 for( ; j <= roi.width - 16; j += 16 )
00483                 {
00484                     __m128i v0, v1;
00485                     v0 = _mm_loadu_si128( (const __m128i*)(src + j) );
00486                     v1 = _mm_loadu_si128( (const __m128i*)(src + j + 8) );
00487                     v0 = _mm_cmpgt_epi16( v0, thresh8 );
00488                     v1 = _mm_cmpgt_epi16( v1, thresh8 );
00489                     v0 = _mm_and_si128( v0, maxval8 );
00490                     v1 = _mm_and_si128( v1, maxval8 );
00491                     _mm_storeu_si128((__m128i*)(dst + j), v0 );
00492                     _mm_storeu_si128((__m128i*)(dst + j + 8), v1 );
00493                 }
00494             }
00495         #elif CV_NEON
00496             int16x8_t v_thresh = vdupq_n_s16(thresh), v_maxval = vdupq_n_s16(maxval);
00497 
00498             for( ; j <= roi.width - 8; j += 8 )
00499             {
00500                 uint16x8_t v_mask = vcgtq_s16(vld1q_s16(src + j), v_thresh);
00501                 vst1q_s16(dst + j, vandq_s16(vreinterpretq_s16_u16(v_mask), v_maxval));
00502             }
00503         #endif
00504 
00505             for( ; j < roi.width; j++ )
00506                 dst[j] = src[j] > thresh ? maxval : 0;
00507         }
00508         break;
00509 
00510     case THRESH_BINARY_INV :
00511         for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
00512         {
00513             j = 0;
00514         #if CV_SSE2
00515             if( useSIMD )
00516             {
00517                 __m128i thresh8 = _mm_set1_epi16(thresh), maxval8 = _mm_set1_epi16(maxval);
00518                 for( ; j <= roi.width - 16; j += 16 )
00519                 {
00520                     __m128i v0, v1;
00521                     v0 = _mm_loadu_si128( (const __m128i*)(src + j) );
00522                     v1 = _mm_loadu_si128( (const __m128i*)(src + j + 8) );
00523                     v0 = _mm_cmpgt_epi16( v0, thresh8 );
00524                     v1 = _mm_cmpgt_epi16( v1, thresh8 );
00525                     v0 = _mm_andnot_si128( v0, maxval8 );
00526                     v1 = _mm_andnot_si128( v1, maxval8 );
00527                     _mm_storeu_si128((__m128i*)(dst + j), v0 );
00528                     _mm_storeu_si128((__m128i*)(dst + j + 8), v1 );
00529                 }
00530             }
00531         #elif CV_NEON
00532             int16x8_t v_thresh = vdupq_n_s16(thresh), v_maxval = vdupq_n_s16(maxval);
00533 
00534             for( ; j <= roi.width - 8; j += 8 )
00535             {
00536                 uint16x8_t v_mask = vcleq_s16(vld1q_s16(src + j), v_thresh);
00537                 vst1q_s16(dst + j, vandq_s16(vreinterpretq_s16_u16(v_mask), v_maxval));
00538             }
00539         #endif
00540 
00541             for( ; j < roi.width; j++ )
00542                 dst[j] = src[j] <= thresh ? maxval : 0;
00543         }
00544         break;
00545 
00546     case THRESH_TRUNC :
00547         for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
00548         {
00549             j = 0;
00550         #if CV_SSE2
00551             if( useSIMD )
00552             {
00553                 __m128i thresh8 = _mm_set1_epi16(thresh);
00554                 for( ; j <= roi.width - 16; j += 16 )
00555                 {
00556                     __m128i v0, v1;
00557                     v0 = _mm_loadu_si128( (const __m128i*)(src + j) );
00558                     v1 = _mm_loadu_si128( (const __m128i*)(src + j + 8) );
00559                     v0 = _mm_min_epi16( v0, thresh8 );
00560                     v1 = _mm_min_epi16( v1, thresh8 );
00561                     _mm_storeu_si128((__m128i*)(dst + j), v0 );
00562                     _mm_storeu_si128((__m128i*)(dst + j + 8), v1 );
00563                 }
00564             }
00565         #elif CV_NEON
00566             int16x8_t v_thresh = vdupq_n_s16(thresh);
00567 
00568             for( ; j <= roi.width - 8; j += 8 )
00569                 vst1q_s16(dst + j, vminq_s16(vld1q_s16(src + j), v_thresh));
00570         #endif
00571 
00572             for( ; j < roi.width; j++ )
00573                 dst[j] = std::min(src[j], thresh);
00574         }
00575         break;
00576 
00577     case THRESH_TOZERO :
00578         for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
00579         {
00580             j = 0;
00581         #if CV_SSE2
00582             if( useSIMD )
00583             {
00584                 __m128i thresh8 = _mm_set1_epi16(thresh);
00585                 for( ; j <= roi.width - 16; j += 16 )
00586                 {
00587                     __m128i v0, v1;
00588                     v0 = _mm_loadu_si128( (const __m128i*)(src + j) );
00589                     v1 = _mm_loadu_si128( (const __m128i*)(src + j + 8) );
00590                     v0 = _mm_and_si128(v0, _mm_cmpgt_epi16(v0, thresh8));
00591                     v1 = _mm_and_si128(v1, _mm_cmpgt_epi16(v1, thresh8));
00592                     _mm_storeu_si128((__m128i*)(dst + j), v0 );
00593                     _mm_storeu_si128((__m128i*)(dst + j + 8), v1 );
00594                 }
00595             }
00596         #elif CV_NEON
00597             int16x8_t v_thresh = vdupq_n_s16(thresh);
00598 
00599             for( ; j <= roi.width - 8; j += 8 )
00600             {
00601                 int16x8_t v_src = vld1q_s16(src + j);
00602                 uint16x8_t v_mask = vcgtq_s16(v_src, v_thresh);
00603                 vst1q_s16(dst + j, vandq_s16(vreinterpretq_s16_u16(v_mask), v_src));
00604             }
00605         #endif
00606 
00607             for( ; j < roi.width; j++ )
00608             {
00609                 short v = src[j];
00610                 dst[j] = v > thresh ? v : 0;
00611             }
00612         }
00613         break;
00614 
00615     case THRESH_TOZERO_INV :
00616         for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
00617         {
00618             j = 0;
00619         #if CV_SSE2
00620             if( useSIMD )
00621             {
00622                 __m128i thresh8 = _mm_set1_epi16(thresh);
00623                 for( ; j <= roi.width - 16; j += 16 )
00624                 {
00625                     __m128i v0, v1;
00626                     v0 = _mm_loadu_si128( (const __m128i*)(src + j) );
00627                     v1 = _mm_loadu_si128( (const __m128i*)(src + j + 8) );
00628                     v0 = _mm_andnot_si128(_mm_cmpgt_epi16(v0, thresh8), v0);
00629                     v1 = _mm_andnot_si128(_mm_cmpgt_epi16(v1, thresh8), v1);
00630                     _mm_storeu_si128((__m128i*)(dst + j), v0 );
00631                     _mm_storeu_si128((__m128i*)(dst + j + 8), v1 );
00632                 }
00633             }
00634         #elif CV_NEON
00635             int16x8_t v_thresh = vdupq_n_s16(thresh);
00636 
00637             for( ; j <= roi.width - 8; j += 8 )
00638             {
00639                 int16x8_t v_src = vld1q_s16(src + j);
00640                 uint16x8_t v_mask = vcleq_s16(v_src, v_thresh);
00641                 vst1q_s16(dst + j, vandq_s16(vreinterpretq_s16_u16(v_mask), v_src));
00642             }
00643         #endif
00644             for( ; j < roi.width; j++ )
00645             {
00646                 short v = src[j];
00647                 dst[j] = v <= thresh ? v : 0;
00648             }
00649         }
00650         break;
00651     default:
00652         return CV_Error( CV_StsBadArg, "" );
00653     }
00654 }
00655 
00656 
00657 static void
00658 thresh_32f( const Mat& _src, Mat& _dst, float thresh, float maxval, int type )
00659 {
00660     int i, j;
00661     Size roi = _src.size();
00662     roi.width *= _src.channels();
00663     const float* src = _src.ptr<float>();
00664     float* dst = _dst.ptr<float>();
00665     size_t src_step = _src.step/sizeof(src[0]);
00666     size_t dst_step = _dst.step/sizeof(dst[0]);
00667 
00668 #if CV_SSE2
00669     volatile bool useSIMD = checkHardwareSupport(CV_CPU_SSE);
00670 #endif
00671 
00672     if( _src.isContinuous() && _dst.isContinuous() )
00673     {
00674         roi.width *= roi.height;
00675         roi.height = 1;
00676     }
00677 
00678 #ifdef HAVE_TEGRA_OPTIMIZATION
00679     if (tegra::useTegra() && tegra::thresh_32f(_src, _dst, roi.width, roi.height, thresh, maxval, type))
00680         return;
00681 #endif
00682 
00683 #if defined(HAVE_IPP)
00684     CV_IPP_CHECK()
00685     {
00686         IppiSize sz = { roi.width, roi.height };
00687         switch( type )
00688         {
00689         case THRESH_TRUNC :
00690             if (0 <= ippiThreshold_GT_32f_C1R(src, (int)src_step*sizeof(src[0]), dst, (int)dst_step*sizeof(dst[0]), sz, thresh))
00691             {
00692                 CV_IMPL_ADD(CV_IMPL_IPP);
00693                 return;
00694             }
00695             setIppErrorStatus();
00696             break;
00697         case THRESH_TOZERO :
00698             if (0 <= ippiThreshold_LTVal_32f_C1R(src, (int)src_step*sizeof(src[0]), dst, (int)dst_step*sizeof(dst[0]), sz, thresh+FLT_EPSILON, 0))
00699             {
00700                 CV_IMPL_ADD(CV_IMPL_IPP);
00701                 return;
00702             }
00703             setIppErrorStatus();
00704             break;
00705         case THRESH_TOZERO_INV :
00706             if (0 <= ippiThreshold_GTVal_32f_C1R(src, (int)src_step*sizeof(src[0]), dst, (int)dst_step*sizeof(dst[0]), sz, thresh, 0))
00707             {
00708                 CV_IMPL_ADD(CV_IMPL_IPP);
00709                 return;
00710             }
00711             setIppErrorStatus();
00712             break;
00713         }
00714     }
00715 #endif
00716 
00717     switch( type )
00718     {
00719         case THRESH_BINARY :
00720             for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
00721             {
00722                 j = 0;
00723 #if CV_SSE2
00724                 if( useSIMD )
00725                 {
00726                     __m128 thresh4 = _mm_set1_ps(thresh), maxval4 = _mm_set1_ps(maxval);
00727                     for( ; j <= roi.width - 8; j += 8 )
00728                     {
00729                         __m128 v0, v1;
00730                         v0 = _mm_loadu_ps( src + j );
00731                         v1 = _mm_loadu_ps( src + j + 4 );
00732                         v0 = _mm_cmpgt_ps( v0, thresh4 );
00733                         v1 = _mm_cmpgt_ps( v1, thresh4 );
00734                         v0 = _mm_and_ps( v0, maxval4 );
00735                         v1 = _mm_and_ps( v1, maxval4 );
00736                         _mm_storeu_ps( dst + j, v0 );
00737                         _mm_storeu_ps( dst + j + 4, v1 );
00738                     }
00739                 }
00740 #elif CV_NEON
00741                 float32x4_t v_thresh = vdupq_n_f32(thresh);
00742                 uint32x4_t v_maxval = vreinterpretq_u32_f32(vdupq_n_f32(maxval));
00743 
00744                 for( ; j <= roi.width - 4; j += 4 )
00745                 {
00746                     float32x4_t v_src = vld1q_f32(src + j);
00747                     uint32x4_t v_dst = vandq_u32(vcgtq_f32(v_src, v_thresh), v_maxval);
00748                     vst1q_f32(dst + j, vreinterpretq_f32_u32(v_dst));
00749                 }
00750 #endif
00751 
00752                 for( ; j < roi.width; j++ )
00753                     dst[j] = src[j] > thresh ? maxval : 0;
00754             }
00755             break;
00756 
00757         case THRESH_BINARY_INV :
00758             for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
00759             {
00760                 j = 0;
00761 #if CV_SSE2
00762                 if( useSIMD )
00763                 {
00764                     __m128 thresh4 = _mm_set1_ps(thresh), maxval4 = _mm_set1_ps(maxval);
00765                     for( ; j <= roi.width - 8; j += 8 )
00766                     {
00767                         __m128 v0, v1;
00768                         v0 = _mm_loadu_ps( src + j );
00769                         v1 = _mm_loadu_ps( src + j + 4 );
00770                         v0 = _mm_cmple_ps( v0, thresh4 );
00771                         v1 = _mm_cmple_ps( v1, thresh4 );
00772                         v0 = _mm_and_ps( v0, maxval4 );
00773                         v1 = _mm_and_ps( v1, maxval4 );
00774                         _mm_storeu_ps( dst + j, v0 );
00775                         _mm_storeu_ps( dst + j + 4, v1 );
00776                     }
00777                 }
00778 #elif CV_NEON
00779                 float32x4_t v_thresh = vdupq_n_f32(thresh);
00780                 uint32x4_t v_maxval = vreinterpretq_u32_f32(vdupq_n_f32(maxval));
00781 
00782                 for( ; j <= roi.width - 4; j += 4 )
00783                 {
00784                     float32x4_t v_src = vld1q_f32(src + j);
00785                     uint32x4_t v_dst = vandq_u32(vcleq_f32(v_src, v_thresh), v_maxval);
00786                     vst1q_f32(dst + j, vreinterpretq_f32_u32(v_dst));
00787                 }
00788 #endif
00789 
00790                 for( ; j < roi.width; j++ )
00791                     dst[j] = src[j] <= thresh ? maxval : 0;
00792             }
00793             break;
00794 
00795         case THRESH_TRUNC :
00796             for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
00797             {
00798                 j = 0;
00799 #if CV_SSE2
00800                 if( useSIMD )
00801                 {
00802                     __m128 thresh4 = _mm_set1_ps(thresh);
00803                     for( ; j <= roi.width - 8; j += 8 )
00804                     {
00805                         __m128 v0, v1;
00806                         v0 = _mm_loadu_ps( src + j );
00807                         v1 = _mm_loadu_ps( src + j + 4 );
00808                         v0 = _mm_min_ps( v0, thresh4 );
00809                         v1 = _mm_min_ps( v1, thresh4 );
00810                         _mm_storeu_ps( dst + j, v0 );
00811                         _mm_storeu_ps( dst + j + 4, v1 );
00812                     }
00813                 }
00814 #elif CV_NEON
00815                 float32x4_t v_thresh = vdupq_n_f32(thresh);
00816 
00817                 for( ; j <= roi.width - 4; j += 4 )
00818                     vst1q_f32(dst + j, vminq_f32(vld1q_f32(src + j), v_thresh));
00819 #endif
00820 
00821                 for( ; j < roi.width; j++ )
00822                     dst[j] = std::min(src[j], thresh);
00823             }
00824             break;
00825 
00826         case THRESH_TOZERO :
00827             for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
00828             {
00829                 j = 0;
00830 #if CV_SSE2
00831                 if( useSIMD )
00832                 {
00833                     __m128 thresh4 = _mm_set1_ps(thresh);
00834                     for( ; j <= roi.width - 8; j += 8 )
00835                     {
00836                         __m128 v0, v1;
00837                         v0 = _mm_loadu_ps( src + j );
00838                         v1 = _mm_loadu_ps( src + j + 4 );
00839                         v0 = _mm_and_ps(v0, _mm_cmpgt_ps(v0, thresh4));
00840                         v1 = _mm_and_ps(v1, _mm_cmpgt_ps(v1, thresh4));
00841                         _mm_storeu_ps( dst + j, v0 );
00842                         _mm_storeu_ps( dst + j + 4, v1 );
00843                     }
00844                 }
00845 #elif CV_NEON
00846                 float32x4_t v_thresh = vdupq_n_f32(thresh);
00847 
00848                 for( ; j <= roi.width - 4; j += 4 )
00849                 {
00850                     float32x4_t v_src = vld1q_f32(src + j);
00851                     uint32x4_t v_dst = vandq_u32(vcgtq_f32(v_src, v_thresh),
00852                                                  vreinterpretq_u32_f32(v_src));
00853                     vst1q_f32(dst + j, vreinterpretq_f32_u32(v_dst));
00854                 }
00855 #endif
00856 
00857                 for( ; j < roi.width; j++ )
00858                 {
00859                     float v = src[j];
00860                     dst[j] = v > thresh ? v : 0;
00861                 }
00862             }
00863             break;
00864 
00865         case THRESH_TOZERO_INV :
00866             for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
00867             {
00868                 j = 0;
00869 #if CV_SSE2
00870                 if( useSIMD )
00871                 {
00872                     __m128 thresh4 = _mm_set1_ps(thresh);
00873                     for( ; j <= roi.width - 8; j += 8 )
00874                     {
00875                         __m128 v0, v1;
00876                         v0 = _mm_loadu_ps( src + j );
00877                         v1 = _mm_loadu_ps( src + j + 4 );
00878                         v0 = _mm_and_ps(v0, _mm_cmple_ps(v0, thresh4));
00879                         v1 = _mm_and_ps(v1, _mm_cmple_ps(v1, thresh4));
00880                         _mm_storeu_ps( dst + j, v0 );
00881                         _mm_storeu_ps( dst + j + 4, v1 );
00882                     }
00883                 }
00884 #elif CV_NEON
00885                 float32x4_t v_thresh = vdupq_n_f32(thresh);
00886 
00887                 for( ; j <= roi.width - 4; j += 4 )
00888                 {
00889                     float32x4_t v_src = vld1q_f32(src + j);
00890                     uint32x4_t v_dst = vandq_u32(vcleq_f32(v_src, v_thresh),
00891                                                  vreinterpretq_u32_f32(v_src));
00892                     vst1q_f32(dst + j, vreinterpretq_f32_u32(v_dst));
00893                 }
00894 #endif
00895                 for( ; j < roi.width; j++ )
00896                 {
00897                     float v = src[j];
00898                     dst[j] = v <= thresh ? v : 0;
00899                 }
00900             }
00901             break;
00902         default:
00903             return CV_Error( CV_StsBadArg, "" );
00904     }
00905 }
00906 
00907 #ifdef HAVE_IPP
00908 static bool ipp_getThreshVal_Otsu_8u( const unsigned char* _src, int step, Size size, unsigned char &thresh)
00909 {
00910 #if IPP_VERSION_X100 >= 810 && !HAVE_ICV
00911     int ippStatus = -1;
00912     IppiSize srcSize = { size.width, size.height };
00913     CV_SUPPRESS_DEPRECATED_START
00914     ippStatus = ippiComputeThreshold_Otsu_8u_C1R(_src, step, srcSize, &thresh);
00915     CV_SUPPRESS_DEPRECATED_END
00916 
00917     if(ippStatus >= 0)
00918         return true;
00919 #else
00920     CV_UNUSED(_src); CV_UNUSED(step); CV_UNUSED(size); CV_UNUSED(thresh);
00921 #endif
00922     return false;
00923 }
00924 #endif
00925 
00926 static double
00927 getThreshVal_Otsu_8u( const Mat& _src )
00928 {
00929     Size size = _src.size();
00930     int step = (int) _src.step;
00931     if( _src.isContinuous() )
00932     {
00933         size.width *= size.height;
00934         size.height = 1;
00935         step = size.width;
00936     }
00937 
00938 #ifdef HAVE_IPP
00939     unsigned char thresh;
00940     CV_IPP_RUN(IPP_VERSION_X100 >= 810 && !HAVE_ICV, ipp_getThreshVal_Otsu_8u(_src.ptr(), step, size, thresh), thresh);
00941 #endif
00942 
00943     const int N = 256;
00944     int i, j, h[N] = {0};
00945     for( i = 0; i < size.height; i++ )
00946     {
00947         const uchar* src = _src.ptr() + step*i;
00948         j = 0;
00949         #if CV_ENABLE_UNROLLED
00950         for( ; j <= size.width - 4; j += 4 )
00951         {
00952             int v0 = src[j], v1 = src[j+1];
00953             h[v0]++; h[v1]++;
00954             v0 = src[j+2]; v1 = src[j+3];
00955             h[v0]++; h[v1]++;
00956         }
00957         #endif
00958         for( ; j < size.width; j++ )
00959             h[src[j]]++;
00960     }
00961 
00962     double mu = 0, scale = 1./(size.width*size.height);
00963     for( i = 0; i < N; i++ )
00964         mu += i*(double)h[i];
00965 
00966     mu *= scale;
00967     double mu1 = 0, q1 = 0;
00968     double max_sigma = 0, max_val = 0;
00969 
00970     for( i = 0; i < N; i++ )
00971     {
00972         double p_i, q2, mu2, sigma;
00973 
00974         p_i = h[i]*scale;
00975         mu1 *= q1;
00976         q1 += p_i;
00977         q2 = 1. - q1;
00978 
00979         if( std::min(q1,q2) < FLT_EPSILON || std::max(q1,q2) > 1. - FLT_EPSILON )
00980             continue;
00981 
00982         mu1 = (mu1 + i*p_i)/q1;
00983         mu2 = (mu - q1*mu1)/q2;
00984         sigma = q1*q2*(mu1 - mu2)*(mu1 - mu2);
00985         if( sigma > max_sigma )
00986         {
00987             max_sigma = sigma;
00988             max_val = i;
00989         }
00990     }
00991 
00992     return max_val;
00993 }
00994 
00995 static double
00996 getThreshVal_Triangle_8u( const Mat& _src )
00997 {
00998     Size size = _src.size();
00999     int step = (int) _src.step;
01000     if( _src.isContinuous() )
01001     {
01002         size.width *= size.height;
01003         size.height = 1;
01004         step = size.width;
01005     }
01006 
01007     const int N = 256;
01008     int i, j, h[N] = {0};
01009     for( i = 0; i < size.height; i++ )
01010     {
01011         const uchar* src = _src.ptr() + step*i;
01012         j = 0;
01013         #if CV_ENABLE_UNROLLED
01014         for( ; j <= size.width - 4; j += 4 )
01015         {
01016             int v0 = src[j], v1 = src[j+1];
01017             h[v0]++; h[v1]++;
01018             v0 = src[j+2]; v1 = src[j+3];
01019             h[v0]++; h[v1]++;
01020         }
01021         #endif
01022         for( ; j < size.width; j++ )
01023             h[src[j]]++;
01024     }
01025 
01026     int left_bound = 0, right_bound = 0, max_ind = 0, max = 0;
01027     int temp;
01028     bool isflipped = false;
01029 
01030     for( i = 0; i < N; i++ )
01031     {
01032         if( h[i] > 0 )
01033         {
01034             left_bound = i;
01035             break;
01036         }
01037     }
01038     if( left_bound > 0 )
01039         left_bound--;
01040 
01041     for( i = N-1; i > 0; i-- )
01042     {
01043         if( h[i] > 0 )
01044         {
01045             right_bound = i;
01046             break;
01047         }
01048     }
01049     if( right_bound < N-1 )
01050         right_bound++;
01051 
01052     for( i = 0; i < N; i++ )
01053     {
01054         if( h[i] > max)
01055         {
01056             max = h[i];
01057             max_ind = i;
01058         }
01059     }
01060 
01061     if( max_ind-left_bound < right_bound-max_ind)
01062     {
01063         isflipped = true;
01064         i = 0, j = N-1;
01065         while( i < j )
01066         {
01067             temp = h[i]; h[i] = h[j]; h[j] = temp;
01068             i++; j--;
01069         }
01070         left_bound = N-1-right_bound;
01071         max_ind = N-1-max_ind;
01072     }
01073 
01074     double thresh = left_bound;
01075     double a, b, dist = 0, tempdist;
01076 
01077     /*
01078      * We do not need to compute precise distance here. Distance is maximized, so some constants can
01079      * be omitted. This speeds up a computation a bit.
01080      */
01081     a = max; b = left_bound-max_ind;
01082     for( i = left_bound+1; i <= max_ind; i++ )
01083     {
01084         tempdist = a*i + b*h[i];
01085         if( tempdist > dist)
01086         {
01087             dist = tempdist;
01088             thresh = i;
01089         }
01090     }
01091     thresh--;
01092 
01093     if( isflipped )
01094         thresh = N-1-thresh;
01095 
01096     return thresh;
01097 }
01098 
01099 class ThresholdRunner : public ParallelLoopBody
01100 {
01101 public:
01102     ThresholdRunner(Mat _src, Mat _dst, double _thresh, double _maxval, int _thresholdType)
01103     {
01104         src = _src;
01105         dst = _dst;
01106 
01107         thresh = _thresh;
01108         maxval = _maxval;
01109         thresholdType = _thresholdType;
01110     }
01111 
01112     void operator () ( const Range& range ) const
01113     {
01114         int row0 = range.start;
01115         int row1 = range.end;
01116 
01117         Mat srcStripe = src.rowRange(row0, row1);
01118         Mat dstStripe = dst.rowRange(row0, row1);
01119 
01120         if (srcStripe.depth() == CV_8U)
01121         {
01122             thresh_8u( srcStripe, dstStripe, (uchar)thresh, (uchar)maxval, thresholdType );
01123         }
01124         else if( srcStripe.depth() == CV_16S )
01125         {
01126             thresh_16s( srcStripe, dstStripe, (short)thresh, (short)maxval, thresholdType );
01127         }
01128         else if( srcStripe.depth() == CV_32F )
01129         {
01130             thresh_32f( srcStripe, dstStripe, (float)thresh, (float)maxval, thresholdType );
01131         }
01132     }
01133 
01134 private:
01135     Mat src;
01136     Mat dst;
01137 
01138     double thresh;
01139     double maxval;
01140     int thresholdType;
01141 };
01142 
01143 #ifdef HAVE_OPENCL
01144 
01145 static bool ocl_threshold( InputArray _src, OutputArray _dst, double & thresh, double maxval, int thresh_type )
01146 {
01147     int type = _src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type),
01148         kercn = ocl::predictOptimalVectorWidth(_src, _dst), ktype = CV_MAKE_TYPE(depth, kercn);
01149     bool doubleSupport = ocl::Device::getDefault().doubleFPConfig() > 0;
01150 
01151     if ( !(thresh_type == THRESH_BINARY  || thresh_type == THRESH_BINARY_INV  || thresh_type == THRESH_TRUNC  ||
01152            thresh_type == THRESH_TOZERO  || thresh_type == THRESH_TOZERO_INV ) ||
01153          (!doubleSupport && depth == CV_64F))
01154         return false;
01155 
01156     const char * const thresholdMap[] = { "THRESH_BINARY", "THRESH_BINARY_INV", "THRESH_TRUNC",
01157                                           "THRESH_TOZERO", "THRESH_TOZERO_INV" };
01158     ocl::Device dev = ocl::Device::getDefault();
01159     int stride_size = dev.isIntel() && (dev.type() & ocl::Device::TYPE_GPU) ? 4 : 1;
01160 
01161     ocl::Kernel k("threshold", ocl::imgproc::threshold_oclsrc,
01162                   format("-D %s -D T=%s -D T1=%s -D STRIDE_SIZE=%d%s", thresholdMap[thresh_type],
01163                          ocl::typeToStr(ktype), ocl::typeToStr(depth), stride_size,
01164                          doubleSupport ? " -D DOUBLE_SUPPORT" : ""));
01165     if (k.empty())
01166         return false;
01167 
01168     UMat src = _src.getUMat();
01169     _dst.create(src.size(), type);
01170     UMat dst = _dst.getUMat();
01171 
01172     if (depth <= CV_32S)
01173         thresh = cvFloor(thresh);
01174 
01175     const double min_vals[] = { 0, CHAR_MIN, 0, SHRT_MIN, INT_MIN, -FLT_MAX, -DBL_MAX, 0 };
01176     double min_val = min_vals[depth];
01177 
01178     k.args(ocl::KernelArg::ReadOnlyNoSize(src), ocl::KernelArg::WriteOnly(dst, cn, kercn),
01179            ocl::KernelArg::Constant(Mat(1, 1, depth, Scalar::all(thresh))),
01180            ocl::KernelArg::Constant(Mat(1, 1, depth, Scalar::all(maxval))),
01181            ocl::KernelArg::Constant(Mat(1, 1, depth, Scalar::all(min_val))));
01182 
01183     size_t globalsize[2] = { (size_t)dst.cols * cn / kercn, (size_t)dst.rows };
01184     globalsize[1] = (globalsize[1] + stride_size - 1) / stride_size;
01185     return k.run(2, globalsize, NULL, false);
01186 }
01187 
01188 #endif
01189 
01190 }
01191 
01192 double cv::threshold( InputArray _src, OutputArray _dst, double thresh, double maxval, int type )
01193 {
01194 #ifdef HAVE_OPENCL
01195     CV_OCL_RUN_(_src.dims() <= 2 && _dst.isUMat(),
01196                 ocl_threshold(_src, _dst, thresh, maxval, type), thresh)
01197 #endif
01198 
01199     Mat src = _src.getMat();
01200     int automatic_thresh = (type & ~CV_THRESH_MASK);
01201     type &= THRESH_MASK;
01202 
01203     CV_Assert( automatic_thresh != (CV_THRESH_OTSU | CV_THRESH_TRIANGLE) );
01204     if( automatic_thresh == CV_THRESH_OTSU )
01205     {
01206         CV_Assert( src.type() == CV_8UC1 );
01207         thresh = getThreshVal_Otsu_8u( src );
01208     }
01209     else if( automatic_thresh == CV_THRESH_TRIANGLE )
01210     {
01211         CV_Assert( src.type() == CV_8UC1 );
01212         thresh = getThreshVal_Triangle_8u( src );
01213     }
01214 
01215     _dst.create( src.size(), src.type() );
01216     Mat dst = _dst.getMat();
01217 
01218     if( src.depth() == CV_8U )
01219     {
01220         int ithresh = cvFloor(thresh);
01221         thresh = ithresh;
01222         int imaxval = cvRound(maxval);
01223         if( type == THRESH_TRUNC  )
01224             imaxval = ithresh;
01225         imaxval = saturate_cast<uchar>(imaxval);
01226 
01227         if( ithresh < 0 || ithresh >= 255 )
01228         {
01229             if( type == THRESH_BINARY  || type == THRESH_BINARY_INV  ||
01230                 ((type == THRESH_TRUNC  || type == THRESH_TOZERO_INV ) && ithresh < 0) ||
01231                 (type == THRESH_TOZERO  && ithresh >= 255) )
01232             {
01233                 int v = type == THRESH_BINARY  ? (ithresh >= 255 ? 0 : imaxval) :
01234                         type == THRESH_BINARY_INV  ? (ithresh >= 255 ? imaxval : 0) :
01235                         /*type == THRESH_TRUNC ? imaxval :*/ 0;
01236                 dst.setTo(v);
01237             }
01238             else
01239                 src.copyTo(dst);
01240             return thresh;
01241         }
01242         thresh = ithresh;
01243         maxval = imaxval;
01244     }
01245     else if( src.depth() == CV_16S )
01246     {
01247         int ithresh = cvFloor(thresh);
01248         thresh = ithresh;
01249         int imaxval = cvRound(maxval);
01250         if( type == THRESH_TRUNC  )
01251             imaxval = ithresh;
01252         imaxval = saturate_cast<short>(imaxval);
01253 
01254         if( ithresh < SHRT_MIN || ithresh >= SHRT_MAX )
01255         {
01256             if( type == THRESH_BINARY  || type == THRESH_BINARY_INV  ||
01257                ((type == THRESH_TRUNC  || type == THRESH_TOZERO_INV ) && ithresh < SHRT_MIN) ||
01258                (type == THRESH_TOZERO  && ithresh >= SHRT_MAX) )
01259             {
01260                 int v = type == THRESH_BINARY  ? (ithresh >= SHRT_MAX ? 0 : imaxval) :
01261                 type == THRESH_BINARY_INV  ? (ithresh >= SHRT_MAX ? imaxval : 0) :
01262                 /*type == THRESH_TRUNC ? imaxval :*/ 0;
01263                 dst.setTo(v);
01264             }
01265             else
01266                 src.copyTo(dst);
01267             return thresh;
01268         }
01269         thresh = ithresh;
01270         maxval = imaxval;
01271     }
01272     else if( src.depth() == CV_32F )
01273         ;
01274     else
01275         CV_Error( CV_StsUnsupportedFormat, "" );
01276 
01277     parallel_for_(Range(0, dst.rows),
01278                   ThresholdRunner(src, dst, thresh, maxval, type),
01279                   dst.total()/(double)(1<<16));
01280     return thresh;
01281 }
01282 
01283 
01284 void cv::adaptiveThreshold( InputArray _src, OutputArray _dst, double maxValue,
01285                             int method, int type, int blockSize, double delta )
01286 {
01287     Mat src = _src.getMat();
01288     CV_Assert( src.type() == CV_8UC1 );
01289     CV_Assert( blockSize % 2 == 1 && blockSize > 1 );
01290     Size size = src.size();
01291 
01292     _dst.create( size, src.type() );
01293     Mat dst = _dst.getMat();
01294 
01295     if( maxValue < 0 )
01296     {
01297         dst = Scalar (0);
01298         return;
01299     }
01300 
01301     Mat mean;
01302 
01303     if( src.data != dst.data )
01304         mean = dst;
01305 
01306     if (method == ADAPTIVE_THRESH_MEAN_C)
01307         boxFilter( src, mean, src.type(), Size(blockSize, blockSize),
01308                    Point(-1,-1), true, BORDER_REPLICATE );
01309     else if (method == ADAPTIVE_THRESH_GAUSSIAN_C)
01310     {
01311         Mat srcfloat,meanfloat;
01312         src.convertTo(srcfloat,CV_32F);
01313         meanfloat=srcfloat;
01314         GaussianBlur(srcfloat, meanfloat, Size(blockSize, blockSize), 0, 0, BORDER_REPLICATE);
01315         meanfloat.convertTo(mean, src.type());
01316     }
01317     else
01318         CV_Error( CV_StsBadFlag, "Unknown/unsupported adaptive threshold method" );
01319 
01320     int i, j;
01321     uchar imaxval = saturate_cast<uchar>(maxValue);
01322     int idelta = type == THRESH_BINARY  ? cvCeil(delta) : cvFloor(delta);
01323     uchar tab[768];
01324 
01325     if( type == CV_THRESH_BINARY )
01326         for( i = 0; i < 768; i++ )
01327             tab[i] = (uchar)(i - 255 > -idelta ? imaxval : 0);
01328     else if( type == CV_THRESH_BINARY_INV )
01329         for( i = 0; i < 768; i++ )
01330             tab[i] = (uchar)(i - 255 <= -idelta ? imaxval : 0);
01331     else
01332         CV_Error( CV_StsBadFlag, "Unknown/unsupported threshold type" );
01333 
01334     if( src.isContinuous() && mean.isContinuous() && dst.isContinuous() )
01335     {
01336         size.width *= size.height;
01337         size.height = 1;
01338     }
01339 
01340     for( i = 0; i < size.height; i++ )
01341     {
01342         const uchar* sdata = src.ptr(i);
01343         const uchar* mdata = mean.ptr(i);
01344         uchar* ddata = dst.ptr(i);
01345 
01346         for( j = 0; j < size.width; j++ )
01347             ddata[j] = tab[sdata[j] - mdata[j] + 255];
01348     }
01349 }
01350 
01351 CV_IMPL double
01352 cvThreshold( const void* srcarr, void* dstarr, double thresh, double maxval, int type )
01353 {
01354     cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr), dst0 = dst;
01355 
01356     CV_Assert( src.size == dst.size && src.channels() == dst.channels() &&
01357         (src.depth() == dst.depth() || dst.depth() == CV_8U));
01358 
01359     thresh = cv::threshold( src, dst, thresh, maxval, type );
01360     if( dst0.data != dst.data )
01361         dst.convertTo( dst0, dst0.depth() );
01362     return thresh;
01363 }
01364 
01365 
01366 CV_IMPL void
01367 cvAdaptiveThreshold( const void *srcIm, void *dstIm, double maxValue,
01368                      int method, int type, int blockSize, double delta )
01369 {
01370     cv::Mat src = cv::cvarrToMat(srcIm), dst = cv::cvarrToMat(dstIm);
01371     CV_Assert( src.size == dst.size && src.type() == dst.type() );
01372     cv::adaptiveThreshold( src, dst, maxValue, method, type, blockSize, delta );
01373 }
01374 
01375 /* End of file. */
01376