详细及易读懂的 大津法(OTSU)原理 和 算法实现

OTSU算法原理简述:

最大类间方差是由日本学者大津(Nobuyuki Otsu)于1979年提出,是一种自适应的阈值确定方法。算法假设图像像素能够根据阈值,被分成背景[background]和目标[objects]两部分。然后,计算该最佳阈值来区分这两类像素,使得两类像素区分度最大。

公式:  记 M = 256 单通道灰度分级 Sum = 像素总数

  1. 背景像素占比 \omega1 = \frac{N1}{Sum}  
  2. 前景像素占比\omega2 = 1- \omega1 = \frac{N2}{Sum} =1- \frac{N1}{Sum}
  3. 背景的平均灰度值\mu 1 = \sum_{i = 0}^{t} i *Pr(i | C_{0}) = \sum_{i = 0}^{t} i *Pi / \sum_{i = 0}^{t} Pi = \frac{\mu(t))}{\omega_{1}}
  4. 前景的平均灰度值\mu 2 = \sum_{i = t+1}^{M - 1} i *Pr(i | C_{1}) = \sum_{i = t+1}^{M - 1} i *Pi / \sum_{i = t+1}^{M - 1} Pi = \frac{\mu - \mu(t))}{\omega _{2}}
  5. 0~M灰度区间的灰度累计值\mu = \mu1*\omega 1 + \mu2*\omega 2
  6. 类间方差:g = \omega 1 * (\mu - \mu1)^{2} + \omega 2 * (\mu - \mu2)^{2}
  7. 将公式3.4.5带入公式6 可得最终简化公式: g = \omega 1 * \omega2 * (\mu1 - \mu2)^{2}

代码:

#include <opencv2\opencv.hpp>
#include <iostream>
#include <time.h>
using namespace std;
using namespace cv;
 
int myOtsu(Mat & src)
{
	int th;
	const int GrayScale = 256;	//单通道图像总灰度256级
	int pixCount[GrayScale] = {0};//每个灰度值所占像素个数
	int pixSum = src.cols * src.rows;//图像总像素点
	float pixPro[GrayScale] = {0};//每个灰度值所占总像素比例
	float w0, w1, u0tmp, u1tmp, u0, u1, deltaTmp, deltaMax = 0; 
 
	for(int i = 0; i < src.cols; i++)
	{
		for(int j = 0; j < src.rows; j++)
		{
			pixCount[src.at<uchar>(j,i)]++;//统计每个灰度级中像素的个数  
		}
	}
 
	for(int i = 0; i < GrayScale; i++)
	{
		pixPro[i] = pixCount[i] * 1.0 / pixSum;//计算每个灰度级的像素数目占整幅图像的比例  
	}
 
	for(int i = 0; i < GrayScale; i++)//遍历所有从0到255灰度级的阈值分割条件,测试哪一个的类间方差最大
	{
		w0 = w1 = u0tmp = u1tmp = u0 = u1 = deltaTmp = 0;  
		for(int j = 0; j < GrayScale; j++)
		{
			if(j <= i)//背景
			{
				w0 += pixPro[j];
				u0tmp += j * pixPro[j]; 
			}
			else//前景
			{
				w1 += pixPro[j];
				u1tmp += j * pixPro[j];
			}
		}
		u0 = u0tmp / w0;
		u1 = u1tmp / w1;
		deltaTmp = (float)(w0 *w1* pow((u0 - u1), 2)); //类间方差公式 g = w1 * w2 * (u1 - u2) ^ 2
		if(deltaTmp > deltaMax) 
		{
			deltaMax = deltaTmp;
			th = i;  
		}  
	}
	return th;
}
 
int main()
{
	Mat src = imread("lena.jpg",IMREAD_GRAYSCALE);//单通道读取图像
	/*my_dst: 自己实现的大津法 得到的处理图像
	otsu_dst:opencv自带的大津法 得到的处理图像
	sub:两个处理图像相差图
	*/
	Mat my_dst, otsu_dst, sub;							
	/*my_th: 自己实现的大津法 得到的最大类件方差 即阈值
	th:opencv自带的大津法 得到的最大类件方差 即阈值
	*/
	int my_th, th;
 
	/*计算开销时间,对比两个算法效率*/
	long my_start = clock();  //开始时间
	{
		my_th = myOtsu(src);
		threshold(src,my_dst,my_th,255,CV_THRESH_BINARY);
	}
	long my_finish = clock();   //结束时间
	long my_t = my_finish-my_start;
	printf("The run time is:%9.3lf\n", my_t, "ms!\n"); //输出时间
	cout << "myOtsu threshold >> " << my_th << endl;
 
	long otsu_start = clock();  //开始时间
	{
		th = threshold(src,otsu_dst,0,255,CV_THRESH_OTSU);
	}
	long otsu_finish = clock();   //结束时间
	long t = my_finish-my_start;
	printf("The run time is:%9.3lf\n",  (double) t / CLOCKS_PER_SEC, "ms!\n"); //输出时间
	cout << "Otsu threshold >> " << th << endl;
 
	subtract(otsu_dst,my_dst,sub);//两图像相减
	imshow("src",src);
	imshow("myOtsu",my_dst);
	imshow("Otsu",otsu_dst);
	imshow("Sub",sub);
	waitKey();
	system("pause");
	return 0;
}

原图:用的是lena

得到测试结果和图像

结论:可以看到自己实现的otsu和opencv自带的自适应阈值算法所得效果和效率相同。

最后:欢迎大家的批评,很高心与大家分享,谢谢大家。

 

 

  • 2
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值