Open CV 七种常见阈值分割

整理摘录 skyseraph 代码所得

出处:http://www.cnblogs.com/skyseraph/

复制The All 可直接运行

  1 #include <windows.h>
  2 #include "cv.h"
  3 #include "highgui.h"
  4 #include <stdio.h>
  5 #include <math.h>
  6 #include <iostream>
  7 #include <ctime>
  8
  9 using namespace std;
 10 /*===============================核心程序===========================================*/
 11 int main(int argc,char** argv)
 12 {
 13     IplImage *src,*grayImg;
 14     src=cvLoadImage("Lena.jpg",1);
 15     grayImg=cvCreateImage(cvGetSize(src),src->depth,1);
 16     cvCvtColor(src,grayImg,CV_BGR2GRAY);
 17
 18     /*===============================图像分割=====================================*/
 19
 20     /*手动设置阈值*/
 21     IplImage* binaryImg = cvCreateImage(cvGetSize(src),IPL_DEPTH_8U, 1);
 22     cvThreshold(grayImg,binaryImg,71,255,CV_THRESH_BINARY);
 23     cvNamedWindow("cvThreshold", CV_WINDOW_AUTOSIZE );
 24     cvShowImage( "cvThreshold", binaryImg );
 25     const char* path1;
 26     path1="Threshold.bmp";
 27     cvSaveImage(path1, binaryImg);
 28
 29
 30     /*---------------------------------------------------------------------------*/
 31     /*自适应阀值  //计算像域邻域的平均灰度,来决定二值化的值*/
 32
 33     IplImage* adThresImg = cvCreateImage(cvGetSize(src),IPL_DEPTH_8U, 1);
 34     double max_value=255;
 35     int adpative_method=CV_ADAPTIVE_THRESH_GAUSSIAN_C;//CV_ADAPTIVE_THRESH_MEAN_C
 36     int threshold_type=CV_THRESH_BINARY;
 37     int block_size=3;//阈值的象素邻域大小
 38     int offset=5;//窗口尺寸
 39     cvAdaptiveThreshold(grayImg,adThresImg,max_value,adpative_method,threshold_type,block_size,offset);
 40     cvNamedWindow("cvAdaptiveThreshold", CV_WINDOW_AUTOSIZE );
 41     cvShowImage( "cvAdaptiveThreshold", adThresImg );
 42     const char* path2;
 43     path2="AdaptiveThreshold.bmp";
 44     cvSaveImage(path2, adThresImg);
 45     /*---------------------------------------------------------------------------*/
 46
 47
 48     /*最大熵阀值分割法*/
 49
 50     IplImage* imgMaxEntropy = cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,1);
 51     MaxEntropy(grayImg,imgMaxEntropy);
 52     cvNamedWindow("MaxEntroyThreshold", CV_WINDOW_AUTOSIZE );
 53     cvShowImage( "MaxEntroyThreshold", imgMaxEntropy );//显示图像
 54     const char* path3;
 55     path3="MaxEntropy.bmp";
 56     cvSaveImage(path3, imgMaxEntropy);
 57
 58     /*-----------------------------------------------------------------------------*/
 59
 60     /*基本全局阀值法*/
 61
 62     IplImage* imgBasicGlobalThreshold = cvCreateImage(cvGetSize(grayImg),IPL_DEPTH_8U,1);
 63     imgBasicGlobalThreshold=cvCloneImage(grayImg);
 64     int  pg[256],i,thre;
 65     for (i=0;i<256;i++) pg[i]=0;
 66     for (i=0;i<imgBasicGlobalThreshold->imageSize;i++)      //  直方图统计
 67         pg[(byte)imgBasicGlobalThreshold->imageData[i]]++;
 68     thre = BasicGlobalThreshold(pg,0,256);    //  确定阈值
 69     cout<<"The Threshold of this Image in BasicGlobalThreshold is:"<<thre<<endl;//输出显示阀值
 70     cvThreshold(imgBasicGlobalThreshold,imgBasicGlobalThreshold,thre,255,CV_THRESH_BINARY);  //  二值化
 71     cvNamedWindow("BasicGlobalThreshold", CV_WINDOW_AUTOSIZE );
 72     cvShowImage( "BasicGlobalThreshold", imgBasicGlobalThreshold);//显示图像
 73     const char* path4;
 74     path4="BasicGlobalThreshold.bmp";
 75     cvSaveImage(path4, imgBasicGlobalThreshold);
 76
 77 /*----------------------------------------------------------------------------------------*/
 78
 79    /*OTSU*/
 80
 81     IplImage* imgOtsu = cvCreateImage(cvGetSize(grayImg),IPL_DEPTH_8U,1);
 82     imgOtsu=cvCloneImage(grayImg);
 83     int thre2;
 84     thre2 = otsu(imgOtsu);
 85     cout<<"The Threshold of this Image in Otsu is:"<<thre2<<endl;//输出显示阀值
 86     cvThreshold(imgOtsu,imgOtsu,thre2,255,CV_THRESH_BINARY);  //  二值化
 87     cvNamedWindow("imgOtsu", CV_WINDOW_AUTOSIZE );
 88     cvShowImage( "imgOtsu", imgOtsu);//显示图像
 89     const char* path5;
 90     path5="Otsu.bmp";
 91     cvSaveImage(path5, imgOtsu);
 92
 93 /*-------------------------------------------------------------------------------------------*/
 94     /*上下阀值法:利用正态分布求可信区间*/
 95     IplImage* imgTopDown = cvCreateImage( cvGetSize(grayImg), IPL_DEPTH_8U, 1 );
 96     imgTopDown=cvCloneImage(grayImg);
 97     CvScalar mean ,std_dev;//平均值、 标准差
 98     double u_threshold,d_threshold;
 99     cvAvgSdv(imgTopDown,&mean,&std_dev,NULL);
