閾值分割總結


OSTU C++實現:

#include <assert.h>
#include "cv.h"
#include "highgui.h"
#include <math.h> 
#include <iostream>
using namespace std;
// implementation of otsu algorithm
// author: onezeros(@yahoo.cn)
// reference: Rafael C. Gonzalez. Digital Image Processing Using MATLAB
void cvThresholdOtsu(IplImage* src, IplImage* dst)
{
	int height=src->height;
	int width=src->width;	

	//histogram
	float histogram[256]={0};
	for(int i=0;i<height;i++) {
		unsigned char* p=(unsigned char*)src->imageData+src->widthStep*i;
		for(int j=0;j<width;j++) {
			histogram[*p++]++;
		}
	}
	//normalize histogram
	int size=height*width;
	for(int i=0;i<256;i++) {
		histogram[i]=histogram[i]/size;
	}

	//average pixel value
	float avgValue=0;
	for(int i=0;i<256;i++) {
		avgValue+=i*histogram[i];
	}

	int threshold;	
	float maxVariance=0;
	float w=0,u=0;
	for(int i=0;i<256;i++) {
		w+=histogram[i];
		u+=i*histogram[i];

		float t=avgValue*w-u;
		float variance=t*t/(w*(1-w));
		if(variance>maxVariance) {
			maxVariance=variance;
			threshold=i;
		}
	}

	cvThreshold(src,dst,threshold,255,CV_THRESH_BINARY);
}
// implementation of otsu algorithm
// author: onezeros(@yahoo.cn)
// reference: Rafael C. Gonzalez. Digital Image Processing Using MATLAB
int cvThresholdOtsu(IplImage* src)
{
	int height=src->height;
	int width=src->width;	

	//histogram
	float histogram[256]={0};
	for(int i=0;i<height;i++) {
		unsigned char* p=(unsigned char*)src->imageData+src->widthStep*i;
		for(int j=0;j<width;j++) {
			histogram[*p++]++;
		}
	}
	//normalize histogram
	int size=height*width;
	for(int i=0;i<256;i++) {
		histogram[i]=histogram[i]/size;
	}

	//average pixel value
	float avgValue=0;
	for(int i=0;i<256;i++) {
		avgValue+=i*histogram[i];
	}

	int threshold;	
	float maxVariance=0;
	float w=0,u=0;
	for(int i=0;i<256;i++) {
		w+=histogram[i];
		u+=i*histogram[i];

		float t=avgValue*w-u;
		float variance=t*t/(w*(1-w));
		if(variance>maxVariance) {
			maxVariance=variance;
			threshold=i;
		}
	}

	return threshold;
}
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
#pragma comment(lib,"cv210d.lib")
#pragma comment(lib,"cxcore210d.lib")
#pragma comment(lib,"highgui210d.lib")

#include <iostream>
using namespace std;

int main()
{	


	int threshold=-1;
	IplImage* img =cvLoadImage("E:\\test.jpg");
		cvShowImage("video",img);
		cvCvtColor(img,img,CV_RGB2YCrCb);

		IplImage* imgCb=cvCreateImage(cvGetSize(img),8,1);
		cvSplit(img,NULL,NULL,imgCb,NULL);
		if (threshold<0){
			threshold=cvThresholdOtsu(imgCb);
		}
		//cvThresholdOtsu(imgCb,imgCb);
		cvThreshold(imgCb,imgCb,threshold,255,CV_THRESH_BINARY);
       cvSaveImage("E:\\imgCb.bmp",imgCb);
		cvShowImage("object",imgCb);
		cvReleaseImage(&imgCb);
	return 0;
}

 迭代閾值分割 mtalab實現:

%基於貝葉斯分類算法的圖像閾值分割 
clear 
clc; 
Init = imread('E:\\test.jpg'); 
Im=rgb2gray(Init);
figure(1)
imhist(Im),title('直方圖') ; 
[x,y]=size(Im);                    % 求出圖象大小 
b=double(Im);                   
zd=double(max(Im))                  % 求出圖象中最大的灰度 
zx=double(min(Im))                % 最小的灰度  
T=double((zd+zx))/2;                     % T賦初值,為最大值和最小值的平均值 

