opencv(4.5.3)-python(十二)--图像阈值处理
翻译及二次校对:cvtutorials.com
目标
- • 在本教程中,你将学习简单的阈值处理、自适应阈值处理和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 range(6):
plt.subplot(2,3,i+1),plt.imshow(images[i],'gray',vmin=0,vmax=255)
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是一个常数,从邻域像素的平均值或加权和中减去。
下面的代码比较了全局阈值处理和自适应阈值处理对不同照度的图像的影响。
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img = cv.imread('sudoku.png',0)
img = cv.medianBlur(img,5)
ret,th1 = cv.threshold(img,127,255,cv.THRESH_BINARY)
th2 = cv.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_MEAN_C,\
cv.THRESH_BINARY,11,2)
th3 = cv.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,\
cv.THRESH_BINARY,11,2)
titles = ['Original Image', 'Global Thresholding (v = 127)',
'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']
images = [img, th1, th2, th3]
for i in range(4):
plt.subplot(2,2,i+1),plt.imshow(images[i],'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
结果如下:
Otsu的二值化
在全局阈值化中,我们使用一个任意选择的值作为阈值。相比之下,Otsu的方法避免了选择一个值,而是自动确定它。
考虑一个只有两个不同图像值的图像(双峰图像),其中直方图只由两个峰值组成。一个好的阈值会在这两个值的中间。同样地,Otsu的方法从图像直方图中确定一个最佳的全局阈值。
为了做到这一点,使用了cv.threshold()函数,其中cv.THRESH_OTSU被作为一个额外的标志传递。阈值可以任意选择。然后,该算法找到最佳的阈值,并作为第一个输出返回。
请看下面的例子。输入的图像是一个有噪声的图像。在第一种情况下,全局阈值为127的阈值被应用。在第二种情况下,直接应用Otsu的阈值处理。在第三种情况下,首先用5x5高斯核过滤图像以去除噪声,然后应用Otsu的阈值。看看噪声过滤是如何改善结果的。
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img = cv.imread('noisy2.png',0)
# global thresholding
ret1,th1 = cv.threshold(img,127,255,cv.THRESH_BINARY)
# Otsu's thresholding
ret2,th2 = cv.threshold(img,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)
# Otsu's thresholding after Gaussian filtering
blur = cv.GaussianBlur(img,(5,5),0)
ret3,th3 = cv.threshold(blur,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)
# plot all the images and their histograms
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 range(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),使加权的类内方差最小,该阈值由以下公式给出:
这里,
它实际上是找到一个位于两个峰值之间的t值,使两个类的方差最小。它可以在Python中简单地实现,如下:
img = cv.imread('noisy2.png',0)
blur = cv.GaussianBlur(img,(5,5),0)
# find normalized_histogram, and its cumulative distribution function
hist = cv.calcHist([blur],[0],None,[256],[0,256])
hist_norm = hist.ravel()/hist.sum()
Q = hist_norm.cumsum()
bins = np.arange(256)
fn_min = np.inf
thresh = -1
for i in range(1,256):
p1,p2 = np.hsplit(hist_norm,[i]) # probabilities
q1,q2 = Q[i],Q[255]-Q[i] # cum sum of classes
if q1 < 1.e-6 or q2 < 1.e-6:
continue
b1,b2 = np.hsplit(bins,[i]) # weights
# finding means and variances
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
# calculates the minimization function
fn = v1*q1 + v2*q2
if fn < fn_min:
fn_min = fn
thresh = i
# find otsu's threshold value with OpenCV function
ret, otsu = cv.threshold(blur,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)
print( "{} {}".format(thresh,ret) )
其他资源
- • 《数字图像处理》,Rafael C. Gonzalez
练习
- • 对Otsu的二进制化有一些优化。你可以搜索并实现它。
相关文章
- python re.compile() 详解——Python正则表达式「建议收藏」
- Python 随机(Random)模块的不可预测之美
- python qt是什么_初识Python与Qt「建议收藏」
- RPC协议及其python实例[通俗易懂]
- [Python图像处理] 十一.灰度直方图概念及OpenCV绘制直方图
- python人工智能学习笔记_[Python] 人工智能与自然语言处理学习笔记(1)[通俗易懂]
- python海龟作图红绿灯_海龟作图—用Python绘图
- Py之cv2:cv2库(OpenCV,opencv-python)的简介、安装、使用方法(常见函数、方法等)最强详细攻略[通俗易懂]
- python语言一般用于什么_PYthon
- OpenCV-Python学习(15)—— OpenCV 图像旋转角度计算(NumPy 三角函数)
- 【说站】python多分支结构是什么
- 【说站】python Fixture类级的介绍
- 【说站】python HTML测试报告的用法
- 关于python中lambda函数的描述_Python全局变量
- OpenCV-Python实战(4) —— OpenCV 五角星各点在坐标系上面的坐标计算(以重心为原点)
- python使用opencv如何保存图片_OpenCV Python 保存图片
- 【计算机视觉】使用OpenCV处理色彩空间(Python版)
- opencv(4.5.3)-python(十)--改变色彩空间
- python-Python与MySQL数据库-处理MySQL查询结果
- Python 学习笔记(4.19更)
- 使用Python编程连接MySQL数据库(python连mysql)
- Python程序运行机制详解(入门必读)
- Python简易操作MySQL数据库指南(python操作mysql数据库)
- Linux下Python编程:从入门到精通(linux下python编程)
- Python操作MySQL数据库的必备模块mysqlpython(mysql_python)
- Python入门篇之面向对象