RISC-V MCU中文社区

【分享】 使用Otsu阈值算法将灰度图像二值化

发表于 全国大学生集成电路创新创业大赛 2021-07-23 22:20:10
0
2162
1

    大家好,我们是大黄蜂队,编号是 CICC1948。前一篇帖子(https://www.rvmcu.com/community-topic-id-856.html分享了模板匹配的目标追踪算法,其中提到了需要利用心理学公式将 RGB 图像转为灰度图像。这里就分享一种能够从灰度图象中求出一个灰度阈值,再根据这个阈值将图片进行二值化(所有像素点只包含纯黑和纯白)的算法 —— Otsu 阈值算法。

    Otsu 算法是由日本学者OTSU于1979年提出的一种对图像进行二值化的高效算法,又称“最大类间方差法”。当我们对一个图象进行二值化操作的时候,需要根据一项灰度阈值来判决每个像素点应该被视作纯黑还是纯白,即利用此阈值将原图像分成前景、背景两个图象。不同阈值对于前景和背景图象的划分不同,一般来说,前景和背景图象的差别越大,表明划分的效果越好。在 Otsu 算法中,以类间方差来衡量背景和前景图象的差别:类间方差越大,表示背景和前景图象的差别越大。因此,Otsu算法的最终目的就是求得一个最佳灰度阈值,使背景与前景的类间方差最大。

     为了找到这个灰度阈值,我们只需要遍历从0到255之间的每一种阈值,计算出根据此阈值划分得到的前景和背景图象的类间方差(共256个),找到其中最大的类间方差,其对应阈值即划分图象的最佳灰度阈值。

    对于图象I(x,y),前景和背景的分割阈值记为T,属于前景的像素点数占整幅图像的比例记为ω0,其平均灰度为μ0;属于背景的像素点数占整幅图像的比例记为ω1,其平均灰度为μ1。图象的总平均灰度记为μ,类间方差记为g。根据以下公式,我们可以将类间方差g计算出来:  

    在用程序实现图像的灰度阈值计算时,就是用上述遍历的方式,这里贴上一段代码,仅供参考:


int otsuThreshold(IplImage *frame)
{
    const int GrayScale = 256;
	int width = frame->width;
	int height = frame->height;
	int pixelCount[GrayScale];                 // 256种灰度值;
	float pixelPro[GrayScale];                
	int i, j, pixelSum = width * height, threshold = 0;   // 用于循环
	uchar* data = (uchar*)frame->imageData;    
                                               // uchar是无符号的,于是数值范围为0~255,

	for(i = 0; i < GrayScale; i++)             // 所有元素置零
	{
		pixelCount[i] = 0;
		pixelPro[i] = 0;
	}
 
	//统计灰度级中每个像素在整幅图像中的个数
	for(i = 0; i < height; i++)
	{
		for(j = 0;j < width;j++)
		{
			pixelCount[(int)data[i * width + j]]++;
		}
	}
	
	//计算每个像素在整幅图像中的比例
	for(i = 0; i < GrayScale; i++)
	{
		pixelPro[i] = (float)pixelCount[i] / pixelSum;
	}
 
	//遍历灰度级[0,255]

	float w0, w1, u0tmp, u1tmp, u0, u1, u, 
			deltaTmp, deltaMax = 0;
	for(i = 0; i < GrayScale; i++)
	{
		w0 = w1 = u0tmp = u1tmp = u0 = u1 = u = deltaTmp = 0;
		for(j = 0; j < GrayScale; j++)
		{
			if(j <= i)   //背景部分
			{
				w0 += pixelPro[j];         
				u0tmp += j * pixelPro[j]; 
			}
			else   //前景部分
			{
				w1 += pixelPro[j];
				u1tmp += j * pixelPro[j];
			}
		}
		u0 = u0tmp / w0;                   
		u1 = u1tmp / w1;                   
		u = u0tmp + u1tmp;
		deltaTmp =                          
			w0 * pow((u0 - u), 2) + w1 * pow((u1 - u), 2);   // pow(x,y) 返回x的y次幂
		if(deltaTmp > deltaMax)
		{
			deltaMax = deltaTmp;
			threshold = i;
		}
	}
	return threshold;
}




    

喜欢1
用户评论
wxz

wxz 实名认证

懒的都不写签名

积分
问答
粉丝
关注
  • RV-STAR 开发板
  • RISC-V处理器设计系列课程
  • 培养RISC-V大学土壤 共建RISC-V教育生态
RV-STAR 开发板