100     u_threshold = mean.val[0] +2.5* std_dev.val[0];//上阀值
101     d_threshold = mean.val[0] -2.5* std_dev.val[0];//下阀值
102     cout<<"The TopThreshold of this Image in TopDown is:"<<d_threshold<<endl;//输出显示阀值
103     cout<<"The DownThreshold of this Image in TopDown is:"<<u_threshold<<endl;
104     cvThreshold(imgTopDown,imgTopDown,d_threshold,u_threshold,CV_THRESH_BINARY_INV);//上下阀值
105     cvNamedWindow("imgTopDown", CV_WINDOW_AUTOSIZE );
106     cvShowImage( "imgTopDown", imgTopDown);//显示图像
107     const char* path6;
108     path6="TopDown.bmp";
109     cvSaveImage(path6, imgTopDown);
110
111     /*---------------------------------------------------------------------------*/
112     /*迭代法*/
113     IplImage* imgIteration = cvCreateImage( cvGetSize(grayImg), IPL_DEPTH_8U, 1 );
114     imgIteration=cvCloneImage(grayImg);
115     int thre3,nDiffRec;
116     thre3 =DetectThreshold(imgIteration, 100, nDiffRec);
117     cout<<"The Threshold of this Image in imgIteration is:"<<thre3<<endl;//输出显示阀值
118     cvThreshold(imgIteration,imgIteration,thre3,255,CV_THRESH_BINARY_INV);//上下阀值
119     cvNamedWindow("imgIteration", CV_WINDOW_AUTOSIZE );
120     cvShowImage( "imgIteration", imgIteration);
121     const char* path7;
122     path7="Iteration.bmp";
123     cvSaveImage(path7, imgIteration);
124
125
126
127
128     /*---------------------------------------------------------------------------*/
129     /*释放内存空间*/
130     cvReleaseImage(&imgIteration);
131     cvReleaseImage(&imgTopDown);
132     cvReleaseImage(&imgOtsu);
133     cvReleaseImage(&imgBasicGlobalThreshold);
134     cvReleaseImage(&imgMaxEntropy );
135     cvReleaseImage(&adThresImg);
136     cvReleaseImage(&binaryImg);
137     cvWaitKey(0);return 0;
138 }

