OpenCV-Python 图像阈值 | 十五
目标
- 在本教程中,您将学习简单阈值,自适应阈值和Otsu阈值。
- 你将学习函数cv.threshold和cv.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∑tP(i)&q2(t)=i=t1∑IP(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∑tq1(t)iP(i)&μ2(t)=i=t1∑Iq2(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) )
其他资源
- Digital Image Processing, Rafael C. Gonzalez
练习题
- Otsu的二值化有一些优化。您可以搜索并实现它。
欢迎关注磐创博客资源汇总站:
http://docs.panchuang.net/
欢迎关注PyTorch官方中文教程站:
http://pytorch.panchuang.net/
OpenCV中文官方文档:
http://woshicver.com/
OpenCV-Python 图像阈值 | 十五的更多相关文章
- 【OpenCV新手教程之十五】水漫金山:OpenCV漫水填充算法(Floodfill)
本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接: http://blog.csdn.net/poem_qianmo/article/details/28261997 作者:毛星云( ...
- Java基于opencv实现图像数字识别(五)—投影法分割字符
Java基于opencv实现图像数字识别(五)-投影法分割字符 水平投影法 1.水平投影法就是先用一个数组统计出图像每行黑色像素点的个数(二值化的图像): 2.选出一个最优的阀值,根据比这个阀值大或小 ...
- Python进阶(三十五)-Fiddler命令行和HTTP断点调试
Python进阶(三十五)-Fiddler命令行和HTTP断点调试 一. Fiddler内置命令 上一节(使用Fiddler进行抓包分析)中,介绍到,在web session(与我们通常所说的se ...
- 孤荷凌寒自学python第八十五天配置selenium并进行模拟浏览器操作1
孤荷凌寒自学python第八十五天配置selenium并进行模拟浏览器操作1 (完整学习过程屏幕记录视频地址在文末) 要模拟进行浏览器操作,只用requests是不行的,因此今天了解到有专门的解决方案 ...
- 孤荷凌寒自学python第七十五天开始写Python的第一个爬虫5
孤荷凌寒自学python第七十五天开始写Python的第一个爬虫5 (完整学习过程屏幕记录视频地址在文末) 今天在上一天的基础上继续完成对我的第一个代码程序的书写. 直接上代码.详细过程见文末屏幕录像 ...
- 孤荷凌寒自学python第六十五天学习mongoDB的基本操作并进行简单封装4
孤荷凌寒自学python第六十五天学习mongoDB的基本操作并进行简单封装4 (完整学习过程屏幕记录视频地址在文末) 今天是学习mongoDB数据库的第十一天. 今天继续学习mongoDB的简单操作 ...
- 孤荷凌寒自学python第四十五天Python初学基础基本结束的下阶段预安装准备
孤荷凌寒自学python第四十五天Python初学基础基本结束的下阶段预安装准备 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 今天本来应当继续学习Python的数据库操作,但根据过去我自 ...
- 孤荷凌寒自学python第三十五天python的文件操作之针对文件操作的os模块的相关内容
孤荷凌寒自学python第三十五天python的文件操作之针对文件操作的os模块的相关内容 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 一.打开文件后,要务必记得关闭,所以一般的写法应当 ...
- 进击的Python【第十五章】:Web前端基础之DOM
进击的Python[第十五章]:Web前端基础之DOM 简介:文档对象模型(Document Object Model,DOM)是一种用于HTML和XML文档的编程接口.它给文档提供了一种结构化的表示 ...
随机推荐
- PHP 导出网页表格如何对标签中的内容设置属性
当在使用php导出excel表格的时候,有时需要将某一列专门设置成文本属性 方法: 在需要设置属性的的<td>标签中 添加 style='vnd.ms-excel.numberforma ...
- shell 之 case。。。esac多分支选择
case分支属于匹配执行的方式,它针对指定的变量预先设置一个可能的取值,判断该变量的实际取值是否与预设的某一个值相匹配,如果匹配上了,就执行相应的一组操作,如果没有任何值能够匹配,就执行预先设置的默认 ...
- 前端每日实战:85# 视频演示如何用纯 CSS 创作一个小球反弹的动画
效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/OwWROO 可交互视频 此视频是可 ...
- 利用pandas选取某个属性符合指定条件的所有行
最近遇到利用pandas选取指定行的需求,经常忘记,在此做下记录 选取某个属性等于特定值的所有行记录 df[(df[‘column_name’] == target_value)] 注:等于用 '== ...
- 2018-05-04 圣杯布局 and 双飞翼布局,display:flex
看到一个神奇的布局,啥都不说了 直接贴代码 要让main在中间,left在左边,可以通过Flex容器下的项目的属性“order”属性来设置:对于order属性:定义项目的排列顺序,越小越靠前,默认为0 ...
- html5插件完成滚屏幕效果
首先想要完成这样的效果要用到jquery-fullpage插件我们需要他的js文件和css样式文件如图 因为是jquery的插件所以我们还要导入jquery-min.js 在页面引入这些样式和插件 ...
- 03 HDFS的客户端操作
服务器和客户端的概念 hdfs的客户端有多种形式 1.网页形式 2.命令行形式 3.客户端在哪里运行,没有约束,只要运行客户端的机器能够跟hdfs集群联网 参数配置 文件的切块大小和存储的副本数量,都 ...
- PHP中elseif与else if的区别
在PHP中,正常情况下elseif和else if的用法及效果是一样的,但在使用带冒号的if语句时(也就是php替代)情况会有点不一样,比如: <?php /*正确的写法*/ $a = 1; ...
- CSS 文本截断方案
单行截断 .ellipsis { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } 此方法兼容到ie6过.不过只能单行 ...
- 使用synchronized修饰静态方法和非静态方法有什么区别
前言 最近被问到了这个问题,第一次回答的也是很不好,在此参考网上答案进行整理记录.供大家学习参考. Synchronized修饰非静态方法 Synchronized修饰非静态方法,实际上是对调用该方法 ...