OSTU大律法二值化原理

介绍

Ostu方法又名最大类间差方法,通过统计整个图像的直方图特性来实现全局阈值T的自动选取,其算法步骤为:

1) 先计算图像的直方图,即将图像所有的像素点按照0~255共256个bin,统计落在每个bin的像素点数量

2) 归一化直方图,也即将每个bin中像素点数量除以总的像素点

3) i表示分类的阈值,也即一个灰度级,从0开始迭代

4) 通过归一化的直方图,统计0~i 灰度级的像素(假设像素值在此范围的像素叫做前景像素) 所占整幅图像的比例w0,并统计前景像素的平均灰度u0;统计i~255灰度级的像素(假设像素值在此范围的像素叫做背景像素) 所占整幅图像的比例w1,并统计背景像素的平均灰度u1;

5) 计算前景像素和背景像素的方差 g = w0*w1*(u0-u1) (u0-u1)

6) i++;转到4),直到i为256时结束迭代

7)将最大g相应的i值作为图像的全局阈值

代码:

#include 
#include 
#include 
#include 
using namespace cv;
using namespace std;
//输入图像,输出阈值
int otsu(IplImage *image)
{
	assert(NULL != image);


	int width = image->width;
	int height = image->height;
	int x = 0, y = 0;
	int pixelCount[256];
	float pixelPro[256];
	int i, j, pixelSum = width * height, threshold = 0;


	uchar* data = (uchar*)image->imageData;


	//初始化
	for (i = 0; i < 256; i++)
	{
		pixelCount[i] = 0;
		pixelPro[i] = 0;
	}


	//统计灰度级中每个像素在整幅图像中的个数
	for (i = y; i < height; i++)
	{
		for (j = x; j < width; j++)
		{
			pixelCount[data[i * image->widthStep + j]]++;
		}
	}




	//计算每个像素在整幅图像中的比例
	for (i = 0; i < 256; i++)
	{
		pixelPro[i] = (float)(pixelCount[i]) / (float)(pixelSum);
	}


	//经典ostu算法,得到前景和背景的分割
	//遍历灰度级[0,255],计算出方差最大的灰度值,为最佳阈值
	float w0, w1, u0tmp, u1tmp, u0, u1, u, deltaTmp, deltaMax = 0;
	for (i = 0; i < 256; i++)
	{
		w0 = w1 = u0tmp = u1tmp = u0 = u1 = u = deltaTmp = 0;


		for (j = 0; j < 256; j++)
		{
			if (j <= i) //背景部分
			{
				//以i为阈值分类,第一类总的概率
				w0 += pixelPro[j];
				u0tmp += j * pixelPro[j];
			}
			else       //前景部分
			{
				//以i为阈值分类,第二类总的概率
				w1 += pixelPro[j];
				u1tmp += j * pixelPro[j];
			}
		}


		u0 = u0tmp / w0;		//第一类的平均灰度
		u1 = u1tmp / w1;		//第二类的平均灰度
		u = u0tmp + u1tmp;		//整幅图像的平均灰度
		//计算类间方差
		deltaTmp = w0 * (u0 - u)*(u0 - u) + w1 * (u1 - u)*(u1 - u);
		//找出最大类间方差以及对应的阈值
		if (deltaTmp > deltaMax)
		{
			deltaMax = deltaTmp;
			threshold = i;
		}
	}
	//返回最佳阈值;
	return threshold;
}


int main(int argc, char* argv[])
{
	IplImage* srcImage = cvLoadImage("1.jpg", 0);
	assert(NULL != srcImage);


	cvNamedWindow("src");
	cvShowImage("src", srcImage);


	IplImage* biImage = cvCreateImage(cvGetSize(srcImage), 8, 1);


	//计算最佳阈值
	int threshold = otsu(srcImage);
	//对图像二值化
	cvThreshold(srcImage, biImage, threshold, 255, CV_THRESH_BINARY);


	cvNamedWindow("binary");
	cvShowImage("binary", biImage);


	cvWaitKey(0);


	cvReleaseImage(&srcImage);
	cvReleaseImage(&biImage);
	cvDestroyWindow("src");
	cvDestroyWindow("binary");


	return 0;
}

缺陷

OSTU算法在处理光照不均匀的图像的时候,效果会明显不好,因为利用的是全局像素信息。

你可能感兴趣的:(图像二值化)