核心代码

  1 /*============================================================================
  2 =  代码内容:最大熵阈值分割
  3 =  修改日期:2009-3-3
  4 =  作者:crond123
  5 =  博客:http://blog.csdn.net/crond123/
  6 =  E_Mail:[email protected]
  7 ===============================================================================*/
  8 // 计算当前位置的能量熵
  9 int HistogramBins = 256;
 10 float HistogramRange1[2] = {0,255};
 11 float *HistogramRange[1] = {&HistogramRange1[0]};
 12 typedef enum {back,object} entropy_state;
 13 double caculateCurrentEntropy(CvHistogram * Histogram1,int cur_threshold,entropy_state state)
 14 {
 15 int start,end;
 16 int  total =0;
 17 double cur_entropy =0.0;
 18 if(state == back)
 19     {
 20         start =0;
 21         end = cur_threshold;
 22     }
 23 else
 24     {
 25         start = cur_threshold;
 26         end =256;
 27     }
 28 for(int i=start;i<end;i++)
 29     {
 30         total += (int)cvQueryHistValue_1D(Histogram1,i);//查询直方块的值 P304
 31     }
 32 for(int j=start;j<end;j++)
 33     {
 34 if((int)cvQueryHistValue_1D(Histogram1,j)==0)
 35 continue;
 36 double percentage = cvQueryHistValue_1D(Histogram1,j)/total;
 37 /*熵的定义公式*/
 38         cur_entropy +=-percentage*logf(percentage);
 39 /*根据泰勒展式去掉高次项得到的熵的近似计算公式
 40         cur_entropy += percentage*percentage;*/
 41     }
 42 return cur_entropy;
 43 //    return (1-cur_entropy);
 44 }
 45
 46 //寻找最大熵阈值并分割
 47 void  MaxEntropy(IplImage *src,IplImage *dst)
 48 {
 49     assert(src != NULL);
 50     assert(src->depth ==8&& dst->depth ==8);
 51     assert(src->nChannels ==1);
 52     CvHistogram * hist  = cvCreateHist(1,&HistogramBins,CV_HIST_ARRAY,HistogramRange);//创建一个指定尺寸的直方图
 53 //参数含义:直方图包含的维数、直方图维数尺寸的数组、直方图的表示格式、方块范围数组、归一化标志
 54     cvCalcHist(&src,hist);//计算直方图
 55 double maxentropy =-1.0;
 56 int max_index =-1;
 57 // 循环测试每个分割点,寻找到最大的阈值分割点
 58 for(int i=0;i<HistogramBins;i++)
 59     {
 60 double cur_entropy = caculateCurrentEntropy(hist,i,object)+caculateCurrentEntropy(hist,i,back);
 61 if(cur_entropy>maxentropy)
 62         {
 63             maxentropy = cur_entropy;
 64             max_index = i;
 65         }
 66     }
 67     cout<<"The Threshold of this Image in MaxEntropy is:"<<max_index<<endl;
 68     cvThreshold(src, dst, (double)max_index,255, CV_THRESH_BINARY);
 69     cvReleaseHist(&hist);
 70 }
 71
 72
 73    /*============================================================================
 74     =  代码内容:基本全局阈值法
 75     ==============================================================================*/
 76     int BasicGlobalThreshold(int*pg,int start,int end)
 77 {                                           //  基本全局阈值法
 78     int  i,t,t1,t2,k1,k2;
 79     double u,u1,u2;
 80     t=0;
 81     u=0;
 82     for (i=start;i<end;i++)
 83     {
 84         t+=pg[i];
 85         u+=i*pg[i];
 86     }
 87     k2=(int) (u/t);                          //  计算此范围灰度的平均值
 88     do
 89     {
 90         k1=k2;
 91         t1=0;
 92         u1=0;
 93         for (i=start;i<=k1;i++)
 94         {             //  计算低灰度组的累加和
 95             t1+=pg[i];
 96             u1+=i*pg[i];
 97         }
 98         t2=t-t1;
 99         u2=u-u1;
100         if (t1)
101             u1=u1/t1;                     //  计算低灰度组的平均值
102         else
103             u1=0;
104         if (t2)
105             u2=u2/t2;                     //  计算高灰度组的平均值
106         else
107             u2=0;
108         k2=(int) ((u1+u2)/2);                 //  得到新的阈值估计值
109     }
110     while(k1!=k2);                           //  数据未稳定,继续
111     //cout<<"The Threshold of this Image in BasicGlobalThreshold is:"<<k1<<endl;
112     return(k1);                              //  返回阈值
113 }
114
115     /*======================================================================*/
116     /* OTSU global thresholding routine */
117     /*======================================================================*/
118     int otsu (IplImage *image)
119     {
120         int w = image->width;
121         int h = image->height;
122
123         unsigned char*np; // 图像指针
124         unsigned char pixel;
125         int thresholdValue=1; // 阈值
126         int ihist[256]; // 图像直方图,256个点
127
128         int i, j, k; // various counters
129         int n, n1, n2, gmin, gmax;
130         double m1, m2, sum, csum, fmax, sb;
131
132         // 对直方图置零...
133         memset(ihist, 0, sizeof(ihist));
134
135         gmin=255; gmax=0;
136         // 生成直方图
137         for (i =0; i < h; i++)
138         {
139             np = (unsigned char*)(image->imageData + image->widthStep*i);
140             for (j =0; j < w; j++)
141             {
142                 pixel = np[j];
143                 ihist[ pixel]++;
144                 if(pixel > gmax) gmax= pixel;
145                 if(pixel < gmin) gmin= pixel;
146             }
147         }
148
149         // set up everything
150         sum = csum =0.0;
151         n =0;
152
153         for (k =0; k <=255; k++)
154         {
155             sum += k * ihist[k]; /* x*f(x) 质量矩*/
156             n += ihist[k]; /* f(x) 质量 */
157         }
158
159         if (!n)
160         {
161             // if n has no value, there is problems...
162             //fprintf (stderr, "NOT NORMAL thresholdValue = 160\n");
163             thresholdValue =160;
164             goto L;
165         }
166
167         // do the otsu global thresholding method
168         fmax =-1.0;
169         n1 =0;
170         for (k =0; k <255; k++)
171         {
172             n1 += ihist[k];
173             if (!n1) { continue; }
174             n2 = n - n1;
175             if (n2 ==0) { break; }
176             csum += k *ihist[k];
177             m1 = csum / n1;
178             m2 = (sum - csum) / n2;
179             sb = n1 * n2 *(m1 - m2) * (m1 - m2);
180             /* bbg: note: can be optimized. */
181             if (sb > fmax)
182             {
183                 fmax = sb;
184                 thresholdValue = k;
185             }
186         }
187
188 L:
189         for (i =0; i < h; i++)
190         {
191             np = (unsigned char*)(image->imageData + image->widthStep*i);
192             for (j =0; j < w; j++)
193             {
194                 if(np[j] >= thresholdValue)
195                     np[j] =255;
196                 else np[j] =0;
197             }
198         }
199
200         //cout<<"The Threshold of this Image in Otsu is:"<<thresholdValue<<endl;
201         return(thresholdValue);
202     }
203
204     /*======================================================================*/
205     /* 迭代法*/
206     /*======================================================================*/
207     // nMaxIter:最大迭代次数;nDiffRec:使用给定阀值确定的亮区与暗区平均灰度差异值
208     int DetectThreshold(IplImage*img, int nMaxIter, int& iDiffRec)  //阀值分割:迭代法
209     {
210         //图像信息
211         int height = img->height;
212         int width = img->width;
213         int step = img->widthStep/sizeof(uchar);
214         uchar *data = (uchar*)img->imageData;
215
216         iDiffRec =0;
217         int F[256]={ 0 }; //直方图数组
218         int iTotalGray=0;//灰度值和
219         int iTotalPixel =0;//像素数和
220         byte bt;//某点的像素值
221
222         uchar iThrehold,iNewThrehold;//阀值、新阀值
223         uchar iMaxGrayValue=0,iMinGrayValue=255;//原图像中的最大灰度值和最小灰度值
224         uchar iMeanGrayValue1,iMeanGrayValue2;
225
226         //获取(i,j)的值,存于直方图数组F
227         for(int i=0;i<width;i++)
228         {
229             for(int j=0;j<height;j++)
230             {
231                 bt = data[i*step+j];
232                 if(bt<iMinGrayValue)
233                     iMinGrayValue = bt;
234                 if(bt>iMaxGrayValue)
235                     iMaxGrayValue = bt;
236                 F[bt]++;
237             }
238         }
239
240         iThrehold =0;//
241         iNewThrehold = (iMinGrayValue+iMaxGrayValue)/2;//初始阀值
242         iDiffRec = iMaxGrayValue - iMinGrayValue;
243
244         for(int a=0;(abs(iThrehold-iNewThrehold)>0.5)&&a<nMaxIter;a++)//迭代中止条件
245         {
246             iThrehold = iNewThrehold;
247             //小于当前阀值部分的平均灰度值
248             for(int i=iMinGrayValue;i<iThrehold;i++)
249             {
250                 iTotalGray += F[i]*i;//F[]存储图像信息
251                 iTotalPixel += F[i];
252             }
253             iMeanGrayValue1 = (uchar)(iTotalGray/iTotalPixel);
254             //大于当前阀值部分的平均灰度值
255             iTotalPixel =0;
256             iTotalGray =0;
257             for(int j=iThrehold+1;j<iMaxGrayValue;j++)
258             {
259                 iTotalGray += F[j]*j;//F[]存储图像信息
260                 iTotalPixel += F[j];
261             }
262             iMeanGrayValue2 = (uchar)(iTotalGray/iTotalPixel);
263
264             iNewThrehold = (iMeanGrayValue2+iMeanGrayValue1)/2;        //新阀值
265             iDiffRec = abs(iMeanGrayValue2 - iMeanGrayValue1);
266         }
267
268         //cout<<"The Threshold of this Image in imgIteration is:"<<iThrehold<<endl;
269         return iThrehold;
270     }

