Python下opencv图像阈值处理的使用笔记

(编辑:jimmy 日期: 2024/11/14 浏览:2)

图像的阈值处理一般使得图像的像素值更单一、图像更简单。阈值可以分为全局性质的阈值,也可以分为局部性质的阈值,可以是单阈值的也可以是多阈值的。当然阈值越多是越复杂的。下面将介绍opencv下的三种阈值方法。

(一)简单阈值

简单阈值当然是最简单,选取一个全局阈值,然后就把整幅图像分成了非黑即白的二值图像了。函数为cv2.threshold()
这个函数有四个参数,第一个原图像,第二个进行分类的阈值,第三个是高于(低于)阈值时赋予的新值,第四个是一个方法选择参数,常用的有:

  • cv2.THRESH_BINARY(黑白二值)
  • cv2.THRESH_BINARY_INV(黑白二值反转)
  • cv2.THRESH_TRUNC (得到的图像为多像素值)
  • cv2.THRESH_TOZERO
  • cv2.THRESH_TOZERO_INV

该函数有两个返回值,第一个retVal(得到的阈值值(在后面一个方法中会用到)),第二个就是阈值化后的图像。
一个实例如下:

import cv2
import matplotlib.pyplot as plt

img = cv2.imread('flower.jpg',0) #直接读为灰度图像
ret,thresh1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
ret,thresh2 = cv2.threshold(img,127,255,cv2.THRESH_BINARY_INV)
ret,thresh3 = cv2.threshold(img,127,255,cv2.THRESH_TRUNC)
ret,thresh4 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO)
ret,thresh5 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO_INV)
titles = ['img','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')
 plt.title(titles[i])
 plt.xticks([]),plt.yticks([])
plt.show()

Python下opencv图像阈值处理的使用笔记 

可以看到这里把阈值设置成了127,对于BINARY方法,当图像中的灰度值大于127的重置像素值为255.

(二)自适应阈值:

前面看到简单阈值是一种全局性的阈值,只需要规定一个阈值值,整个图像都和这个阈值比较。而自适应阈值可以看成一种局部性的阈值,通过规定一个区域大小,比较这个点与区域大小里面像素点的平均值(或者其他特征)的大小关系确定这个像素点是属于黑或者白(如果是二值情况)。使用的函数为:cv2.adaptiveThreshold()
该函数需要填6个参数:

  1. 第一个原始图像
  2. 第二个像素值上限
  3. 第三个自适应方法Adaptive Method:
    1. — cv2.ADAPTIVE_THRESH_MEAN_C :领域内均值
    2. —cv2.ADAPTIVE_THRESH_GAUSSIAN_C :领域内像素点加权和,权 重为一个高斯窗口
  4. 第四个值的赋值方法:只有cv2.THRESH_BINARY 和cv2.THRESH_BINARY_INV
  5. 第五个Block size:规定领域大小(一个正方形的领域)
  6. 第六个常数C,阈值等于均值或者加权值减去这个常数(为0相当于阈值 就是求得领域内均值或者加权值)

这种方法理论上得到的效果更好,相当于在动态自适应的调整属于自己像素点的阈值,而不是整幅图像都用一个阈值。

一个实例如下:

mport cv2
import matplotlib.pyplot as plt

img = cv2.imread('flower.jpg',0) #直接读为灰度图像
ret,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
th2 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,11,2) #换行符号 th3 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,2) #换行符号 images = [img,th1,th2,th3]
plt.figure()
for i in xrange(4):
 plt.subplot(2,2,i+1),plt.imshow(images[i],'gray')
plt.show()

Python下opencv图像阈值处理的使用笔记 

可以看到上述窗口大小使用的为11,当窗口越小的时候,得到的图像越细。想想一下,如果把窗口设置足够大以后(不能超过图像大小),那么得到的结果可能就和第二幅图像的相同了。

(三)Otsu's二值化

我们前面说到,cv2.threshold函数是有两个返回值的,前面一直用的第二个返回值,也就是阈值处理后的图像,那么第一个返回值(得到图像的阈值)将会在这里用到。

前面对于阈值的处理上,我们选择的阈值都是127,那么实际情况下,怎么去选择这个127呢?有的图像可能阈值不是127得到的效果更好。那么这里我们需要算法自己去寻找到一个阈值,而Otsu's就可以自己找到一个认为最好的阈值。并且Otsu's非常适合于图像灰度直方图具有双峰的情况,他会在双峰之间找到一个值作为阈值,对于非双峰图像,可能并不是很好用。那么经过Otsu's得到的那个阈值就是函数cv2.threshold的第一个参数了。因为Otsu's方法会产生一个阈值,那么函数cv2.threshold的的第二个参数(设置阈值)就是0了,并且在cv2.threshold的方法参数中还得加上语句cv2.THRESH_OTSU。那么什么是双峰图像(只能是灰度图像才有),就是图像的灰度统计图中可以明显看出只有两个波峰,比如下面一个图的灰度直方图就可以是双峰图:

Python下opencv图像阈值处理的使用笔记 

好了现在对这个图进行Otsu's阈值处理就非常的好,通过函数cv2.threshold会自动找到一个介于两波峰之间的阈值。一个实例如下:

import cv2
import matplotlib.pyplot as plt

img = cv2.imread('finger.jpg',0) #直接读为灰度图像
#简单滤波
ret1,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
#Otsu 滤波
ret2,th2 = cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
print ret2
plt.figure()
plt.subplot(221),plt.imshow(img,'gray')
plt.subplot(222),plt.hist(img.ravel(),256)#.ravel方法将矩阵转化为一维
plt.subplot(223),plt.imshow(th1,'gray')
plt.subplot(224),plt.imshow(th2,'gray')

Python下opencv图像阈值处理的使用笔记 

print ret2 得到的结果为122。可以看出似乎两个结果并没有很明显差别(素材也不太好弄~_~!),主要是两个阈值(127与122)太相近了,如果这两个隔得很远那么会很明显的。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

一句话新闻
高通与谷歌联手!首款骁龙PC优化Chrome浏览器发布
高通和谷歌日前宣布,推出首次面向搭载骁龙的Windows PC的优化版Chrome浏览器。
在对骁龙X Elite参考设计的初步测试中,全新的Chrome浏览器在Speedometer 2.1基准测试中实现了显著的性能提升。
预计在2024年年中之前,搭载骁龙X Elite计算平台的PC将面世。该浏览器的提前问世,有助于骁龙PC问世就获得满血表现。
谷歌高级副总裁Hiroshi Lockheimer表示,此次与高通的合作将有助于确保Chrome用户在当前ARM兼容的PC上获得最佳的浏览体验。