【图像算法】七种常见阈值分割代码(Otsu、最大熵、迭代法、自适应阀值、手动、迭代法、基本全局阈值法)

图像算法:图像阈值分割

SkySeraph Dec 21st 2010  HQU

Email:zgzhaobo@gmail.com    QQ:452728574

Latest Modified Date:Dec.21st 2010 HQU

一、工具:VC+OpenCV

二、语言:C++

三、原理(略)

四、程序

主程序(核心部分) 

复制代码
代码
1   /* ===============================图像分割===================================== */
2   /* --------------------------------------------------------------------------- */
3   /* 手动设置阀值 */
4   IplImage *  binaryImg  =  cvCreateImage(cvSize(w, h),IPL_DEPTH_8U,  1 );
5   cvThreshold(smoothImgGauss,binaryImg, 71 , 255 ,CV_THRESH_BINARY); 
6   cvNamedWindow( " cvThreshold " , CV_WINDOW_AUTOSIZE );
7   cvShowImage(  " cvThreshold " , binaryImg );
8   // cvReleaseImage(&binaryImg); 
9     /* --------------------------------------------------------------------------- */
10   /* 自适应阀值 //计算像域邻域的平均灰度,来决定二值化的值 */
11   IplImage *  adThresImg  =  cvCreateImage(cvSize(w, h),IPL_DEPTH_8U,  1 );
12   double  max_value = 255 ;
13   int  adpative_method = CV_ADAPTIVE_THRESH_GAUSSIAN_C; // CV_ADAPTIVE_THRESH_MEAN_C
14     int  threshold_type = CV_THRESH_BINARY;
15   int  block_size = 3 ; // 阈值的象素邻域大小
16     int  offset = 5 ; // 窗口尺寸
17      cvAdaptiveThreshold(smoothImgGauss,adThresImg,max_value,adpative_method,threshold_type,block_size,offset);
18   cvNamedWindow( " cvAdaptiveThreshold " , CV_WINDOW_AUTOSIZE );
19   cvShowImage(  " cvAdaptiveThreshold " , adThresImg );
20   cvReleaseImage( & adThresImg);
21   /* --------------------------------------------------------------------------- */
22   /* 最大熵阀值分割法 */  
23   IplImage *  imgMaxEntropy  =  cvCreateImage(cvGetSize(imgGrey),IPL_DEPTH_8U, 1 );
24   MaxEntropy(smoothImgGauss,imgMaxEntropy);
25   cvNamedWindow( " MaxEntroyThreshold " , CV_WINDOW_AUTOSIZE );
26   cvShowImage(  " MaxEntroyThreshold " , imgMaxEntropy ); // 显示图像
27      cvReleaseImage( & imgMaxEntropy ); 
28   /* --------------------------------------------------------------------------- */
29   /* 基本全局阀值法 */
30   IplImage *  imgBasicGlobalThreshold  =  cvCreateImage(cvGetSize(imgGrey),IPL_DEPTH_8U, 1 );
31   cvCopyImage(srcImgGrey,imgBasicGlobalThreshold);
32   int  pg[ 256 ],i,thre; 
33   for  (i = 0 ;i < 256 ;i ++ ) pg[i] = 0 ;
34   for  (i = 0 ;i < imgBasicGlobalThreshold -> imageSize;i ++ //  直方图统计
35      pg[(BYTE)imgBasicGlobalThreshold -> imageData[i]] ++
36   thre  =  BasicGlobalThreshold(pg, 0 , 256 );  //  确定阈值
37      cout << " The Threshold of this Image in BasicGlobalThreshold is: " << thre << endl; // 输出显示阀值
38      cvThreshold(imgBasicGlobalThreshold,imgBasicGlobalThreshold,thre, 255 ,CV_THRESH_BINARY);  //  二值化 
39      cvNamedWindow( " BasicGlobalThreshold " , CV_WINDOW_AUTOSIZE );
40   cvShowImage(  " BasicGlobalThreshold " , imgBasicGlobalThreshold); // 显示图像
41      cvReleaseImage( & imgBasicGlobalThreshold);
42   /* --------------------------------------------------------------------------- */
43   /* OTSU */
44   IplImage *  imgOtsu  =  cvCreateImage(cvGetSize(imgGrey),IPL_DEPTH_8U, 1 );
45   cvCopyImage(srcImgGrey,imgOtsu);
46   int  thre2;
47   thre2  =  otsu2(imgOtsu);
48   cout << " The Threshold of this Image in Otsu is: " << thre2 << endl; // 输出显示阀值
49   cvThreshold(imgOtsu,imgOtsu,thre2, 255 ,CV_THRESH_BINARY);  //  二值化 
50   cvNamedWindow( " imgOtsu " , CV_WINDOW_AUTOSIZE );
51   cvShowImage(  " imgOtsu " , imgOtsu); // 显示图像 
52   cvReleaseImage( & imgOtsu);
53   /* --------------------------------------------------------------------------- */
54   /* 上下阀值法:利用正态分布求可信区间 */
55   IplImage *  imgTopDown  =  cvCreateImage( cvGetSize(imgGrey), IPL_DEPTH_8U,  1  );
56   cvCopyImage(srcImgGrey,imgTopDown);
57   CvScalar mean ,std_dev; // 平均值、 标准差
58   double  u_threshold,d_threshold;
59   cvAvgSdv(imgTopDown, & mean, & std_dev,NULL); 
60   u_threshold  =  mean.val[ 0 + 2.5 *  std_dev.val[ 0 ]; // 上阀值
61   d_threshold  =  mean.val[ 0 - 2.5 *  std_dev.val[ 0 ]; // 下阀值
62   // u_threshold = mean + 2.5 * std_dev;  // 错误
63   // d_threshold = mean - 2.5 * std_dev;
64   cout << " The TopThreshold of this Image in TopDown is: " << d_threshold << endl; // 输出显示阀值
65   cout << " The DownThreshold of this Image in TopDown is: " << u_threshold << endl;
66   cvThreshold(imgTopDown,imgTopDown,d_threshold,u_threshold,CV_THRESH_BINARY_INV); // 上下阀值
67   cvNamedWindow( " imgTopDown " , CV_WINDOW_AUTOSIZE );
68   cvShowImage(  " imgTopDown " , imgTopDown); // 显示图像 
69   cvReleaseImage( & imgTopDown);
70   /* --------------------------------------------------------------------------- */
71   /* 迭代法 */
72   IplImage *  imgIteration  =  cvCreateImage( cvGetSize(imgGrey), IPL_DEPTH_8U,  1  );
73   cvCopyImage(srcImgGrey,imgIteration);
74   int  thre3,nDiffRec;
75   thre3  = DetectThreshold(imgIteration,  100 , nDiffRec);
76   cout << " The Threshold of this Image in imgIteration is: " << thre3 << endl; // 输出显示阀值
77   cvThreshold(imgIteration,imgIteration,thre3, 255 ,CV_THRESH_BINARY_INV); // 上下阀值
78   cvNamedWindow( " imgIteration " , CV_WINDOW_AUTOSIZE );
79   cvShowImage(  " imgIteration " , imgIteration);
80   cvReleaseImage( & imgIteration);
复制代码

模块程序

迭代法

复制代码
1   /* ====================================================================== */
2   /*  迭代法 */
3   /* ====================================================================== */
4   //  nMaxIter:最大迭代次数;nDiffRec:使用给定阀值确定的亮区与暗区平均灰度差异值
5   int  DetectThreshold(IplImage * img,  int  nMaxIter,  int &  iDiffRec)  // 阀值分割:迭代法
6   {
7   // 图像信息
8   int  height  =  img -> height;
9   int  width  =  img -> width;
10   int  step  =  img -> widthStep / sizeof (uchar);
11   uchar  * data  =  (uchar * )img -> imageData;
12  
13   iDiffRec  = 0 ;
14   int  F[ 256 ] = {  0  };  // 直方图数组
15   int  iTotalGray = 0 ; // 灰度值和
16   int  iTotalPixel  = 0 ; // 像素数和
17   byte  bt; // 某点的像素值
18  
19   uchar iThrehold,iNewThrehold; // 阀值、新阀值
20   uchar iMaxGrayValue = 0 ,iMinGrayValue = 255 ; // 原图像中的最大灰度值和最小灰度值
21   uchar iMeanGrayValue1,iMeanGrayValue2;
22  
23   // 获取(i,j)的值,存于直方图数组F
24   for ( int  i = 0 ;i < width;i ++ )
25   {
26   for ( int  j = 0 ;j < height;j ++ )
27   {
28   bt  =  data[i * step + j];
29   if (bt < iMinGrayValue)
30   iMinGrayValue  =  bt;
31   if (bt > iMaxGrayValue)
32   iMaxGrayValue  =  bt;
33   F[bt] ++ ;
34   }
35   }
36  
37   iThrehold  = 0 ; //
38   iNewThrehold  =  (iMinGrayValue + iMaxGrayValue) / 2 ; // 初始阀值
39   iDiffRec  =  iMaxGrayValue  -  iMinGrayValue;
40  
41   for ( int  a = 0 ;(abs(iThrehold - iNewThrehold) > 0.5 ) && a < nMaxIter;a ++ ) // 迭代中止条件
42   {
43   iThrehold  =  iNewThrehold;
44   // 小于当前阀值部分的平均灰度值
45   for ( int  i = iMinGrayValue;i < iThrehold;i ++ )
46   {
47   iTotalGray  +=  F[i] * i; // F[]存储图像信息
48   iTotalPixel  +=  F[i];
49   }
50   iMeanGrayValue1  =  (uchar)(iTotalGray / iTotalPixel);
51   // 大于当前阀值部分的平均灰度值
52   iTotalPixel  = 0 ;
53   iTotalGray  = 0 ;
54   for ( int  j = iThrehold + 1 ;j < iMaxGrayValue;j ++ )
55   {
56   iTotalGray  +=  F[j] * j; // F[]存储图像信息
57   iTotalPixel  +=  F[j]; 
58   }
59   iMeanGrayValue2  =  (uchar)(iTotalGray / iTotalPixel);
60  
61   iNewThrehold  =  (iMeanGrayValue2 + iMeanGrayValue1) / 2 // 新阀值
62   iDiffRec  =  abs(iMeanGrayValue2  -  iMeanGrayValue1);
63   }
64  
65   // cout<<"The Threshold of this Image in imgIteration is:"<<iThrehold<<endl;
66   return  iThrehold;
67   }
68
复制代码

  

Otsu代码一 

复制代码
1   /* ====================================================================== */
2   /*  OTSU global thresholding routine  */
3   /*  takes a 2D unsigned char array pointer, number of rows, and  */
4   /*  number of cols in the array. returns the value of the threshold  */
5   /* parameter: 
6   *image --- buffer for image
7   rows, cols --- size of image
8   x0, y0, dx, dy --- region of vector used for computing threshold
9   vvv --- debug option, is 0, no debug information outputed
10   */
11   /*
12   OTSU 算法可以说是自适应计算单阈值(用来转换灰度图像为二值图像)的简单高效方法。
13   下面的代码最早由 Ryan Dibble提供,此后经过多人Joerg.Schulenburg, R.Z.Liu 等修改,补正。
14   算法对输入的灰度图像的直方图进行分析,将直方图分成两个部分,使得两部分之间的距离最大。
15   划分点就是求得的阈值。
16   */
17   /* ====================================================================== */
18   int  otsu (unsigned  char * image,  int  rows,  int  cols,  int  x0,  int  y0,  int  dx,  int  dy,  int  vvv)
19   {
20  
21   unsigned  char * np;  //  图像指针
22   int  thresholdValue = 1 //  阈值
23   int  ihist[ 256 ];  //  图像直方图,256个点
24  
25   int  i, j, k;  //  various counters
26   int  n, n1, n2, gmin, gmax;
27   double  m1, m2, sum, csum, fmax, sb;
28  
29   //  对直方图置零
30   memset(ihist,  0 sizeof (ihist));
31  
32   gmin = 255 ; gmax = 0 ;
33   //  生成直方图
34   for  (i  =  y0  + 1 ; i  <  y0  +  dy  - 1 ; i ++
35   {
36   np  =  (unsigned  char * )image[i * cols + x0 + 1 ];
37   for  (j  =  x0  + 1 ; j  <  x0  +  dx  - 1 ; j ++ )
38   {
39   ihist[ * np] ++ ;
40   if ( * np  >  gmax) gmax =* np;
41   if ( * np  <  gmin) gmin =* np;
42   np ++ /*  next pixel  */
43   }
44   }
45  
46   //  set up everything
47   sum  =  csum  = 0.0 ;
48   = 0 ;
49  
50   for  (k  = 0 ; k  <= 255 ; k ++
51   {
52   sum  +=  ( double ) k  *  ( double ) ihist[k];  /*  x*f(x) 质量矩 */
53   +=  ihist[k];  /*  f(x) 质量  */
54   }
55  
56   if  ( ! n) 
57   {
58   //  if n has no value, there is problems...
59   fprintf (stderr,  " NOT NORMAL thresholdValue = 160\n " );
60   return  ( 160 );
61   }
62  
63   //  do the otsu global thresholding method
64   fmax  = - 1.0 ;
65   n1  = 0 ;
66   for  (k  = 0 ; k  < 255 ; k ++ )
67   {
68   n1  +=  ihist[k];
69   if  ( ! n1) 
70   { 
71   continue
72   }
73   n2  =  n  -  n1;
74   if  (n2  == 0 )
75   { 
76   break
77   }
78   csum  +=  ( double ) k  * ihist[k];
79   m1  =  csum  /  n1;
80   m2  =  (sum  -  csum)  /  n2;
81   sb  =  ( double ) n1  * ( double ) n2  * (m1  -  m2)  *  (m1  -  m2);
82   /*  bbg: note: can be optimized.  */
83   if  (sb  >  fmax) 
84   {
85   fmax  =  sb;
86   thresholdValue  =  k;
87   }
88   }
89  
90   //  at this point we have our thresholding value
91  
92   //  debug code to display thresholding values
93   if  ( vvv  & 1  )
94   fprintf(stderr, " # OTSU: thresholdValue = %d gmin=%d gmax=%d\n " ,
95   thresholdValue, gmin, gmax);
96  
97   return (thresholdValue);
98   }
复制代码

Otsu代码二 

复制代码
1   /* ====================================================================== */
2   /*  OTSU global thresholding routine  */
3   /* ====================================================================== */
4   int  otsu2 (IplImage  * image)
5   {
6   int  w  =  image -> width;
7   int  h  =  image -> height;
8  
9   unsigned  char * np;  //  图像指针
10   unsigned  char  pixel;
11   int  thresholdValue = 1 //  阈值
12   int  ihist[ 256 ];  //  图像直方图,256个点
13  
14   int  i, j, k;  //  various counters
15   int  n, n1, n2, gmin, gmax;
16   double  m1, m2, sum, csum, fmax, sb;
17  
18   //  对直方图置零...
19   memset(ihist,  0 sizeof (ihist));
20  
21   gmin = 255 ; gmax = 0 ;
22   //  生成直方图
23   for  (i  = 0 ; i  <  h; i ++
24   {
25   np  =  (unsigned  char * )(image -> imageData  +  image -> widthStep * i);
26   for  (j  = 0 ; j  <  w; j ++
27   {
28   pixel  =  np[j];
29   ihist[ pixel] ++ ;
30   if (pixel  >  gmax) gmax =  pixel;
31   if (pixel  <  gmin) gmin =  pixel;
32   }
33   }
34  
35   //  set up everything
36   sum  =  csum  = 0.0 ;
37   = 0 ;
38  
39   for  (k  = 0 ; k  <= 255 ; k ++
40   {
41   sum  +=  k  *  ihist[k];  /*  x*f(x) 质量矩 */
42   +=  ihist[k];  /*  f(x) 质量  */
43   }
44  
45   if  ( ! n) 
46   {
47   //  if n has no value, there is problems...
48   // fprintf (stderr, "NOT NORMAL thresholdValue = 160\n");
49   thresholdValue  = 160 ;
50   goto  L;
51   }
52  
53   //  do the otsu global thresholding method
54   fmax  = - 1.0 ;
55   n1  = 0 ;
56   for  (k  = 0 ; k  < 255 ; k ++
57   {
58   n1  +=  ihist[k];
59   if  ( ! n1) {  continue ; }
60   n2  =  n  -  n1;
61   if  (n2  == 0 ) {  break ; }
62   csum  +=  k  * ihist[k];
63   m1  =  csum  /  n1;
64   m2  =  (sum  -  csum)  /  n2;
65   sb  =  n1  *  n2  * (m1  -  m2)  *  (m1  -  m2);
66   /*  bbg: note: can be optimized.  */
67   if  (sb  >  fmax)
68   {
69   fmax  =  sb;
70   thresholdValue  =  k;
71   }
72   }
73  
74   L:
75   for  (i  = 0 ; i  <  h; i ++
76   {
77   np  =  (unsigned  char * )(image -> imageData  +  image -> widthStep * i);
78   for  (j  = 0 ; j  <  w; j ++
79   {
80   if (np[j]  >=  thresholdValue)
81   np[j]  = 255 ;
82   else  np[j]  = 0 ;
83   }
84   }
85  
86   // cout<<"The Threshold of this Image in Otsu is:"<<thresholdValue<<endl;
87   return (thresholdValue);
88   }
复制代码

 

最大熵阀值 

复制代码
1   /* ============================================================================
2   = 代码内容:最大熵阈值分割 
3   = 修改日期:2009-3-3 
4   = 作者:crond123 
5   = 博客: http://blog.csdn.net/crond123/
6   = E_Mail:crond123@163.com 
7   =============================================================================== */
8   //  计算当前位置的能量熵
9   double  caculateCurrentEntropy(CvHistogram  *  Histogram1, int  cur_threshold,entropy_state state)
10   {
11   int  start,end;
12   int  total  = 0 ;
13   double  cur_entropy  = 0.0 ;
14   if (state  ==  back) 
15   {
16   start  = 0 ;
17   end  =  cur_threshold; 
18   }
19   else  
20   {
21   start  =  cur_threshold;
22   end  = 256
23  
24   for ( int  i = start;i < end;i ++
25   {
26   total  +=  ( int )cvQueryHistValue_1D(Histogram1,i); // 查询直方块的值 P304
27   }
28   for ( int  j = start;j < end;j ++ )
29   {
30   if (( int )cvQueryHistValue_1D(Histogram1,j) == 0 )
31   continue ;
32   double  percentage  =  cvQueryHistValue_1D(Histogram1,j) / total;
33   /* 熵的定义公式 */
34   cur_entropy  += - percentage * logf(percentage);
35   /* 根据泰勒展式去掉高次项得到的熵的近似计算公式
36   cur_entropy += percentage*percentage; */  
37   }
38   return  cur_entropy;
39   //  return (1-cur_entropy);
40   }
41  
42   // 寻找最大熵阈值并分割
43   void  MaxEntropy(IplImage  * src,IplImage  * dst)
44   {
45   assert(src  !=  NULL);
46   assert(src -> depth  == 8 &&  dst -> depth  == 8 );
47   assert(src -> nChannels  == 1 );
48   CvHistogram  *  hist  =  cvCreateHist( 1 , & HistogramBins,CV_HIST_ARRAY,HistogramRange); // 创建一个指定尺寸的直方图
49   // 参数含义:直方图包含的维数、直方图维数尺寸的数组、直方图的表示格式、方块范围数组、归一化标志
50   cvCalcHist( & src,hist); // 计算直方图
51   double  maxentropy  = - 1.0 ;
52   int  max_index  = - 1 ;
53   //  循环测试每个分割点,寻找到最大的阈值分割点
54   for ( int  i = 0 ;i < HistogramBins;i ++
55   {
56   double  cur_entropy  =  caculateCurrentEntropy(hist,i, object ) + caculateCurrentEntropy(hist,i,back);
57   if (cur_entropy > maxentropy)
58   {
59   maxentropy  =  cur_entropy;
60   max_index  =  i;
61   }
62   }
63   cout << " The Threshold of this Image in MaxEntropy is: " << max_index << endl;
64   cvThreshold(src, dst, ( double )max_index, 255 , CV_THRESH_BINARY);
65   cvReleaseHist( & hist);
66   }
复制代码

基本全局阀值法 

复制代码
1   /* ============================================================================
2   = 代码内容:基本全局阈值法 
3   ============================================================================== */
4   int  BasicGlobalThreshold( int * pg, int  start, int  end)
5   {  //  基本全局阈值法
6   int  i,t,t1,t2,k1,k2;
7   double  u,u1,u2; 
8   t = 0
9   u = 0 ;
10   for  (i = start;i < end;i ++
11   {
12   t += pg[i]; 
13   u += i * pg[i];
14   }
15   k2 = ( int ) (u / t);  //  计算此范围灰度的平均值 
16   do  
17   {
18   k1 = k2;
19   t1 = 0
20   u1 = 0 ;
21   for  (i = start;i <= k1;i ++
22   {  //  计算低灰度组的累加和
23   t1 += pg[i]; 
24   u1 += i * pg[i];
25   }
26   t2 = t - t1;
27   u2 = u - u1;
28   if  (t1) 
29   u1 = u1 / t1;  //  计算低灰度组的平均值
30   else  
31   u1 = 0 ;
32   if  (t2) 
33   u2 = u2 / t2;  //  计算高灰度组的平均值
34   else  
35   u2 = 0 ;
36   k2 = ( int ) ((u1 + u2) / 2 );  //  得到新的阈值估计值
37   }
38   while (k1 != k2);  //  数据未稳定,继续
39   // cout<<"The Threshold of this Image in BasicGlobalThreshold is:"<<k1<<endl;
40   return (k1);  //  返回阈值
41   }
复制代码

  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值