子模块代码

  1 #include <windows.h>
  2 #include "cv.h"
  3 #include "highgui.h"
  4 #include <stdio.h>
  5 #include <math.h>
  6 #include <iostream>
  7 #include <ctime>
  8
  9 using namespace std;
 10
 11 /*============================================================================
 12 =  代码内容:最大熵阈值分割
 13 =  修改日期:2009-3-3
 14 =  作者:crond123
 15 =  博客:http://blog.csdn.net/crond123/
 16 =  E_Mail:[email protected]
 17 ===============================================================================*/
 18 // 计算当前位置的能量熵
 19 int HistogramBins = 256;
 20 float HistogramRange1[2] = {0,255};
 21 float *HistogramRange[1] = {&HistogramRange1[0]};
 22 typedef enum {back,object} entropy_state;
 23 double caculateCurrentEntropy(CvHistogram * Histogram1,int cur_threshold,entropy_state state)
 24 {
 25 int start,end;
 26 int  total =0;
 27 double cur_entropy =0.0;
 28 if(state == back)
 29     {
 30         start =0;
 31         end = cur_threshold;
 32     }
 33 else
 34     {
 35         start = cur_threshold;
 36         end =256;
 37     }
 38 for(int i=start;i<end;i++)
 39     {
 40         total += (int)cvQueryHistValue_1D(Histogram1,i);//查询直方块的值 P304
 41     }
 42 for(int j=start;j<end;j++)
 43     {
 44 if((int)cvQueryHistValue_1D(Histogram1,j)==0)
 45 continue;
 46 double percentage = cvQueryHistValue_1D(Histogram1,j)/total;
 47 /*熵的定义公式*/
 48         cur_entropy +=-percentage*logf(percentage);
 49 /*根据泰勒展式去掉高次项得到的熵的近似计算公式
 50         cur_entropy += percentage*percentage;*/
 51     }
 52 return cur_entropy;
 53 //    return (1-cur_entropy);
 54 }
 55
 56 //寻找最大熵阈值并分割
 57 void  MaxEntropy(IplImage *src,IplImage *dst)
 58 {
 59     assert(src != NULL);
 60     assert(src->depth ==8&& dst->depth ==8);
 61     assert(src->nChannels ==1);
 62     CvHistogram * hist  = cvCreateHist(1,&HistogramBins,CV_HIST_ARRAY,HistogramRange);//创建一个指定尺寸的直方图
 63 //参数含义:直方图包含的维数、直方图维数尺寸的数组、直方图的表示格式、方块范围数组、归一化标志
 64     cvCalcHist(&src,hist);//计算直方图
 65 double maxentropy =-1.0;
 66 int max_index =-1;
 67 // 循环测试每个分割点,寻找到最大的阈值分割点
 68 for(int i=0;i<HistogramBins;i++)
 69     {
 70 double cur_entropy = caculateCurrentEntropy(hist,i,object)+caculateCurrentEntropy(hist,i,back);
 71 if(cur_entropy>maxentropy)
 72         {
 73             maxentropy = cur_entropy;
 74             max_index = i;
 75         }
 76     }
 77     cout<<"The Threshold of this Image in MaxEntropy is:"<<max_index<<endl;
 78     cvThreshold(src, dst, (double)max_index,255, CV_THRESH_BINARY);
 79     cvReleaseHist(&hist);
 80 }
 81
 82
 83    /*============================================================================
 84     =  代码内容:基本全局阈值法
 85     ==============================================================================*/
 86     int BasicGlobalThreshold(int*pg,int start,int end)
 87 {                                           //  基本全局阈值法
 88     int  i,t,t1,t2,k1,k2;
 89     double u,u1,u2;
 90     t=0;
 91     u=0;
 92     for (i=start;i<end;i++)
 93     {
 94         t+=pg[i];
 95         u+=i*pg[i];
 96     }
 97     k2=(int) (u/t);                          //  计算此范围灰度的平均值
 98     do
 99     {
100         k1=k2;
101         t1=0;
102         u1=0;
103         for (i=start;i<=k1;i++)
104         {             //  计算低灰度组的累加和
105             t1+=pg[i];
106             u1+=i*pg[i];
107         }
108         t2=t-t1;
109         u2=u-u1;
110         if (t1)
111             u1=u1/t1;                     //  计算低灰度组的平均值
112         else
113             u1=0;
114         if (t2)
115             u2=u2/t2;                     //  计算高灰度组的平均值
116         else
117             u2=0;
118         k2=(int) ((u1+u2)/2);                 //  得到新的阈值估计值
119     }
120     while(k1!=k2);                           //  数据未稳定,继续
121     //cout<<"The Threshold of this Image in BasicGlobalThreshold is:"<<k1<<endl;
122     return(k1);                              //  返回阈值
123 }
124
125     /*======================================================================*/
126     /* OTSU global thresholding routine */
127     /*======================================================================*/
128     int otsu (IplImage *image)
129     {
130         int w = image->width;
131         int h = image->height;
132
133         unsigned char*np; // 图像指针
134         unsigned char pixel;
135         int thresholdValue=1; // 阈值
136         int ihist[256]; // 图像直方图,256个点
137
138         int i, j, k; // various counters
139         int n, n1, n2, gmin, gmax;
140         double m1, m2, sum, csum, fmax, sb;
141
142         // 对直方图置零...
143         memset(ihist, 0, sizeof(ihist));
144
145         gmin=255; gmax=0;
146         // 生成直方图
147         for (i =0; i < h; i++)
148         {
149             np = (unsigned char*)(image->imageData + image->widthStep*i);
150             for (j =0; j < w; j++)
151             {
152                 pixel = np[j];
153                 ihist[ pixel]++;
154                 if(pixel > gmax) gmax= pixel;
155                 if(pixel < gmin) gmin= pixel;
156             }
157         }
158
159         // set up everything
160         sum = csum =0.0;
161         n =0;
162
163         for (k =0; k <=255; k++)
164         {
165             sum += k * ihist[k]; /* x*f(x) 质量矩*/
166             n += ihist[k]; /* f(x) 质量 */
167         }
168
169         if (!n)
170         {
171             // if n has no value, there is problems...
172             //fprintf (stderr, "NOT NORMAL thresholdValue = 160\n");
173             thresholdValue =160;
174             goto L;
175         }
176
177         // do the otsu global thresholding method
178         fmax =-1.0;
179         n1 =0;
180         for (k =0; k <255; k++)
181         {
182             n1 += ihist[k];
183             if (!n1) { continue; }
184             n2 = n - n1;
185             if (n2 ==0) { break; }
186             csum += k *ihist[k];
187             m1 = csum / n1;
188             m2 = (sum - csum) / n2;
189             sb = n1 * n2 *(m1 - m2) * (m1 - m2);
190             /* bbg: note: can be optimized. */
191             if (sb > fmax)
192             {
193                 fmax = sb;
194                 thresholdValue = k;
195             }
196         }
197
198 L:
199         for (i =0; i < h; i++)
200         {
201             np = (unsigned char*)(image->imageData + image->widthStep*i);
202             for (j =0; j < w; j++)
203             {
204                 if(np[j] >= thresholdValue)
205                     np[j] =255;
206                 else np[j] =0;
207             }
208         }
209
210         //cout<<"The Threshold of this Image in Otsu is:"<<thresholdValue<<endl;
211         return(thresholdValue);
212     }
213
214     /*======================================================================*/
215     /* 迭代法*/
216     /*======================================================================*/
217     // nMaxIter:最大迭代次数;nDiffRec:使用给定阀值确定的亮区与暗区平均灰度差异值
218     int DetectThreshold(IplImage*img, int nMaxIter, int& iDiffRec)  //阀值分割:迭代法
219     {
220         //图像信息
221         int height = img->height;
222         int width = img->width;
223         int step = img->widthStep/sizeof(uchar);
224         uchar *data = (uchar*)img->imageData;
225
226         iDiffRec =0;
227         int F[256]={ 0 }; //直方图数组
228         int iTotalGray=0;//灰度值和
229         int iTotalPixel =0;//像素数和
230         byte bt;//某点的像素值
231
232         uchar iThrehold,iNewThrehold;//阀值、新阀值
233         uchar iMaxGrayValue=0,iMinGrayValue=255;//原图像中的最大灰度值和最小灰度值
234         uchar iMeanGrayValue1,iMeanGrayValue2;
235
236         //获取(i,j)的值,存于直方图数组F
237         for(int i=0;i<width;i++)
238         {
239             for(int j=0;j<height;j++)
240             {
241                 bt = data[i*step+j];
242                 if(bt<iMinGrayValue)
243                     iMinGrayValue = bt;
244                 if(bt>iMaxGrayValue)
245                     iMaxGrayValue = bt;
246                 F[bt]++;
247             }
248         }
249
250         iThrehold =0;//
251         iNewThrehold = (iMinGrayValue+iMaxGrayValue)/2;//初始阀值
252         iDiffRec = iMaxGrayValue - iMinGrayValue;
253
254         for(int a=0;(abs(iThrehold-iNewThrehold)>0.5)&&a<nMaxIter;a++)//迭代中止条件
255         {
256             iThrehold = iNewThrehold;
257             //小于当前阀值部分的平均灰度值
258             for(int i=iMinGrayValue;i<iThrehold;i++)
259             {
260                 iTotalGray += F[i]*i;//F[]存储图像信息
261                 iTotalPixel += F[i];
262             }
263             iMeanGrayValue1 = (uchar)(iTotalGray/iTotalPixel);
264             //大于当前阀值部分的平均灰度值
265             iTotalPixel =0;
266             iTotalGray =0;
267             for(int j=iThrehold+1;j<iMaxGrayValue;j++)
268             {
269                 iTotalGray += F[j]*j;//F[]存储图像信息
270                 iTotalPixel += F[j];
271             }
272             iMeanGrayValue2 = (uchar)(iTotalGray/iTotalPixel);
273
274             iNewThrehold = (iMeanGrayValue2+iMeanGrayValue1)/2;        //新阀值
275             iDiffRec = abs(iMeanGrayValue2 - iMeanGrayValue1);
276         }
277
278         //cout<<"The Threshold of this Image in imgIteration is:"<<iThrehold<<endl;
279         return iThrehold;
280     }
281
282
283 /*===============================核心程序===========================================*/
284 int main(int argc,char** argv)
285 {
286     IplImage *src,*grayImg;
287     src=cvLoadImage("Lena.jpg",1);
288     grayImg=cvCreateImage(cvGetSize(src),src->depth,1);
289     cvCvtColor(src,grayImg,CV_BGR2GRAY);
290
291     /*===============================图像分割=====================================*/
292
293     /*手动设置阈值*/
294     IplImage* binaryImg = cvCreateImage(cvGetSize(src),IPL_DEPTH_8U, 1);
295     cvThreshold(grayImg,binaryImg,71,255,CV_THRESH_BINARY);
296     cvNamedWindow("cvThreshold", CV_WINDOW_AUTOSIZE );
297     cvShowImage( "cvThreshold", binaryImg );
298     const char* path1;
299     path1="Threshold.bmp";
300     cvSaveImage(path1, binaryImg);
301
302
303     /*---------------------------------------------------------------------------*/
304     /*自适应阀值  //计算像域邻域的平均灰度,来决定二值化的值*/
305
306     IplImage* adThresImg = cvCreateImage(cvGetSize(src),IPL_DEPTH_8U, 1);
307     double max_value=255;
308     int adpative_method=CV_ADAPTIVE_THRESH_GAUSSIAN_C;//CV_ADAPTIVE_THRESH_MEAN_C
309     int threshold_type=CV_THRESH_BINARY;
310     int block_size=3;//阈值的象素邻域大小
311     int offset=5;//窗口尺寸
312     cvAdaptiveThreshold(grayImg,adThresImg,max_value,adpative_method,threshold_type,block_size,offset);
313     cvNamedWindow("cvAdaptiveThreshold", CV_WINDOW_AUTOSIZE );
314     cvShowImage( "cvAdaptiveThreshold", adThresImg );
315     const char* path2;
316     path2="AdaptiveThreshold.bmp";
317     cvSaveImage(path2, adThresImg);
318     /*---------------------------------------------------------------------------*/
319
320
321     /*最大熵阀值分割法*/
322
323     IplImage* imgMaxEntropy = cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,1);
324     MaxEntropy(grayImg,imgMaxEntropy);
325     cvNamedWindow("MaxEntroyThreshold", CV_WINDOW_AUTOSIZE );
326     cvShowImage( "MaxEntroyThreshold", imgMaxEntropy );//显示图像
327     const char* path3;
328     path3="MaxEntropy.bmp";
329     cvSaveImage(path3, imgMaxEntropy);
330
331     /*-----------------------------------------------------------------------------*/
332
333     /*基本全局阀值法*/
334
335     IplImage* imgBasicGlobalThreshold = cvCreateImage(cvGetSize(grayImg),IPL_DEPTH_8U,1);
336     imgBasicGlobalThreshold=cvCloneImage(grayImg);
337     int  pg[256],i,thre;
338     for (i=0;i<256;i++) pg[i]=0;
339     for (i=0;i<imgBasicGlobalThreshold->imageSize;i++)      //  直方图统计
340         pg[(byte)imgBasicGlobalThreshold->imageData[i]]++;
341     thre = BasicGlobalThreshold(pg,0,256);    //  确定阈值
342     cout<<"The Threshold of this Image in BasicGlobalThreshold is:"<<thre<<endl;//输出显示阀值
343     cvThreshold(imgBasicGlobalThreshold,imgBasicGlobalThreshold,thre,255,CV_THRESH_BINARY);  //  二值化
344     cvNamedWindow("BasicGlobalThreshold", CV_WINDOW_AUTOSIZE );
345     cvShowImage( "BasicGlobalThreshold", imgBasicGlobalThreshold);//显示图像
346     const char* path4;
347     path4="BasicGlobalThreshold.bmp";
348     cvSaveImage(path4, imgBasicGlobalThreshold);
349
350 /*----------------------------------------------------------------------------------------*/
351
352    /*OTSU*/
353
354     IplImage* imgOtsu = cvCreateImage(cvGetSize(grayImg),IPL_DEPTH_8U,1);
355     imgOtsu=cvCloneImage(grayImg);
356     int thre2;
357     thre2 = otsu(imgOtsu);
358     cout<<"The Threshold of this Image in Otsu is:"<<thre2<<endl;//输出显示阀值
359     cvThreshold(imgOtsu,imgOtsu,thre2,255,CV_THRESH_BINARY);  //  二值化
360     cvNamedWindow("imgOtsu", CV_WINDOW_AUTOSIZE );
361     cvShowImage( "imgOtsu", imgOtsu);//显示图像
362     const char* path5;
363     path5="Otsu.bmp";
364     cvSaveImage(path5, imgOtsu);
365
366 /*-------------------------------------------------------------------------------------------*/
367     /*上下阀值法:利用正态分布求可信区间*/
368     IplImage* imgTopDown = cvCreateImage( cvGetSize(grayImg), IPL_DEPTH_8U, 1 );
369     imgTopDown=cvCloneImage(grayImg);
370     CvScalar mean ,std_dev;//平均值、 标准差
371     double u_threshold,d_threshold;
372     cvAvgSdv(imgTopDown,&mean,&std_dev,NULL);
373     u_threshold = mean.val[0] +2.5* std_dev.val[0];//上阀值
374     d_threshold = mean.val[0] -2.5* std_dev.val[0];//下阀值
375     cout<<"The TopThreshold of this Image in TopDown is:"<<d_threshold<<endl;//输出显示阀值
376     cout<<"The DownThreshold of this Image in TopDown is:"<<u_threshold<<endl;
377     cvThreshold(imgTopDown,imgTopDown,d_threshold,u_threshold,CV_THRESH_BINARY_INV);//上下阀值
378     cvNamedWindow("imgTopDown", CV_WINDOW_AUTOSIZE );
379     cvShowImage( "imgTopDown", imgTopDown);//显示图像
380     const char* path6;
381     path6="TopDown.bmp";
382     cvSaveImage(path6, imgTopDown);
383
384     /*---------------------------------------------------------------------------*/
385     /*迭代法*/
386     IplImage* imgIteration = cvCreateImage( cvGetSize(grayImg), IPL_DEPTH_8U, 1 );
387     imgIteration=cvCloneImage(grayImg);
388     int thre3,nDiffRec;
389     thre3 =DetectThreshold(imgIteration, 100, nDiffRec);
390     cout<<"The Threshold of this Image in imgIteration is:"<<thre3<<endl;//输出显示阀值
391     cvThreshold(imgIteration,imgIteration,thre3,255,CV_THRESH_BINARY_INV);//上下阀值
392     cvNamedWindow("imgIteration", CV_WINDOW_AUTOSIZE );
393     cvShowImage( "imgIteration", imgIteration);
394     const char* path7;
395     path7="Iteration.bmp";
396     cvSaveImage(path7, imgIteration);
397
398
399
400
401     /*---------------------------------------------------------------------------*/
402     /*释放内存空间*/
403     cvReleaseImage(&imgIteration);
404     cvReleaseImage(&imgTopDown);
405     cvReleaseImage(&imgOtsu);
406     cvReleaseImage(&imgBasicGlobalThreshold);
407     cvReleaseImage(&imgMaxEntropy );
408     cvReleaseImage(&adThresImg);
409     cvReleaseImage(&binaryImg);
410     cvWaitKey(0);return 0;
411 }