count=double(0);                         % 記錄幾次循環 
while 1                   % 迭代最佳閾值分割算法 
    count=count+1; 
    S0=0.0; n0=0.0;                   %為計算灰度大於閾值的元素的灰度總值、個數賦值 
    S1=0.0; n1=0.0;                   %為計算灰度小於閾值的元素的灰度總值、個數賦值 
    for i=1:x
        for j=1:y
            if double(Im(i,j))>=T
                S1=S1+double(Im(i,j));  %大於閾域值圖像點灰度值累加
                n1=n1+1;                %大於閾域值圖像點個數累加
            else 
                S0=S0+double(Im(i,j));  %小於閾域值圖像點灰度值累加
                n0=n0+1;                %小於閥域值圖像點個數累加
            end 
        end 
    end  
    T0=S0/n0; %求小於閥域值均值
    T1=S1/n1; %求大於閥域值均值
    if abs(T-((T0+T1)/2))<0.1     %迭代至 前后兩次閥域值相差幾乎為0時 停止迭代。
        break;
    else
       T=(T0+T1)/2;                 %在閾值T下,迭代閾值的計算過程 
   end 
end 

count                                %顯示運行次數
T
i1=im2bw(Im,T/255);               % 圖像在最佳閾值下二值化 
figure(2)
imshow(i1,'border','tight','InitialMagnification','fit') 
title('實驗結果') ;

 其他的見下面代碼,閾值需要自己測試設定(C++實現):

 

