【数字图像处理】(一)二值化

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/fangjin_kl/article/details/41146293

全局二值法

1.迭代法

迭代法
迭代法是基于逼近的思想,其步骤如下:
(1)求出图象的最大灰度值和最小灰度值,分别记为Rmax和Rmin,令阈值T=(Rmax+Rmin)/2。
(2)根据阈值T将图象的平均灰度值分成两组R1和R2。
(3)分别求出两组的平均灰度值μ1和μ2。
(4)求出新阈值T=(μ1+μ2)/2。

 

2.最大类间方差法OTSU

 

#include "MyIPL.h"

//手动设定阈值
void thresholdSimple(Mat &src,Mat &dst,int threshold )
{
	for (int i=0;i<src.rows;i++)
	{
		for (int j=0;j<src.cols;j++)
		{
			dst.at<uchar>(i,j) = (src.at<uchar>(i,j)>threshold)?0:255;
		}
	}
}


	/*======================================================================*/
	/* 迭代法*/
	/*======================================================================*/
	// nMaxIter:最大迭代次数;nDiffRec:使用给定阀值确定的亮区与暗区平均灰度差异值;
int IterThreshold(Mat img, int nMaxIter, int& iDiffRec)  //阀值分割:迭代法
{
	//图像信息
	int height = img.rows;
	int width = img.cols;
	//int step = width;
	//uchar *data = (uchar*)img->imageData;

	iDiffRec =0;
	int F[256]={ 0 }; //直方图数组
	int iTotalGray=0;//灰度值和
	int iTotalPixel =0;//像素数和
	uchar 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 = img.at<uchar>(j,i);
			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(Mat image)
{
	int w = image.cols;
	int h = image.rows;

	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++) 
	{
		for (j =0; j < w; j++) 
		{
			pixel = image.at<uchar>(i,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(image.at<uchar>(i,j) >= thresholdValue)
				np[j] =255;
			else np[j] =0;
		}
	}

	//cout<<"The Threshold of this Image in Otsu is:"<<thresholdValue<<endl;
	return(thresholdValue);
}


 

展开阅读全文

没有更多推荐了,返回首页