【Opencv】阈值化

阈值化

1. 阈值化简介

阈值化是一种图像分割的方法,用于从一幅图片里面提取我们需要的部分。比如分离图像的前景和背景。其基本原理就是利用一幅图像各个部分之间的像素差异,通过设定一个阈值,截取出我们需要的部分。阈值化有以下三种方法:固定阈值化、自适应阈值化、otsus’s阈值化(最大类间方差)

2. 固定阈值化

固定阈值化是最简单的一种方法,通过设定阈值,来处理图像中的像素点。

2.1函数原型

double cv::cuda::threshold	(	
	InputArray 	src,
	OutputArray 	dst,
	double 	thresh,
	double 	maxval,
	int 	type,
	) 

第一个参数:输入图像
第二个参数:输出参数
第三个参数:阈值
第四个参数:最大值。当第五个参数取CV_THRESH_BINARY或者CV_THRESH_BINARY_INV的时候,处理高于或者低于阈值的像素变成最大值
第五个参数:用于控制阈值化的类型

2.2 阈值化类型

第一条曲线:原始数据曲线,中间的黑色线表示阈值,下面五张图表示固定阈值化的五种类型。

第二条曲线:二进制阈值化。对应Opencv参数为THRESH_BINARY。其作用是像素值大于阈值的时候,把这个像素变成最大值。像素值低于阈值的时候,把这个像素变成0

第三条曲线:反二进制阈值化。对应的Opencv参数为THRESH_BINARY_INV,与THRESH_BINARY参数正好相反。当像素值大于阈值的时候,把这个像素变成0,。像素值低于阈值的时候,把这个像素变成最大值。

第四条曲线:截断阈值化。对应的Opencv参数为THRESH_TRUNC。当像素值大于阈值的时候,把数据变成阈值。像素值小于阈值的时候保持不变。

第五条曲线:反阈值化为0。对应的参数为THRESH_TOZERO。当像素值大于阈值的时候,把数据变成0,小于阈值的时候不变。

第六条曲线:阈值化为0。对应的参数为THRESH_TOZERO_INV。当像素值小于阈值的时候,把数据变成0。大于阈值的时候不变。

2.3程序举例

Mat m = imread("1.jpg",0);
Mat n;
threshold(m, n, 100, 255, THRESH_BINARY_INV);

原始图和阈值化之后的效果图
在这里插入图片描述

3. 自适应阈值化

3.1 用途

自适应阈值化是一种阈值不固定的阈值化方法。图像中每一个像素都有它不同的阈值。这个阈值与像素及其周围的点决定。

自适应阈值化能够解决从背景颜色亮度不一的图片中提取有效数据的问题。比如下面这张图片,可以看出由于拍摄角度等原因,获取到的图片亮度不一,如果使用固定阈值化的方法处理背景色,会丢失很多有用的东西。
在这里插入图片描述
下图是使用固定阈值化,type为二进制阈值的效果:
在这里插入图片描述
而如果使用自适应阈值化,让每个像素都根据自己周围环境调整阈值,会得到一个比较好的效果。

在这里插入图片描述

3.2 实现原理

自适应阈值化有两种设置像素阈值的方法。

一种是采用平均值的方法,即是选定一定大小的邻域范围,比如5。那么这个像素的阈值就有他的邻域5x5范围内像素的平均值。利用这个阈值做二进制阈值处理。

另外一种方法是采用高斯函数的方法,相当于对邻域做加权平均。因为高斯函数具有靠近中间权重大,四边权重小的特点。利用高斯函数作为权重,对邻域范围求加权平均,得到的结果就是阈值。

使用自适应阈值能够根据图像的背景色自动调整阈值大小。在不同区域范围具有不同的阈值。具有亮度高的区域阈值大,亮度低的区域阈值小的特点。

3.3 函数原型

void cv::adaptiveThreshold	(	
	InputArray 	src,
	OutputArray 	dst,
	double 	maxValue,
	int 	adaptiveMethod,
	int 	thresholdType,
	int 	blockSize,
	double 	C 
)	

第一个参数:原图
第二个参数:处理之后的图
第三参数:用于二进制阈值化处理的最大值
第四个参数:自适应类型。有两个参数可以选择。ADAPTIVE_THRESH_MEAN_C或者ADAPTIVE_THRESH_GAUSSIAN_C两种,分别对应前文所述的平均值方法和高斯方法,求具体每个像素的阈值范围。
第五个参数:阈值类型,只能选择THRESH_BINARY和THRESH_BINARY_INV。
第六个参数:邻域尺寸,如5对应5x5的矩形邻域
第七个参数:用于调整图像的阈值。求阈值的时候,相当于先让邻域的像素减去C,再做加权平均或者平均。

3.4 用法举例
Mat m = imread("2.jpg",0);
	Mat n;
	adaptiveThreshold(m, n, 255.0, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 11,2);
	
	imshow("n",n);

4.otsus’s阈值化

4.1 otsus’s阈值化简介

otsus’s阈值化也叫做大津法或者最大类间方差。是一种用于估计图像前景提取的阈值的方法。比如一幅图片,对像素点分布做了统计,发现他是一个双峰分布的,通过最大类间方差的方法,就能够利用这个分布统计图,计算出最佳的阈值该选在什么地方。
在这里插入图片描述