*===============================圖像分割=====================================*/
*---------------------------------------------------------------------------*/
#include <assert.h>
#include "cv.h"
#include "highgui.h"
#include <math.h> 
#include <iostream>
using namespace std;
int HistogramBins = 256;  
float HistogramRange1[2]={0,255};  
float *HistogramRange[1]={&HistogramRange1[0]};  
typedef  
enum {back,object} entropy_state;  
*======================================================================*/
* 迭代法*/
*======================================================================*/
// nMaxIter:最大迭代次數;nDiffRec:使用給定閥值確定的亮區與暗區平均灰度差異值
int DetectThreshold(IplImage*img, int nMaxIter, int& iDiffRec)  //閥值分割:迭代法
{
	//圖像信息
	int height = img->height;
	int width = img->width;
	int step = img->widthStep/sizeof(uchar);
	uchar *data = (uchar*)img->imageData;

	iDiffRec =0;
	int F[256]={ 0 }; //直方圖數組
	int iTotalGray=0;//灰度值和
	int iTotalPixel =0;//像素數和
	byte bt;//某點的像素值

	uchar iThrehold,iNewThrehold;//閥值、新閥值
	uchar iMaxGrayValue=0,iMinGrayValue=255;//原圖像中的最大灰度值和最小灰度值
	uchar iMeanGrayValue1,iMeanGrayValue2;

	//獲取(i,j)的值,存於直方圖數組F
	for(int i=0;i<width;i++)
	{
		for(int j=0;j<height;j++)
		{
			bt = data[i*step+j];
			if(bt<iMinGrayValue)
				iMinGrayValue = bt;
			if(bt>iMaxGrayValue)
				iMaxGrayValue = bt;
			F[bt]++;
		}
	}

	iThrehold =0;//
	iNewThrehold = (iMinGrayValue+iMaxGrayValue)/2;//初始閥值
	iDiffRec = iMaxGrayValue - iMinGrayValue;

	for(int a=0;(abs(iThrehold-iNewThrehold)>0.5)&&a<nMaxIter;a++)//迭代中止條件
	{
		iThrehold = iNewThrehold;
		//小於當前閥值部分的平均灰度值
		for(int i=iMinGrayValue;i<iThrehold;i++)
		{
			iTotalGray += F[i]*i;//F[]存儲圖像信息
			iTotalPixel += F[i];
		}
		iMeanGrayValue1 = (uchar)(iTotalGray/iTotalPixel);
		//大於當前閥值部分的平均灰度值
		iTotalPixel =0;
		iTotalGray =0;
		for(int j=iThrehold+1;j<iMaxGrayValue;j++)
		{
			iTotalGray += F[j]*j;//F[]存儲圖像信息
			iTotalPixel += F[j];    
		}
		iMeanGrayValue2 = (uchar)(iTotalGray/iTotalPixel);

		iNewThrehold = (iMeanGrayValue2+iMeanGrayValue1)/2;        //新閥值
		iDiffRec = abs(iMeanGrayValue2 - iMeanGrayValue1);
	}

	//cout<<"The Threshold of this Image in imgIteration is:"<<iThrehold<<endl;
	return iThrehold;
}
*======================================================================*/
 /* OTSU global thresholding routine */
 /* takes a 2D unsigned char array pointer, number of rows, and */
 /* number of cols in the array. returns the value of the threshold */
 /*parameter: 
 *image --- buffer for image
 rows, cols --- size of image
 x0, y0, dx, dy --- region of vector used for computing threshold
 vvv --- debug option, is 0, no debug information outputed
 */
 /*
 OTSU 算法可以說是自適應計算單閾值(用來轉換灰度圖像為二值圖像)的簡單高效方法。
 下面的代碼最早由 Ryan Dibble提供,此后經過多人Joerg.Schulenburg, R.Z.Liu 等修改,補正。
 算法對輸入的灰度圖像的直方圖進行分析,將直方圖分成兩個部分,使得兩部分之間的距離最大。
 划分點就是求得的閾值。
 */
 /*======================================================================*/
 int otsu (unsigned char*image, int rows, int cols, int x0, int y0, int dx, int dy, int vvv)
 {
     
     unsigned char*np; // 圖像指針
 int thresholdValue=1; // 閾值
 int ihist[256]; // 圖像直方圖,256個點
     
 int i, j, k; // various counters
 int n, n1, n2, gmin, gmax;
 double m1, m2, sum, csum, fmax, sb;
     
 // 對直方圖置零
     memset(ihist, 0, sizeof(ihist));
     
     gmin=255; gmax=0;
 // 生成直方圖
 for (i = y0 +1; i < y0 + dy -1; i++) 
     {
         np = (unsigned char*)image[i*cols+x0+1];
 for (j = x0 +1; j < x0 + dx -1; j++)
         {
             ihist[*np]++;
 if(*np > gmax) gmax=*np;
 if(*np < gmin) gmin=*np;
             np++; /* next pixel */
         }
     }
     
 // set up everything
     sum = csum =0.0;
     n =0;
     
 for (k =0; k <=255; k++) 
     {
         sum += (double) k * (double) ihist[k]; /* x*f(x) 質量矩*/
         n += ihist[k]; /* f(x) 質量 */
     }
     
 if (!n) 
     {
 // if n has no value, there is problems...
         fprintf (stderr, "NOT NORMAL thresholdValue = 160\n");
 return (160);
     }
     
 // do the otsu global thresholding method
     fmax =-1.0;
     n1 =0;
 for (k =0; k <255; k++)
     {
         n1 += ihist[k];
 if (!n1) 
         { 
 continue; 
         }
         n2 = n - n1;
 if (n2 ==0)
         { 
 break; 
         }
         csum += (double) k *ihist[k];
         m1 = csum / n1;
         m2 = (sum - csum) / n2;
         sb = (double) n1 *(double) n2 *(m1 - m2) * (m1 - m2);
 /* bbg: note: can be optimized. */
 if (sb > fmax) 
         {
             fmax = sb;
             thresholdValue = k;
         }
     }
     
 // at this point we have our thresholding value
     
 // debug code to display thresholding values
 if ( vvv &1 )
         fprintf(stderr,"# OTSU: thresholdValue = %d gmin=%d gmax=%d\n",
         thresholdValue, gmin, gmax);
     
 return(thresholdValue);
 }
 /*======================================================================*/
 /* OTSU global thresholding routine */
 /*======================================================================*/
 int otsu2 (IplImage *image)
 {
	 int w = image->width;
	 int h = image->height;

	 unsigned char*np; // 圖像指針
	 unsigned char pixel;
	 int thresholdValue=1; // 閾值
	 int ihist[256]; // 圖像直方圖,256個點

	 int i, j, k; // various counters
	 int n, n1, n2, gmin, gmax;
	 double m1, m2, sum, csum, fmax, sb;

	 // 對直方圖置零...
	 memset(ihist, 0, sizeof(ihist));

	 gmin=255; gmax=0;
	 // 生成直方圖
	 for (i =0; i < h; i++) 
	 {
		 np = (unsigned char*)(image->imageData + image->widthStep*i);
		 for (j =0; j < w; j++) 
		 {
			 pixel = np[j];
			 ihist[ pixel]++;
			 if(pixel > gmax) gmax= pixel;
			 if(pixel < gmin) gmin= pixel;
		 }
	 }

	 // set up everything
	 sum = csum =0.0;
	 n =0;

	 for (k =0; k <=255; k++) 
	 {
		 sum += k * ihist[k]; /* x*f(x) 質量矩*/
		 n += ihist[k]; /* f(x) 質量 */
	 }

	 if (!n) 
	 {
		 // if n has no value, there is problems...
		 //fprintf (stderr, "NOT NORMAL thresholdValue = 160\n");
		 thresholdValue =160;
		 goto L;
	 }

	 // do the otsu global thresholding method
	 fmax =-1.0;
	 n1 =0;
	 for (k =0; k <255; k++) 
	 {
		 n1 += ihist[k];
		 if (!n1) { continue; }
		 n2 = n - n1;
		 if (n2 ==0) { break; }
		 csum += k *ihist[k];
		 m1 = csum / n1;
		 m2 = (sum - csum) / n2;
		 sb = n1 * n2 *(m1 - m2) * (m1 - m2);
		 /* bbg: note: can be optimized. */
		 if (sb > fmax)
		 {
			 fmax = sb;
			 thresholdValue = k;
		 }
	 }

L:
	 for (i =0; i < h; i++) 
	 {
		 np = (unsigned char*)(image->imageData + image->widthStep*i);
		 for (j =0; j < w; j++) 
		 {
			 if(np[j] >= thresholdValue)
				 np[j] =255;
			 else np[j] =0;
		 }
	 }

	 //cout<<"The Threshold of this Image in Otsu is:"<<thresholdValue<<endl;
	 return(thresholdValue);
 }
 /*============================================================================
 =  代碼內容:最大熵閾值分割                                      
 =  修改日期:2009-3-3                                                                                                         
 =  作者:crond123 
 =  博客:http://blog.csdn.net/crond123/
 =  E_Mail:crond123@163.com                                                      
 ===============================================================================*/
 // 計算當前位置的能量熵
 double caculateCurrentEntropy(CvHistogram * Histogram1,int cur_threshold,entropy_state state)
 {
 int start,end;
 int  total =0;
 double cur_entropy =0.0;
 if(state == back)    
     {
         start =0;
         end = cur_threshold;    
     }
 else    
     {
         start = cur_threshold;
         end =256;    
     }    
 for(int i=start;i<end;i++)    
     {
         total += (int)cvQueryHistValue_1D(Histogram1,i);//查詢直方塊的值 P304
     }
 for(int j=start;j<end;j++)
     {
 if((int)cvQueryHistValue_1D(Histogram1,j)==0)
 continue;
 double percentage = cvQueryHistValue_1D(Histogram1,j)/total;
 /*熵的定義公式*/
         cur_entropy +=-percentage*logf(percentage);
 /*根據泰勒展式去掉高次項得到的熵的近似計算公式
         cur_entropy += percentage*percentage;*/        
     }
 return cur_entropy;
 //    return (1-cur_entropy);
 }
 
 //尋找最大熵閾值並分割
 void  MaxEntropy(IplImage *src,IplImage *dst)
 {
     assert(src != NULL);
     assert(src->depth ==8&& dst->depth ==8);
     assert(src->nChannels ==1);
     CvHistogram * hist  = cvCreateHist(1,&HistogramBins,CV_HIST_ARRAY,HistogramRange);//創建一個指定尺寸的直方圖
 //參數含義:直方圖包含的維數、直方圖維數尺寸的數組、直方圖的表示格式、方塊范圍數組、歸一化標志
     cvCalcHist(&src,hist);//計算直方圖
 double maxentropy =-1.0;
 int max_index =-1;
 // 循環測試每個分割點,尋找到最大的閾值分割點
 for(int i=0;i<HistogramBins;i++)    
     {
 double cur_entropy = caculateCurrentEntropy(hist,i,object)+caculateCurrentEntropy(hist,i,back);
 if(cur_entropy>maxentropy)
         {
             maxentropy = cur_entropy;
             max_index = i;
         }
     }
     cout<<"The Threshold of this Image in MaxEntropy is:"<<max_index<<endl;
     cvThreshold(src, dst, (double)max_index,255, CV_THRESH_BINARY);
     cvReleaseHist(&hist);
 }
 /*============================================================================
 =  代碼內容:基本全局閾值法                              
 ==============================================================================*/
 int BasicGlobalThreshold(int*pg,int start,int end)
 {                                           //  基本全局閾值法
 int  i,t,t1,t2,k1,k2;
 double u,u1,u2;    
     t=0;     
     u=0;
 for (i=start;i<end;i++) 
     {
         t+=pg[i];        
         u+=i*pg[i];
     }
     k2=(int) (u/t);                          //  計算此范圍灰度的平均值    
 do 
     {
         k1=k2;
         t1=0;    
         u1=0;
 for (i=start;i<=k1;i++) 
         {             //  計算低灰度組的累加和
             t1+=pg[i];    
             u1+=i*pg[i];
         }
         t2=t-t1;
         u2=u-u1;
 if (t1) 
             u1=u1/t1;                     //  計算低灰度組的平均值
 else 
             u1=0;
 if (t2) 
             u2=u2/t2;                     //  計算高灰度組的平均值
 else 
             u2=0;
         k2=(int) ((u1+u2)/2);                 //  得到新的閾值估計值
     }
 while(k1!=k2);                           //  數據未穩定,繼續
 //cout<<"The Threshold of this Image in BasicGlobalThreshold is:"<<k1<<endl;
 return(k1);                              //  返回閾值
 }