All

运行结果:

                  

Orignal Img                                                      Threshold Img                                    AdaptiveThreshold Img

                  

BasicGlobalThreshold                                      MaxEntropy                                                  Otsu

         

TopDown                                                 Iteration

Hai

0730

时间: 2024-10-10 11:02:54

Open CV 七种常见阈值分割的相关文章

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

图像算法:图像阈值分割 SkySeraph Dec 21st 2010  HQU Email:[email protected]    QQ:452728574 Latest Modified Date:Dec.21st 2010 HQU 一.工具:VC+OpenCV 二.语言:C++ 三.原理(略) 四.程序 主程序(核心部分)  代码 1 /*===============================图像分割=====================================*/2

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

转自:http://blog.csdn.net/xw20084898/article/details/17564957 一.工具:VC+OpenCV 二.语言:C++ 三.原理 otsu法(最大类间方差法,有时也称之为大津算法)使用的是聚类的思想,把图像的灰度数按灰度级分成2个部分,使得两个部分之间的灰度值差异最大,每个部分之间的灰度差异最小,通过方差的计算来寻找一个合适的灰度级别 来划分. 所以 可以在二值化的时候 采用otsu算法来自动选取阈值进行二值化.otsu算法被认为是图像分割中阈值选

枚举的七种常见使用方法