4.2 otsus’s 原理

最大类间方差,顾名思义,就是要计算类间方差最大时候的阈值位置。我们假设这个阈值把双峰曲线分为A类和B类。假设一共有N个像素点,阈值为t,灰度值区间为0-255,Ni表示灰度为0的像素点的个数。Pi表示灰度为0的像素点的比例
具体公式为:
δ b 2 ( t ) = w 0 ( u 0 − u t ) 2 + w 1 ( u 1 − u t ) 2 \delta _b^2(t)=w_0(u_0-u_t)^2+w_1(u_1-u_t)^2 δb2(t)=w0(u0ut)2+w1(u1ut)2
其中
(1) δ b 2 ( t ) \delta _b^2(t) δb2(t)表示阈值为t的时候的类间方差
(2) w 0 w_0 w0表示A类像素点的比例(灰度小于阈值的点),公式为
w 0 = ∑ i = 0 t P i = ∑ i = 0 t N i N w_0=\sum_{i=0}^{t}P_i=\sum_{i=0}^{t}\frac{N_i}{N} w0=i=0tPi=i=0tNNi
(3) w 1 w_1 w1表示B类像素点所占的比例(灰度大于阈值的点),公式为
w 0 = ∑ i = t 255 P i = ∑ i = 0 t N i N w_0=\sum_{i=t}^{255}P_i=\sum_{i=0}^{t}\frac{N_i}{N} w0=i=t255Pi=i=0tNNi
(4) u 0 u_0 u0表示类像素点的平均灰度,公式为
u 0 = ∑ i = 0 t P i ∗ i w 0 u_0=\sum_{i=0}^{t} \frac{Pi*i}{w0} u0=i=0tw0Pii
(5) u 1 u_1 u1表示A类像素点的平均灰度,公式为
u 1 = ∑ i = t N P i ∗ i w 1 u_1=\sum_{i=t}^{N} \frac{Pi*i}{w1} u1=i=tNw1Pii
(6) u t u_t ut表示全部像素的评价灰度,公式为
u t = ∑ i = 0 N P i ∗ i u_t=\sum_{i=0}^{N} Pi*i ut=i=0NPii
当i=0到255做遍历计算,求得 δ b 2 ( t ) \delta _b^2(t) δb2(t)最大时候,相应的t就是阈值

4.3 otsus’s 算法Opencv实现

Opencv中有一个特定的参数,可以用来求这个阈值,使用方法如下:

threshold(m, n, 0, 255, THRESH_BINARY | THRESH_OTSU);

与固定化阈值计算方法是一致的,不过不必书写阈值,只需要在后面类型中加入一个THRESH_OTSU参数即可自动计算该阈值

4.4 otsus’s 算法实现

写了一段基于c++和opencv的算法代码,相当于4.3参数的具体实现方法,可以参考。

#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
	Mat m = imread("1.jpg",0);
	Mat n;
	//01创建用来统计图像中各个灰度值的数量以及比例的数组
	int nNum[256];
	double nPro[256];

	//定义A组比例,B组比例,A组平均灰度,B组平均灰度,总的平均灰度
	double w0=0, w1=0, u0=0, u1=0, ut=0;
	double maxVal = 0;
	int maxNum = 0;
	double sigma = 0;


	for (int i = 0; i < 256; i++)
	{

		nNum[i] = 0;
		nPro[i] = 0.0;

	}

	//02统计每个灰度值的数量
	for (int i = 0; i < m.rows; i++)
	{
		for (int j = 0; j < m.cols; j++)
		{
			nNum[m.at<uchar>(i, j)] += 1;
		}
	}

	//03统计每个灰度值的比例
	for (int i = 0; i < 256; i++)
	{
		nPro[i] = 1.0*nNum[i] / (m.cols * m.rows);
		ut += i * nPro[i];
		
	}

	//04开始遍历
	
	for (int i = 0; i < 256; i++)
	{
		

		w0 = w1 = u0 = u1 =sigma= 0;
		for (int j = 0; j < 255; j++)
		{
			
			
			if (j < i)
			{
				w0 += nPro[j];
				u0 += nPro[j] * j;
			}
			else
			{
				w1 += nPro[j];
				u1 += nPro[j] * j;
			}
		
		
		}

		u0 = u0 / w0;
		u1 = u1 / w1;
		
		sigma = w0 * pow((u0 - ut), 2) + w1 * pow((u1 - ut), 2);
	
		
		if (sigma > maxVal)
		{
			maxVal = sigma;
			maxNum = i;
			
		}
		
		

	}
//05利用求得的阈值做固定化阈值计算
	threshold(m, n, maxNum, 255, THRESH_BINARY);
	imshow("a", n);
	threshold(m, n, 0, 255, THRESH_BINARY | THRESH_OTSU);
	imshow("b", n);
	waitKey(0);


	return 0;
}




在这里插入图片描述左右分别是使用opencv的参数和自己手写算法实现的阈值化图片,可以看出结果是一样的

5. 参考文献

【1】https://www.bilibili.com/video/av68735378?p=39【一起来撸】OpenCV最新4.1.1官网直击

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值