番外篇: Otsu阈值法
大部分图像处理任务都需要先进行二值化操作,阈值的选取很关键,Otsu阈值法会自动计算阈值。
Otsu阈值法(日本人大津展之提出的,也可称大津算法)非常适用于双峰图片,啥意思呢?
什么是双峰图片?
双峰图片就是指图片的灰度直方图上有两个峰值,直方图就是每个值(0~255)的像素点个数统计,后面会详细介绍。
Otsu算法假设这副图片由前景色和背景色组成,通过统计学方法(最大类间方差)选取一个阈值,将前景和背景尽可能分开,我们先来看下代码,然后详细说明下算法原理。
代码示例
下面这段代码对比了使用固定阈值和Otsu阈值后的不同结果:
另外,对含噪点的图像,先进行滤波操作效果会更好。
import cv2
from matplotlib import pyplot as plt
img = cv2.imread('noisy.jpg', 0)
# 固定阈值法
ret1, th1 = cv2.threshold(img, 100, 255, cv2.THRESH_BINARY)
# Otsu阈值法
ret2, th2 = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# 先进行高斯滤波,再使用Otsu阈值法
blur = cv2.GaussianBlur(img, (5, 5), 0)
ret3, th3 = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)Copy to clipboardErrorCopied
下面我们用Matplotlib把原图、直方图和阈值图都显示出来:
images = [img, 0, th1, img, 0, th2, blur, 0, th3]
titles = ['Original', 'Histogram', 'Global(v=100)',
'Original', 'Histogram', "Otsu's",
'Gaussian filtered Image', 'Histogram', "Otsu's"]
for i in range(3):
# 绘制原图
plt.subplot(3, 3, i * 3 + 1)
plt.imshow(images[i * 3], 'gray')
plt.title(titles[i * 3], fontsize=8)
plt.xticks([]), plt.yticks([])
# 绘制直方图plt.hist,ravel函数将数组降成一维
plt.subplot(3, 3, i * 3 + 2)
plt.hist(images[i * 3].ravel(), 256)
plt.title(titles[i * 3 + 1], fontsize=8)
plt.xticks([]), plt.yticks([])
# 绘制阈值图
plt.subplot(3, 3, i * 3 + 3)
plt.imshow(images[i * 3 + 2], 'gray')
plt.title(titles[i * 3 + 2], fontsize=8)
plt.xticks([]), plt.yticks([])
plt.show()Copy to clipboardErrorCopied
可以看到,Otsu阈值明显优于固定阈值,省去了不断尝试阈值判断效果好坏的过程。其中,绘制直方图时,使用了numpy中的ravel()函数,它会将原矩阵压缩成一维数组,便于画直方图。
Otsu算法详解
Otsu阈值法将整幅图分为前景(目标)和背景,以下是一些符号规定:
- TT:分割阈值
- N\_0N_0:前景像素点数
- N\_1N_1:背景像素点数
- omega\_0ω_0:前景的像素点数占整幅图像的比例
- omega\_1ω_1:背景的像素点数占整幅图像的比例
- mu\_0μ_0:前景的平均像素值
- mu\_1μ_1:背景的平均像素值
- muμ:整幅图的平均像素值
- rows imes colsrows×cols:图像的行数和列数
结合下图会更容易理解一些,有一副大小为4×4的图片,假设阈值T为1,那么:
其实很好理解,N\_0+N\_1N_0+N_1就是总的像素点个数,也就是行数乘列数:
N_0+N_1=rows imes colsN0+N1=rows×cols
omega\_0ω_0和omega\_1ω_1是前/背景所占的比例,也就是:
omega_0=frac{N_0}{rows imes cols}ω0=rows×colsN0omega_1=frac{N_1}{rows imes cols}ω1=rows×colsN1omega_0+omega_1=1 ag{1}ω0+ω1=1(1)
整幅图的平均像素值就是:
mu=omega_0 imes mu_0+omega_1 imes mu_1 ag{2}μ=ω0×μ0+ω1×μ1(2)
此时,我们定义一个前景mu\_0μ_0与背景mu\_1μ_1的方差gg:
g=omega_0(mu_0-mu)^2+omega_1(mu_1-mu)^2 ag{3}g=ω0(μ0−μ)2+ω1(μ1−μ)2(3)
将前述的1/2/3公式整合在一起,便是:
g=omega_0omega_1(mu_0-mu_1)^2g=ω0ω1(μ0−μ1)2
gg就是前景与背景两类之间的方差,这个值越大,说明前景和背景的差别也就越大,效果越好。Otsu算法便是遍历阈值T,使得gg最大,所以又称为最大类间方差法。基本上双峰图片的阈值T在两峰之间的谷底。
接口文档
引用
相关文章
- 【技术种草】cdn+轻量服务器+hugo=让博客“云原生”一下
- CLB运维&运营最佳实践 ---访问日志大洞察
- vnc方式登陆服务器
- 轻松学排序算法:眼睛直观感受几种常用排序算法
- 十二个经典的大数据项目
- 为什么使用 CDN 内容分发网络?
- 大数据——大数据默认端口号列表
- Weld 1.1.5.Final,JSR-299 的框架
- JavaFX 2012:彻底开源
- 提升as3程序性能的十大要点
- 通过凸面几何学进行独立于边际的在线多类学习
- 利用行动影响的规律性和部分已知的模型进行离线强化学习
- ModelLight:基于模型的交通信号控制的元强化学习
- 浅谈Visual Source Safe项目分支
- 基于先验知识的递归卡尔曼滤波的代理人联合状态和输入估计
- 结合网络结构和非线性恢复来提高声誉评估的性能
- 最佳实践丨云开发CloudBase多环境管理实践
- TimeVAE:用于生成多变量时间序列的变异自动编码器
- 具有线性阈值激活的神经网络:结构和算法
- 内网渗透之横向移动 -- 从域外向域内进行密码喷洒攻击