枚举的使用的方法有很多,下面举出常用的七种方法: 用法一:常量 在JDK1.5之前,我们定义常量都是:publicstaticfianl.....现在好了,有了枚举,可以把相关的常量分组到一个枚举类型里,而且枚举提供了比常量更多的方法. Java代码 public enum Color { RED, GREEN, BLANK, YELLOW } 用法二:switch JDK1.6之前的switch语句只支持int,char,enum类型,使用枚举,能让我们的代码可读性更强. Java代码 enu

机器学习实践中应避免的七种常见错误

统计建模和工程开发很相似. 在工程开发中,人们有多种方法搭建一套键-值存储系统,每种设计针对使用模式有一套不同的假设.在统计建模中,也有很多算法来构造一个分类器,每种算法对数据也有各自的假设集合. 当处理少量数据时,因为实验成本很低,我们尽可能多的尝试各种算法,从而选出效果最优的算法.但提到“大数据”,提前分析数据,然后设计相应“管道”模型(预处理,建模,优化算法,评价,产品化)是事半功倍的. 正如在我以前的文章里提到,每个给定的建模问题都存在几十种解法.每个模型会提出不同的假设条件,我们也很难

七种常见经典排序算法总结(C++)

最近想复习下C++,很久没怎么用了,毕业时的一些经典排序算法也忘差不多了,所以刚好一起再学习一遍. 除了冒泡.插入.选择这几个复杂度O(n^2)的基本排序算法,希尔.归并.快速.堆排序,多多少少还有些晦涩难懂,幸好又博客园大神dreamcatcher-cx都总结成了图解,一步步很详细,十分感谢. 而且就时间复杂度来说,这几种算法到底有什么区别呢,刚好做了下测试. 代码参考: http://yansu.org/2015/09/07/sort-algorithms.html //: basic_so

