前言
如前面所提及的,一张图像的信息都被记录在一个矩阵内,其通道数值便是不同点的信息,利用信息对图片进行处理,筛选出所需要的信息,简化图像信息加速后续处理的速度。 在OpenCV中的常见的阈值操作主要有三种,分别为:固定阈值、自适应阈值和Otsu阈值三种。
固定阈值过滤
使用 cv2.threshold() 函数。此方法为选定一个阈值,大于该阈值的和小于该阈值的分别被赋予不同的操作。
retval, dst=cv.threshold( src, thresh, maxval, type[,dst])
参数 | 介绍 |
---|
src | 操作的源图像 | thresh | 阈值(分界线) | maxval | 和阈值方式配合使用(通常是将像素在大于或小于阈值是需要赋予的值) | type | 阈值方式 | dst | 输出的图像会与选用的dst有相同的像素和通道数,默认值为src相同的参数 |
阈值方式type:
cv.THRESH BINARY
cv.THRESH BINARY INV
cv.THRESH TRUNC
cv.TOZERO
cv.TOZERO INV
有以上五种,处理的取值逻辑如下所示。
import numpy as np
import cv2
im1 = np.ones((500,500), np.uint8)
for i in range(500):
for j in range(250):
im1[i][2*j] = im1[i][2*j-1] = j
thresh, maxv = 100, 255
_, im2 = cv2.threshold(im1, thresh, maxv, cv2.THRESH_BINARY)
_, im3 = cv2.threshold(im1, thresh, maxv, cv2.THRESH_BINARY_INV)
_, im4 = cv2.threshold(im1, thresh, maxv, cv2.THRESH_TOZERO)
_, im5 = cv2.threshold(im1, thresh, maxv, cv2.THRESH_TOZERO_INV)
_, im6 = cv2.threshold(im1, thresh, maxv, cv2.THRESH_TRUNC)
img = [im1, im2, im3, im4, im5, im6]
for item in range(len(img)):
cv2.imshow('im'+ str(int(item)+1), img[item])
k = cv2.waitKey(0)
if k == ord('s'):
cv2.destroyAllWindows()
自适应阈值过滤
使用 cv2.adaptiveThreshold() 函数,自适应阈值区分与上一小节的全局阈值,自适应阈值的方法是在一个小范围内选取一个阈值进行筛选。
dst = cv2.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C[, dst])
参数 | 介绍 |
---|
src | 8位单通道的源图像(灰度图像) | maxValue | 赋予满足条件的像素的灰度值 | maxval | 赋予满足条件的像素的灰度值 | adaptiveMehtod | 使用的自适应阈值方法,有两种 cv2.ADAPTIVE_THRESH_MEAN_C 和 cv2.ADAPTIVE_THRESH_GAUSSIAN_C | blockSize | 每次自适应计算的像素区域大小(只能是奇数,如3、5、11、17) | C | 这个参数与指定的方法有关 |
两种阈值方法略有区别,首先相同点在于计算的领域都是一个大小为 blockSize×blockSize 的矩形范围内,区别在于 MEANS 是取的周围所有的点的平均值与阈值作比较,而 GAUSSIAN 则是加权平均值,权值的大小和离中心像素点的距离有关。 blockSize 取值越大图像每次操作的区域越大,细节保留越少,同时边框感也越强。 C 的取值越小处理后的图像边框感越强,整体的轮廓很明显;反之取值越大,图像的许多细节会被过滤去。
import cv2
import numpy as np
im1 = cv2.imread('fruit_test.jpg',0)
im1 = cv2.resize(im1, None, fx=0.2, fy=0.2, interpolation=cv2.INTER_AREA)
for i in range(10):
name = 'im_mean'+str(i)
cv2.imshow(name,cv2.adaptiveThreshold(im1, 127,
cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, int(i)*2+3, 11))
for i in range(10):
name = 'im_guas'+str(i)
cv2.imshow(name,cv2.adaptiveThreshold(im1, 127,
cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, int(i)*2+3, 11))
k = cv2.waitKey(0)
if k == ord('s'):
Otsu阈值过滤(大津法)
大津法(Otsu)是由日本学者大津展之( Nobuyuki Otsu )提出的一种自适应阈值处理方法,这是求解全局阈值的最佳方法,且计算简单,对于仅存在双峰的图像效果非常好。 其实大津法是在全局阈值上的一种改进,在固定的全局阈值中靠肉眼观测并不能直接找到最佳的阈值是在哪个位置,所以通常的方法都是不断地尝试,直到找到一个合适的阈值。大津法则是帮助我们直接找到一个合适的阈值,它会从图像的灰度直方图中计算出一个合适的阈值,对双峰图像处理效果最好,而非双峰图像所取的阈值可能不准确。 具体的操作方法如下说明与代码所示。
说明: 仍然使用的是 cv2.threshold() 函数,但是阈值选取的为0,并且在后续的阈值方法中添加 cv2.THRESH_OSTU 即可。
import cv2
import numpy as np
im1 = cv2.imread('t5.jpg',0)
im1 = cv2.resize(im1, None, fx=0.3, fy=0.3, interpolation=cv2.INTER_AREA)
ret1, th1 = cv2.threshold(im1, 127, 255, cv2.THRESH_BINARY)
ret2, th2 = cv2.threshold(im1, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
img = [im1, th1, th2]
for i in range(len(img)):
cv2.imshow('im'+str(i+1), img[i])
k = cv2.waitKey(0)
if k == ord('s'):
cv2.destroyAllWindows()
附封面一张~
|