zjx
zjx
发布于 2025-10-22 / 5 阅读
0
0

Otsu阈值处理

大津二值化算法(Otsu’s Method)

大津算法,也被称作最大类间方差法,是一种可以自动确定二值化中阈值的算法。

从类内方差和类间方差的比值计算得来:

  1. 小于阈值t的类记作0,大于阈值t的类记作1$

  2. w0和w1是被阈值t分开的两个类中的像素数占总像素数的比率(满足w0+w1=1)

  3. S02,S12是这两个类中像素值的方差

  4. M0,M1是这两个类的像素值的平均值

即:

  1. 类内方差:

    S_w^2=w_0·S_0^2+w_1·S_1^2
  2. 类间方差:

    S_b^2=w_0·(M_0-M_t)^2+w_1·(M_1-M_t)^2
  3. 图像所有像素的方差:

    S_t^2=S_w^2+S_b^2=常数

根据以上的式子,我们用以下的式子计算分离度X:

X=\frac {S_b^2} {S_w^2}=\frac {S_b^2} {S_t^2-S_w^2}

也就是说

\mathop{\arg\max}\limits_{t} X = \mathop{\arg\max}\limits_{t} S_b^2

换言之,如果使S_b^2=w_0·w_1·(M_0-M_1)^2最大,就可以得到最好的二值化阈值t

void solution4::otsuMethod(Mat& src, Mat& dst)
{
	if (src.channels() != 1)
	{
		dst = src.clone();
		cout << "input src's channel is not 1" << endl;
		return;
	}
	double totalnum = src.rows * src.cols;
	int otsu_th = 0;
	double max_st = 0.0;
	for (int i = 0; i < 256; i++)
	{
		int t0 = 0;//图像小于i的像素点数目
		int t1 = 0;//图像大于i的像素点数目

		int s0 = 0;//图像小于i的像素点灰度和
		int s1 = 0;//图像大于i的像素点灰度和

		double m0 = 0.0;//图像小于i的像素点的平均灰度
		double m1 = 0.0;//图像大于i的像素点的平均灰度

		double w0 = 0.0;//图像小于i的像素点数目/总数
		double w1 = 0.0;//图像大于i的像素点数目/总数
		for (int row = 0; row < src.rows; row++)
		{
			for (int col = 0; col < src.cols; col++)
			{
				int grayval = src.at<uchar>(row, col);
				if (grayval < i)
				{
					t0++;
					s0 += grayval;
				}
				else
				{
					t1++;
					s1 += grayval;
				}
			}
		}

		w0 = t0 / totalnum;
		w1 = t1 / totalnum;

		if (w0 <= 0.0 || w1 <= 0.0)
		{
			continue;
		}

		m0 = s0 / t0;
		m1 = s1 / t1;

		double st = w0 * w1 * abs(m1 - m0);
		
		if (st > max_st)
		{
			max_st = st;
			otsu_th = i;
		}

	}
	Mat dst_otsu;

	threshold(src, dst, otsu_th, 255, THRESH_BINARY);
	threshold(src, dst_otsu, 0, 255, THRESH_BINARY|THRESH_OTSU);
	getchar();
}


评论