int main()
{
	/*手動設置閥值*/
	IplImage* smoothImgGauss = cvLoadImage("E:\\test.jpg", CV_LOAD_IMAGE_GRAYSCALE);
	IplImage* imgGrey = cvCreateImage(cvGetSize(smoothImgGauss),IPL_DEPTH_8U, 1);
	int w = smoothImgGauss->width, h = smoothImgGauss->height;
	IplImage* binaryImg = cvCreateImage(cvGetSize(smoothImgGauss),IPL_DEPTH_8U, 1);
	cvThreshold(smoothImgGauss,binaryImg,71,255,CV_THRESH_BINARY); 
	//cvNamedWindow("cvThreshold", CV_WINDOW_AUTOSIZE );
	//cvShowImage( "cvThreshold", binaryImg );
	cvSaveImage("E:\\手動設置閥值.bmp",binaryImg);
	cvReleaseImage(&binaryImg);    
	/*---------------------------------------------------------------------------*/
	/*自適應閥值  //計算像域鄰域的平均灰度,來決定二值化的值*/
	IplImage* adThresImg = cvCreateImage(cvGetSize(smoothImgGauss),IPL_DEPTH_8U, 1);
	double max_value=255;
	int adpative_method=CV_ADAPTIVE_THRESH_GAUSSIAN_C;//CV_ADAPTIVE_THRESH_MEAN_C
	int threshold_type=CV_THRESH_BINARY;
	int block_size=3;//閾值的象素鄰域大小
	int offset=5;//窗口尺寸
	cvAdaptiveThreshold(smoothImgGauss,adThresImg,max_value,adpative_method,threshold_type,block_size,offset);
	//cvNamedWindow("cvAdaptiveThreshold", CV_WINDOW_AUTOSIZE );
	cvSaveImage("E:\\自適應閥值.bmp",adThresImg);
	//cvShowImage( "cvAdaptiveThreshold", adThresImg );
	cvReleaseImage(&adThresImg);

	/*---------------------------------------------------------------------------*/
	/*最大熵閥值分割法*/    
	IplImage* imgMaxEntropy = cvCreateImage(cvGetSize(imgGrey),IPL_DEPTH_8U,1);
	MaxEntropy(smoothImgGauss,imgMaxEntropy);
	//cvNamedWindow("MaxEntroyThreshold", CV_WINDOW_AUTOSIZE );
	//cvShowImage( "MaxEntroyThreshold", imgMaxEntropy );//顯示圖像
	cvSaveImage("E:\\最大熵閥值分割.bmp",imgMaxEntropy);
	cvReleaseImage(&imgMaxEntropy ); 
	
	/*---------------------------------------------------------------------------*/
	/*基本全局閥值法*/
	IplImage* imgBasicGlobalThreshold = cvCreateImage(cvGetSize(imgGrey),IPL_DEPTH_8U,1);
	IplImage* srcImgGrey = cvCreateImage(cvGetSize(imgGrey),IPL_DEPTH_8U,1);
	cvCopyImage(srcImgGrey,imgBasicGlobalThreshold);
	int  pg[256],i,thre;    
	for (i=0;i<256;i++) pg[i]=0;
	for (i=0;i<imgBasicGlobalThreshold->imageSize;i++)      //  直方圖統計
		pg[(BYTE)imgBasicGlobalThreshold->imageData[i]]++;    
	thre = BasicGlobalThreshold(pg,0,256);    //  確定閾值
	cout<<"The Threshold of this Image in BasicGlobalThreshold is:"<<thre<<endl;//輸出顯示閥值
	cvThreshold(imgBasicGlobalThreshold,imgBasicGlobalThreshold,thre,200,CV_THRESH_BINARY);  //  二值化    
	//cvNamedWindow("BasicGlobalThreshold", CV_WINDOW_AUTOSIZE );
	//cvShowImage( "BasicGlobalThreshold", imgBasicGlobalThreshold);//顯示圖像
    cvSaveImage("E:\\基本全局閥值法.bmp",imgBasicGlobalThreshold);
	cvReleaseImage(&imgBasicGlobalThreshold);
	/*---------------------------------------------------------------------------*/
	/*OTSU*/
	IplImage* imgOtsu = cvCreateImage(cvGetSize(imgGrey),IPL_DEPTH_8U,1);
	cvCopyImage(srcImgGrey,imgOtsu);
	int thre2;
	thre2 = otsu2(imgOtsu);
	cout<<"The Threshold of this Image in Otsu is:"<<thre2<<endl;//輸出顯示閥值
	cvThreshold(imgOtsu,imgOtsu,thre2,200,CV_THRESH_BINARY);  //  二值化    
	//cvNamedWindow("imgOtsu", CV_WINDOW_AUTOSIZE );
	//cvShowImage( "imgOtsu", imgOtsu);//顯示圖像    
	cvSaveImage("E:\\OTSU.bmp",imgOtsu);
	cvReleaseImage(&imgOtsu);
	/*---------------------------------------------------------------------------*/
	/*上下閥值法:利用正態分布求可信區間*/
	IplImage* imgTopDown = cvCreateImage( cvGetSize(imgGrey), IPL_DEPTH_8U, 1 );
	cvCopyImage(srcImgGrey,imgTopDown);
	CvScalar mean ,std_dev;//平均值、 標准差
	double u_threshold,d_threshold;
	cvAvgSdv(imgTopDown,&mean,&std_dev,NULL);    
	u_threshold = mean.val[0] +2.5* std_dev.val[0];//上閥值
	d_threshold = mean.val[0] -2.5* std_dev.val[0];//下閥值
	//u_threshold = mean + 2.5 * std_dev; //錯誤
	//d_threshold = mean - 2.5 * std_dev;
	cout<<"The TopThreshold of this Image in TopDown is:"<<d_threshold<<endl;//輸出顯示閥值
	cout<<"The DownThreshold of this Image in TopDown is:"<<u_threshold<<endl;
	cvThreshold(imgTopDown,imgTopDown,d_threshold,u_threshold,CV_THRESH_BINARY_INV);//上下閥值
	//cvNamedWindow("imgTopDown", CV_WINDOW_AUTOSIZE );
	//cvShowImage( "imgTopDown", imgTopDown);//顯示圖像  
	cvSaveImage("E:\\上下閥值法.bmp",imgTopDown);
	cvReleaseImage(&imgTopDown);
}

 再次,全局閾值分割C++:

