Ostu最大类间方差法的C++实现

一、Ostu的原理

最大类间方差法是由日本学者大津(Nobuyuki Ostu)在1979年提出的,该方法根据计算公式自动计算分割单域值,是一种根据灰度图像自动计算阈值的方法。它按照灰度图像的灰度值等级属性,将图像256个灰度级自动划分成背景点和目标点两部分,即计算出一个合适的中间值k,将图像256个灰度级分为两部分。算法分类的原理是使背景和目标之间的类间方差最大,因为背景和目标之间的类间方差越大,说明构成图像的两部分的差别越大,错分的可能性越小。

类间方法 g g g的计算公式为:
g = w 1 ∗ w − 2 ∗ ( u 1 − u 2 ) 2 g=w_1*w-2*(u_1-u_2)^2 g=w1w2u1u22
其中: w 1 w_1 w1为目标像素点占整幅图像的比例, u 1 u_1 u1为其平均灰度, w 2 w_2 w2为背景像素点占整幅图像的比例, u 2 u_2 u2为其平均灰度。通过公式计算得到的 g g g也就是类间方差最大值,即这副图像的自适应阈值。

二、基于OpenCV的C++程序

int otsu(Mat image)
{
	int width = image.rows, height = image.cols, threshold = 0;
	int pixelCount[256];
	float pixelPro[256];

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

	//统计灰度级中每个像素在整幅图像中的个数
	for (int i = 0; i < width; i++)
	{
		for (int j = 0; j < height; j++)
		{
			pixelCount[image.at<uchar>(i,j)]++;
		}
	}

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

	//经典ostu算法,得到前景和背景的分割
	//遍历灰度级[0,255],计算出方差最大的灰度值,为最佳阈值
	float w0, w1, u0tmp, u1tmp, u0, u1, u, deltaTmp, deltaMax = 0;
	for (int i = 0; i < 256; i++)
	{
		w0 = w1 = u0tmp = u1tmp = u0 = u1 = u = deltaTmp = 0;
		for (int 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;
}
void main()
{
	cv::Mat diff_image, binary_image;
	diff_image = imread("..//xx", 0);  //读取灰度图
	int threshold = otsu(diff_image);  //得到阈值
	cv::threshold(diff_image, binary_image, threshold, 255, THRESH_BINARY);  //二值化
	imshow("binary_image", binary_image);
}

你可能感兴趣的:(C++与Python,c++,opencv,计算机视觉)