阈值分割总结

OSTU C++实现:

#include 
#include "cv.h"
#include "highgui.h"
#include  
#include 
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;iimageData+src->widthStep*i;
		for(int j=0;jmaxVariance) {
			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;iimageData+src->widthStep*i;
		for(int j=0;jmaxVariance) {
			maxVariance=variance;
			threshold=i;
		}
	}

	return threshold;
}
#include 
#include 
#include 
#pragma comment(lib,"cv210d.lib")
#pragma comment(lib,"cxcore210d.lib")
#pragma comment(lib,"highgui210d.lib")

#include 
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 
#include "cv.h"
#include "highgui.h"
#include  
#include 
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;iiMaxGrayValue)
				iMaxGrayValue = bt;
			F[bt]++;
		}
	}

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

	for(int a=0;(abs(iThrehold-iNewThrehold)>0.5)&&a 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:"<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;imaxentropy)
         {
             maxentropy = cur_entropy;
             max_index = i;
         }
     }
     cout<<"The Threshold of this Image in MaxEntropy is:"<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;iimageSize;i++)      //  直方图统计
		pg[(BYTE)imgBasicGlobalThreshold->imageData[i]]++;    
	thre = BasicGlobalThreshold(pg,0,256);    //  确定阈值
	cout<<"The Threshold of this Image in BasicGlobalThreshold is:"<

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

/************************************************************************/
/* 全局阈值分割  自动求取阈值        */
/************************************************************************/
//自动求取阈值,增加对场景的适应性
//只需求取一次,之后就可以一直使用
#include
#include 
#include 
#include 
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:     "< 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"<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;
}

 

 

 

 

 

你可能感兴趣的:(阈值分割总结)