/************************************************************************/
/* 全局閾值分割  自動求取閾值        */
/************************************************************************/
//自動求取閾值,增加對場景的適應性
//只需求取一次,之后就可以一直使用
#include<cv.h>
#include <highgui.h>
#include <iostream>
#include <math.h>
using namespace std;
int main(){
	IplImage * image,* image2;
	image = cvLoadImage("E:\\111.jpg",0);
	cvNamedWindow("image",1);
	cvShowImage("image",image);
	image2 = cvCreateImage(cvSize(image->width,image->height),image->depth,1);
	double T = 0;
	double dT0 = 1.0;//閾值求取結束標志
	double dT = 255.0;

	//求取平均灰度,作為閾值T的初始值T0
	int i, j;
	double T0 = 0,T1 = 0,T2 = 0;//初始閾值
	int count1,count2;
	unsigned char * ptr,*dst;
	for (i = 0 ; i< image->height ; i++)
	{
		for (j =0 ; j < image->width;j++)
		{
			ptr = (unsigned char *)image->imageData + i*image->widthStep + j;
			T0 += ((double)(*ptr))/image->width/image->height;
		}
	}
	cout<<"T0:     "<<T0<<endl;
	T = (int)(T0 + 0.5); 
	//計算T兩側的灰度平均值,然后把二者的均值賦值給T
	while (dT > dT0)
	{

		T1 = 0;
		T2 = 0;
		count1 = 0;
		count2 = 0;
		for (i = 0 ; i< image->height ; i++)
		{
			for (j =0 ; j < image->width;j++)
			{
				ptr = (unsigned char *)image->imageData + i*image->widthStep + j;
				if (*ptr > T)
				{
					T1 += ((double)(*ptr))/image->width/image->height;
					count1++;
				} 
				else if(*ptr < T)
				{
					T2 +=  ((double)(*ptr))/image->width/image->height;
					count2++;
				}
			}
		}

		T1 = T1*image->width*image->height/count1;
		T2 = T2*image->width*image->height/count2;
		dT = fabs(T - (T1 + T2)/2);

		cout<<"T1"<<T1<<endl;
		cout<<"T2"<<T2<<endl;
		cout<<"dT  " << dT<<endl;
		T = (T1 + T2)/2;
		cout<<"T:     "<<T<<endl;
	}



	//根據求取的閾值進行分割
	for (i = 0 ; i< image2->height ; i++)
	{
		for (j =0 ; j < image2->width;j++)
		{
			ptr = (unsigned char *)image->imageData + i*image->widthStep + j;
			dst = (unsigned char *)image2->imageData+i*image2->widthStep+j;
			if (*ptr > T)
			{
				*dst = 255;
			} 
			else
			{
				*dst =0;
			}
		}
	}

	cvNamedWindow("image2",1);
	cvShowImage("image2",image2);
	cvSaveImage("E:\\image\\dowels2.tif",image2);
	cvWaitKey(0);
	return 0;
}

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM