目标

  • 在本教程中,您将学习简单阈值,自适应阈值和Otsu阈值。
  • 你将学习函数cv.thresholdcv.adaptiveThreshold

简单阈值

在这里,问题直截了当。对于每个像素,应用相同的阈值。如果像素值小于阈值,则将其设置为0,否则将其设置为最大值。函数cv.threshold用于应用阈值。第一个参数是源图像,它应该是灰度图像。第二个参数是阈值,用于对像素值进行分类。第三个参数是分配给超过阈值的像素值的最大值。OpenCV提供了不同类型的阈值,这由函数的第四个参数给出。通过使用cv.THRESH_BINARY类型。所有简单的阈值类型为:

  • cv.THRESH_BINARY
  • cv.THRESH_BINARY_INV
  • cv.THRESH_TRUNC
  • cv.THRESH_TOZERO
  • cv.THRESH_TOZERO_INV

请通过类型的文档来观察区别。

该方法返回两个输出。第一个是使用的阈值,第二个输出是阈值后的图像

此代码比较了不同的简单阈值类型:

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img = cv.imread('gradient.png',0)
ret,thresh1 = cv.threshold(img,127,255,cv.THRESH_BINARY)
ret,thresh2 = cv.threshold(img,127,255,cv.THRESH_BINARY_INV)
ret,thresh3 = cv.threshold(img,127,255,cv.THRESH_TRUNC)
ret,thresh4 = cv.threshold(img,127,255,cv.THRESH_TOZERO)
ret,thresh5 = cv.threshold(img,127,255,cv.THRESH_TOZERO_INV)
titles = ['Original Image','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV']
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]
for i in xrange(6):
plt.subplot(2,3,i 1),plt.imshow(images[i],'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()

注意

为了绘制多个图像,我们使用plt.subplot()函数。请查看matplotlib文档以获取更多详细信息。

该代码产生以下结果:

自适应阈值

在上一节中,我们使用一个全局值作为阈值。但这可能并非在所有情况下都很好,例如,如果图像在不同区域具有不同的光照条件。在这种情况下,自适应阈值阈值化可以提供帮助。在此,算法基于像素周围的小区域确定像素的阈值。因此,对于同一图像的不同区域,我们获得了不同的阈值,这为光照度变化的图像提供了更好的结果。

除上述参数外,方法cv.adaptiveThreshold还包含三个输入参数:

adaptiveMethod决定阈值是如何计算的:

cv.ADAPTIVE_THRESH_MEAN_C::阈值是邻近区域的平均值减去常数C

cv.ADAPTIVE_THRESH_GAUSSIAN_C:阈值是邻域值的高斯加权总和减去常数C

BLOCKSIZE确定附近区域的大小,C是从邻域像素的平均或加权总和中减去的一个常数。

下面的代码比较了光照变化的图像的全局阈值和自适应阈值:

结果:

Otsu的二值化

在全局阈值化中,我们使用任意选择的值作为阈值。相反,Otsu的方法避免了必须选择一个值并自动确定它的情况。

考虑仅具有两个不同图像值的图像(双峰图像),其中直方图将仅包含两个峰。一个好的阈值应该在这两个值的中间。类似地,Otsu的方法从图像直方图中确定最佳全局阈值。

为此,使用了cv.threshold作为附加标志传递。阈值可以任意选择。然后,算法找到最佳阈值,该阈值作为第一输出返回。

查看以下示例。输入图像为噪点图像。在第一种情况下,采用值为127的全局阈值。在第二种情况下,直接采用Otsu阈值法。在第三种情况下,首先使用5x5高斯核对图像进行滤波以去除噪声,然后应用Otsu阈值处理。了解噪声滤波如何改善结果。

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img = cv.imread('noisy2.png',0)
# 全局阈值
ret1,th1 = cv.threshold(img,127,255,cv.THRESH_BINARY)
# Otsu阈值
ret2,th2 = cv.threshold(img,0,255,cv.THRESH_BINARY cv.THRESH_OTSU)
# 高斯滤波后再采用Otsu阈值
blur = cv.GaussianBlur(img,(5,5),0)
ret3,th3 = cv.threshold(blur,0,255,cv.THRESH_BINARY cv.THRESH_OTSU)
# 绘制所有图像及其直方图
images = [img, 0, th1,
img, 0, th2,
blur, 0, th3]
titles = ['Original Noisy Image','Histogram','Global Thresholding (v=127)',
'Original Noisy Image','Histogram',"Otsu's Thresholding",
'Gaussian filtered Image','Histogram',"Otsu's Thresholding"]
for i in xrange(3):
plt.subplot(3,3,i*3 1),plt.imshow(images[i*3],'gray')
plt.title(titles[i*3]), plt.xticks([]), plt.yticks([])
plt.subplot(3,3,i*3 2),plt.hist(images[i*3].ravel(),256)
plt.title(titles[i*3 1]), plt.xticks([]), plt.yticks([])
plt.subplot(3,3,i*3 3),plt.imshow(images[i*3 2],'gray')
plt.title(titles[i*3 2]), plt.xticks([]), plt.yticks([])
plt.show()

结果:

Otsu的二值化如何实现?

本节演示了Otsu二值化的Python实现,以展示其实际工作方式。如果您不感兴趣,可以跳过此步骤。

由于我们正在处理双峰图像,因此Otsu的算法尝试找到一个阈值(t),该阈值将由关系式给出的加权类内方差最小化:

σw2(t)=q1(t)σ12(t)q2(t)σ22(t)
\sigma_w^2(t) = q_1(t)\sigma_1^2(t) q_2(t)\sigma_2^2(t)
σw2​(t)=q1​(t)σ12​(t)q2​(t)σ22​(t)

其中

q1(t)=∑i=1tP(i)&q2(t)=∑i=t1IP(i)
q_1(t) = \sum_{i=1}^{t} P(i) \quad \& \quad q_2(t) = \sum_{i=t 1}^{I} P(i)
q1​(t)=i=1∑t​P(i)&q2​(t)=i=t1∑I​P(i)

μ1(t)=∑i=1tiP(i)q1(t)&μ2(t)=∑i=t1IiP(i)q2(t)
\mu_1(t) = \sum_{i=1}^{t} \frac{iP(i)}{q_1(t)} \quad \& \quad \mu_2(t) = \sum_{i=t 1}^{I} \frac{iP(i)}{q_2(t)}
μ1​(t)=i=1∑t​q1​(t)iP(i)​&μ2​(t)=i=t1∑I​q2​(t)iP(i)​

σ12(t)=∑i=1t[i−μ1(t)]2P(i)q1(t)&σ22(t)=∑i=t1I[i−μ2(t)]2P(i)q2(t)
\sigma_1^2(t) = \sum_{i=1}^{t} [i-\mu_1(t)]^2 \frac{P(i)}{q_1(t)} \quad \& \quad \sigma_2^2(t) = \sum_{i=t 1}^{I} [i-\mu_2(t)]^2 \frac{P(i)}{q_2(t)}
σ12​(t)=i=1∑t​[i−μ1​(t)]2q1​(t)P(i)​&σ22​(t)=i=t1∑I​[i−μ2​(t)]2q2​(t)P(i)​

实际上,它找到位于两个峰值之间的t值,以使两个类别的差异最小。它可以简单地在Python中实现,如下所示:

img = cv.imread('noisy2.png',0)
blur = cv.GaussianBlur(img,(5,5),0)
# 寻找归一化直方图和对应的累积分布函数
hist = cv.calcHist([blur],[0],None,[256],[0,256])
hist_norm = hist.ravel()/hist.max()
Q = hist_norm.cumsum()
bins = np.arange(256)
fn_min = np.inf
thresh = -1
for i in xrange(1,256):
p1,p2 = np.hsplit(hist_norm,[i]) # 概率
q1,q2 = Q[i],Q[255]-Q[i] # 对类求和
b1,b2 = np.hsplit(bins,[i]) # 权重
# 寻找均值和方差
m1,m2 = np.sum(p1*b1)/q1, np.sum(p2*b2)/q2
v1,v2 = np.sum(((b1-m1)**2)*p1)/q1,np.sum(((b2-m2)**2)*p2)/q2
# 计算最小化函数
fn = v1*q1 v2*q2
if fn < fn_min:
fn_min = fn
thresh = i
# 使用OpenCV函数找到otsu的阈值
ret, otsu = cv.threshold(blur,0,255,cv.THRESH_BINARY cv.THRESH_OTSU)
print( "{} {}".format(thresh,ret) )

其他资源

  1. Digital Image Processing, Rafael C. Gonzalez

练习题

  1. Otsu的二值化有一些优化。您可以搜索并实现它。

欢迎关注磐创博客资源汇总站:

http://docs.panchuang.net/

欢迎关注PyTorch官方中文教程站:

http://pytorch.panchuang.net/

OpenCV中文官方文档:

http://woshicver.com/

最新文章

  1. Lesson 20 One man in a boat
  2. IO碰到的问题
  3. VS XML注释
  4. JQuery------$.get()和$.post()传递数据的使用方法
  5. 【云计算】docker registry v2简介
  6. 亲和数[HDU2040]
  7. VmWare下安装Linux Centos6.0详细过程
  8. 【转】Android自动化测试之MonkeyRunner录制和回放脚本(四)
  9. Myeclipse 中添加mysql的jdbc驱动
  10. java学习之线程的操作方法
  11. 【转】[Android实例] Handler+ExecutorService(线程池)+MessageQueue模式+缓存模式
  12. 201521123003《Java程序设计》第13周学习总结
  13. ajax接收json
  14. firewalld的基本使用
  15. Putty6.0 提示Access denied
  16. mysql学习笔记--数据完整性
  17. Pygame安装教程
  18. 笔记:CSS hack的学习与了解…
  19. [更新]一份包含: 采用RSA JWT(Json Web Token, RSA加密)的OAUTH2.0,HTTP BASIC,本地数据库验证,Windows域验证,单点登录的Spring Security配置文件
  20. artTemplate--使用artTemplate时,由于json对象属性有特殊格式 导致调用报错artTemplate,syntax error,Template Error

热门文章

  1. 新浪微博PC端登录分析
  2. Leetcode 206题 反转链表(Reverse Linked List)Java语言求解
  3. git还原历史某一版本
  4. 啥是python?
  5. 一起了解 .Net Foundation 项目 No.11
  6. Web网页布局的主要方式
  7. java 构造器(构造方法)使用详细说明
  8. ubuntu16.04设置开机自启服务
  9. Go module学习笔记
  10. Yuchuan_linux_C 编程之八 文件操作相关函数