| /*M/////////////////////////////////////////////////////////////////////////////////////// |
| // |
| // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. |
| // |
| // By downloading, copying, installing or using the software you agree to this license. |
| // If you do not agree to this license, do not download, install, |
| // copy or use the software. |
| // |
| // |
| // Intel License Agreement |
| // For Open Source Computer Vision Library |
| // |
| // Copyright (C) 2000, Intel Corporation, all rights reserved. |
| // Third party copyrights are property of their respective owners. |
| // |
| // Redistribution and use in source and binary forms, with or without modification, |
| // are permitted provided that the following conditions are met: |
| // |
| // * Redistribution's of source code must retain the above copyright notice, |
| // this list of conditions and the following disclaimer. |
| // |
| // * Redistribution's in binary form must reproduce the above copyright notice, |
| // this list of conditions and the following disclaimer in the documentation |
| // and/or other materials provided with the distribution. |
| // |
| // * The name of Intel Corporation may not be used to endorse or promote products |
| // derived from this software without specific prior written permission. |
| // |
| // This software is provided by the copyright holders and contributors "as is" and |
| // any express or implied warranties, including, but not limited to, the implied |
| // warranties of merchantability and fitness for a particular purpose are disclaimed. |
| // In no event shall the Intel Corporation or contributors be liable for any direct, |
| // indirect, incidental, special, exemplary, or consequential damages |
| // (including, but not limited to, procurement of substitute goods or services; |
| // loss of use, data, or profits; or business interruption) however caused |
| // and on any theory of liability, whether in contract, strict liability, |
| // or tort (including negligence or otherwise) arising in any way out of |
| // the use of this software, even if advised of the possibility of such damage. |
| // |
| //M*/ |
| |
| #include "_cv.h" |
| |
| static CvStatus CV_STDCALL |
| icvThresh_8u_C1R( const uchar* src, int src_step, uchar* dst, int dst_step, |
| CvSize roi, uchar thresh, uchar maxval, int type ) |
| { |
| int i, j; |
| uchar tab[256]; |
| |
| switch( type ) |
| { |
| case CV_THRESH_BINARY: |
| for( i = 0; i <= thresh; i++ ) |
| tab[i] = 0; |
| for( ; i < 256; i++ ) |
| tab[i] = maxval; |
| break; |
| case CV_THRESH_BINARY_INV: |
| for( i = 0; i <= thresh; i++ ) |
| tab[i] = maxval; |
| for( ; i < 256; i++ ) |
| tab[i] = 0; |
| break; |
| case CV_THRESH_TRUNC: |
| for( i = 0; i <= thresh; i++ ) |
| tab[i] = (uchar)i; |
| for( ; i < 256; i++ ) |
| tab[i] = thresh; |
| break; |
| case CV_THRESH_TOZERO: |
| for( i = 0; i <= thresh; i++ ) |
| tab[i] = 0; |
| for( ; i < 256; i++ ) |
| tab[i] = (uchar)i; |
| break; |
| case CV_THRESH_TOZERO_INV: |
| for( i = 0; i <= thresh; i++ ) |
| tab[i] = (uchar)i; |
| for( ; i < 256; i++ ) |
| tab[i] = 0; |
| break; |
| default: |
| return CV_BADFLAG_ERR; |
| } |
| |
| for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step ) |
| { |
| for( j = 0; j <= roi.width - 4; j += 4 ) |
| { |
| uchar t0 = tab[src[j]]; |
| uchar t1 = tab[src[j+1]]; |
| |
| dst[j] = t0; |
| dst[j+1] = t1; |
| |
| t0 = tab[src[j+2]]; |
| t1 = tab[src[j+3]]; |
| |
| dst[j+2] = t0; |
| dst[j+3] = t1; |
| } |
| |
| for( ; j < roi.width; j++ ) |
| dst[j] = tab[src[j]]; |
| } |
| |
| return CV_NO_ERR; |
| } |
| |
| |
| static CvStatus CV_STDCALL |
| icvThresh_32f_C1R( const float *src, int src_step, float *dst, int dst_step, |
| CvSize roi, float thresh, float maxval, int type ) |
| { |
| int i, j; |
| const int* isrc = (const int*)src; |
| int* idst = (int*)dst; |
| Cv32suf v; |
| int iThresh, iMax; |
| |
| v.f = thresh; iThresh = CV_TOGGLE_FLT(v.i); |
| v.f = maxval; iMax = v.i; |
| |
| src_step /= sizeof(src[0]); |
| dst_step /= sizeof(dst[0]); |
| |
| switch( type ) |
| { |
| case CV_THRESH_BINARY: |
| for( i = 0; i < roi.height; i++, isrc += src_step, idst += dst_step ) |
| { |
| for( j = 0; j < roi.width; j++ ) |
| { |
| int temp = isrc[j]; |
| idst[j] = ((CV_TOGGLE_FLT(temp) <= iThresh) - 1) & iMax; |
| } |
| } |
| break; |
| |
| case CV_THRESH_BINARY_INV: |
| for( i = 0; i < roi.height; i++, isrc += src_step, idst += dst_step ) |
| { |
| for( j = 0; j < roi.width; j++ ) |
| { |
| int temp = isrc[j]; |
| idst[j] = ((CV_TOGGLE_FLT(temp) > iThresh) - 1) & iMax; |
| } |
| } |
| break; |
| |
| case CV_THRESH_TRUNC: |
| for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step ) |
| { |
| for( j = 0; j < roi.width; j++ ) |
| { |
| float temp = src[j]; |
| |
| if( temp > thresh ) |
| temp = thresh; |
| dst[j] = temp; |
| } |
| } |
| break; |
| |
| case CV_THRESH_TOZERO: |
| for( i = 0; i < roi.height; i++, isrc += src_step, idst += dst_step ) |
| { |
| for( j = 0; j < roi.width; j++ ) |
| { |
| int temp = isrc[j]; |
| idst[j] = ((CV_TOGGLE_FLT( temp ) <= iThresh) - 1) & temp; |
| } |
| } |
| break; |
| |
| case CV_THRESH_TOZERO_INV: |
| for( i = 0; i < roi.height; i++, isrc += src_step, idst += dst_step ) |
| { |
| for( j = 0; j < roi.width; j++ ) |
| { |
| int temp = isrc[j]; |
| idst[j] = ((CV_TOGGLE_FLT( temp ) > iThresh) - 1) & temp; |
| } |
| } |
| break; |
| |
| default: |
| return CV_BADFLAG_ERR; |
| } |
| |
| return CV_OK; |
| } |
| |
| |
| static double |
| icvGetThreshVal_Otsu( const CvHistogram* hist ) |
| { |
| double max_val = 0; |
| |
| CV_FUNCNAME( "icvGetThreshVal_Otsu" ); |
| |
| __BEGIN__; |
| |
| int i, count; |
| const float* h; |
| double sum = 0, mu = 0; |
| bool uniform = false; |
| double low = 0, high = 0, delta = 0; |
| float* nu_thresh = 0; |
| double mu1 = 0, q1 = 0; |
| double max_sigma = 0; |
| |
| if( !CV_IS_HIST(hist) || CV_IS_SPARSE_HIST(hist) || hist->mat.dims != 1 ) |
| CV_ERROR( CV_StsBadArg, |
| "The histogram in Otsu method must be a valid dense 1D histogram" ); |
| |
| count = hist->mat.dim[0].size; |
| h = (float*)cvPtr1D( hist->bins, 0 ); |
| |
| if( !CV_HIST_HAS_RANGES(hist) || CV_IS_UNIFORM_HIST(hist) ) |
| { |
| if( CV_HIST_HAS_RANGES(hist) ) |
| { |
| low = hist->thresh[0][0]; |
| high = hist->thresh[0][1]; |
| } |
| else |
| { |
| low = 0; |
| high = count; |
| } |
| |
| delta = (high-low)/count; |
| low += delta*0.5; |
| uniform = true; |
| } |
| else |
| nu_thresh = hist->thresh2[0]; |
| |
| for( i = 0; i < count; i++ ) |
| { |
| sum += h[i]; |
| if( uniform ) |
| mu += (i*delta + low)*h[i]; |
| else |
| mu += (nu_thresh[i*2] + nu_thresh[i*2+1])*0.5*h[i]; |
| } |
| |
| sum = fabs(sum) > FLT_EPSILON ? 1./sum : 0; |
| mu *= sum; |
| |
| mu1 = 0; |
| q1 = 0; |
| |
| for( i = 0; i < count; i++ ) |
| { |
| double p_i, q2, mu2, val_i, sigma; |
| |
| p_i = h[i]*sum; |
| mu1 *= q1; |
| q1 += p_i; |
| q2 = 1. - q1; |
| |
| if( MIN(q1,q2) < FLT_EPSILON || MAX(q1,q2) > 1. - FLT_EPSILON ) |
| continue; |
| |
| if( uniform ) |
| val_i = i*delta + low; |
| else |
| val_i = (nu_thresh[i*2] + nu_thresh[i*2+1])*0.5; |
| |
| mu1 = (mu1 + val_i*p_i)/q1; |
| mu2 = (mu - q1*mu1)/q2; |
| sigma = q1*q2*(mu1 - mu2)*(mu1 - mu2); |
| if( sigma > max_sigma ) |
| { |
| max_sigma = sigma; |
| max_val = val_i; |
| } |
| } |
| |
| __END__; |
| |
| return max_val; |
| } |
| |
| |
| icvAndC_8u_C1R_t icvAndC_8u_C1R_p = 0; |
| icvCompareC_8u_C1R_cv_t icvCompareC_8u_C1R_cv_p = 0; |
| icvThreshold_GTVal_8u_C1R_t icvThreshold_GTVal_8u_C1R_p = 0; |
| icvThreshold_GTVal_32f_C1R_t icvThreshold_GTVal_32f_C1R_p = 0; |
| icvThreshold_LTVal_8u_C1R_t icvThreshold_LTVal_8u_C1R_p = 0; |
| icvThreshold_LTVal_32f_C1R_t icvThreshold_LTVal_32f_C1R_p = 0; |
| |
| CV_IMPL double |
| cvThreshold( const void* srcarr, void* dstarr, double thresh, double maxval, int type ) |
| { |
| CvHistogram* hist = 0; |
| |
| CV_FUNCNAME( "cvThreshold" ); |
| |
| __BEGIN__; |
| |
| CvSize roi; |
| int src_step, dst_step; |
| CvMat src_stub, *src = (CvMat*)srcarr; |
| CvMat dst_stub, *dst = (CvMat*)dstarr; |
| CvMat src0, dst0; |
| int coi1 = 0, coi2 = 0; |
| int ithresh, imaxval, cn; |
| bool use_otsu; |
| |
| CV_CALL( src = cvGetMat( src, &src_stub, &coi1 )); |
| CV_CALL( dst = cvGetMat( dst, &dst_stub, &coi2 )); |
| |
| if( coi1 + coi2 ) |
| CV_ERROR( CV_BadCOI, "COI is not supported by the function" ); |
| |
| if( !CV_ARE_CNS_EQ( src, dst ) ) |
| CV_ERROR( CV_StsUnmatchedFormats, "Both arrays must have equal number of channels" ); |
| |
| cn = CV_MAT_CN(src->type); |
| if( cn > 1 ) |
| { |
| src = cvReshape( src, &src0, 1 ); |
| dst = cvReshape( dst, &dst0, 1 ); |
| } |
| |
| use_otsu = (type & ~CV_THRESH_MASK) == CV_THRESH_OTSU; |
| type &= CV_THRESH_MASK; |
| |
| if( use_otsu ) |
| { |
| float _ranges[] = { 0, 256 }; |
| float* ranges = _ranges; |
| int hist_size = 256; |
| void* srcarr0 = src; |
| |
| if( CV_MAT_TYPE(src->type) != CV_8UC1 ) |
| CV_ERROR( CV_StsNotImplemented, "Otsu method can only be used with 8uC1 images" ); |
| |
| CV_CALL( hist = cvCreateHist( 1, &hist_size, CV_HIST_ARRAY, &ranges )); |
| cvCalcArrHist( &srcarr0, hist ); |
| thresh = cvFloor(icvGetThreshVal_Otsu( hist )); |
| } |
| |
| if( !CV_ARE_DEPTHS_EQ( src, dst ) ) |
| { |
| if( CV_MAT_TYPE(dst->type) != CV_8UC1 ) |
| CV_ERROR( CV_StsUnsupportedFormat, "In case of different types destination should be 8uC1" ); |
| |
| if( type != CV_THRESH_BINARY && type != CV_THRESH_BINARY_INV ) |
| CV_ERROR( CV_StsBadArg, |
| "In case of different types only CV_THRESH_BINARY " |
| "and CV_THRESH_BINARY_INV thresholding types are supported" ); |
| |
| if( maxval < 0 ) |
| { |
| CV_CALL( cvSetZero( dst )); |
| } |
| else |
| { |
| CV_CALL( cvCmpS( src, thresh, dst, type == CV_THRESH_BINARY ? CV_CMP_GT : CV_CMP_LE )); |
| if( maxval < 255 ) |
| CV_CALL( cvAndS( dst, cvScalarAll( maxval ), dst )); |
| } |
| EXIT; |
| } |
| |
| if( !CV_ARE_SIZES_EQ( src, dst ) ) |
| CV_ERROR( CV_StsUnmatchedSizes, "" ); |
| |
| roi = cvGetMatSize( src ); |
| if( CV_IS_MAT_CONT( src->type & dst->type )) |
| { |
| roi.width *= roi.height; |
| roi.height = 1; |
| src_step = dst_step = CV_STUB_STEP; |
| } |
| else |
| { |
| src_step = src->step; |
| dst_step = dst->step; |
| } |
| |
| switch( CV_MAT_DEPTH(src->type) ) |
| { |
| case CV_8U: |
| |
| ithresh = cvFloor(thresh); |
| imaxval = cvRound(maxval); |
| if( type == CV_THRESH_TRUNC ) |
| imaxval = ithresh; |
| imaxval = CV_CAST_8U(imaxval); |
| |
| if( ithresh < 0 || ithresh >= 255 ) |
| { |
| if( type == CV_THRESH_BINARY || type == CV_THRESH_BINARY_INV || |
| ((type == CV_THRESH_TRUNC || type == CV_THRESH_TOZERO_INV) && ithresh < 0) || |
| (type == CV_THRESH_TOZERO && ithresh >= 255) ) |
| { |
| int v = type == CV_THRESH_BINARY ? (ithresh >= 255 ? 0 : imaxval) : |
| type == CV_THRESH_BINARY_INV ? (ithresh >= 255 ? imaxval : 0) : |
| type == CV_THRESH_TRUNC ? imaxval : 0; |
| |
| cvSet( dst, cvScalarAll(v) ); |
| EXIT; |
| } |
| else |
| { |
| cvCopy( src, dst ); |
| EXIT; |
| } |
| } |
| |
| if( type == CV_THRESH_BINARY || type == CV_THRESH_BINARY_INV ) |
| { |
| if( icvCompareC_8u_C1R_cv_p && icvAndC_8u_C1R_p ) |
| { |
| IPPI_CALL( icvCompareC_8u_C1R_cv_p( src->data.ptr, src_step, |
| (uchar)ithresh, dst->data.ptr, dst_step, roi, |
| type == CV_THRESH_BINARY ? cvCmpGreater : cvCmpLessEq )); |
| |
| if( imaxval < 255 ) |
| IPPI_CALL( icvAndC_8u_C1R_p( dst->data.ptr, dst_step, |
| (uchar)imaxval, dst->data.ptr, dst_step, roi )); |
| EXIT; |
| } |
| } |
| else if( type == CV_THRESH_TRUNC || type == CV_THRESH_TOZERO_INV ) |
| { |
| if( icvThreshold_GTVal_8u_C1R_p ) |
| { |
| IPPI_CALL( icvThreshold_GTVal_8u_C1R_p( src->data.ptr, src_step, |
| dst->data.ptr, dst_step, roi, (uchar)ithresh, |
| (uchar)(type == CV_THRESH_TRUNC ? ithresh : 0) )); |
| EXIT; |
| } |
| } |
| else |
| { |
| assert( type == CV_THRESH_TOZERO ); |
| if( icvThreshold_LTVal_8u_C1R_p ) |
| { |
| ithresh = cvFloor(thresh+1.); |
| ithresh = CV_CAST_8U(ithresh); |
| IPPI_CALL( icvThreshold_LTVal_8u_C1R_p( src->data.ptr, src_step, |
| dst->data.ptr, dst_step, roi, (uchar)ithresh, 0 )); |
| EXIT; |
| } |
| } |
| |
| icvThresh_8u_C1R( src->data.ptr, src_step, |
| dst->data.ptr, dst_step, roi, |
| (uchar)ithresh, (uchar)imaxval, type ); |
| break; |
| case CV_32F: |
| |
| if( type == CV_THRESH_TRUNC || type == CV_THRESH_TOZERO_INV ) |
| { |
| if( icvThreshold_GTVal_32f_C1R_p ) |
| { |
| IPPI_CALL( icvThreshold_GTVal_32f_C1R_p( src->data.fl, src_step, |
| dst->data.fl, dst_step, roi, (float)thresh, |
| type == CV_THRESH_TRUNC ? (float)thresh : 0 )); |
| EXIT; |
| } |
| } |
| else if( type == CV_THRESH_TOZERO ) |
| { |
| if( icvThreshold_LTVal_32f_C1R_p ) |
| { |
| IPPI_CALL( icvThreshold_LTVal_32f_C1R_p( src->data.fl, src_step, |
| dst->data.fl, dst_step, roi, (float)(thresh*(1 + FLT_EPSILON)), 0 )); |
| EXIT; |
| } |
| } |
| |
| icvThresh_32f_C1R( src->data.fl, src_step, dst->data.fl, dst_step, roi, |
| (float)thresh, (float)maxval, type ); |
| break; |
| default: |
| CV_ERROR( CV_BadDepth, cvUnsupportedFormat ); |
| } |
| |
| __END__; |
| |
| if( hist ) |
| cvReleaseHist( &hist ); |
| |
| return thresh; |
| } |
| |
| /* End of file. */ |