Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of gr-peach-opencv-project by
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
Generated on Tue Jul 12 2022 15:17:31 by
1.7.2