红外目标图像中阈值分割方法的比较与研究

红外目标图像中阈值分割方法的比较与研究   摘要:本文主要以红外图像目标检测技术为背景,在图像阈值分割中以最大熵准则及遗传算法为基础,研究了一维最大熵值法(KSW法)及基于遗传算法的KSW熵法单阈值.双阈值等三种不同的阈值分割方法,并通过实验仿真验证了它们的性能及差异.实验结果表明:基于遗传算法的KSW熵法的双阈值分割方法,可以用于红外型目标检测系统中,并取得良好效果,为了验证其是否具有普适性,在其它科学领域如:沿海码头等方向也做了相应的仿真实验,结果较为满意. 关键词:红外目标检测:阈值分割:

短短三分钟内就可能被入侵的七种物联网设备

ForeScout公司近日发布了物联网企业风险报告,这份报告概述了常见设备如何给企业带来固有风险的严峻现状. 该公司研究了七种常见的企业物联网设备,结果表明,它们的核心技术.基本的开发方法和快速生产使得在软件.固件和硬件里面实施适当的安全机制成了一项"经常被忽视的任务". ForeScout科技公司的总裁兼首席执行官迈克尔·德萨塞尔(Michael DeCesare)在报告中说:"物联网已得到公众的接受,但是这种设备在企业界的普及带来了大得多的攻击面――这为黑客提供了易于访问

数据分析常见的七种思路

数据分析常见的七种思路:1.简单趋势通过访问趋势了解产品使用情况,便于产品迭代.访问用户量.访问来源.访问用户行为三大指标对于趋势分析具有重要意义.2.多维分解根据分析需要,从多维度对指标进行分解.例如浏览器类型.操作系统类型.访问来源.广告来源.地区.网站/手机应用.设备品牌.APP版本等维度.3.转化漏斗按照已知的转化路径,借助漏斗模型分析总体和每一步的转化情况.常见的转化情境有注册转化分析.购买转化分析等.4.用户分群在精细化分析中,常常需要对有某个特定行为的用户群组进行分析和比对:需要将

数据分析师:数据分析工作常见七种错误及其规避技巧(转自经管之家)

数据分析师:数据分析工作常见七种错误及其规避技巧商业领域的数据科学家和侦探类似:去探索未知的事物.不过,当他们在这个旅程中冒险的时候,他们很容易落入陷阱.所以要明白,这些错误是如何造成的,以及如何避免.“ ... 数据分析师:数据分析工作常见七种错误及其规避技巧 商业领域的数据科学家和侦探类似:去探索未知的事物.不过,当他们在这个旅程中冒险的时候,他们很容易落入陷阱.所以要明白,这些错误是如何造成的,以及如何避免. “错误是发现的入口.”——James Joyce (著名的爱尔兰小说家). 这在