上一节,我们提到过像素矩阵值的范围为0到255,但有些时候我们需要人为的设定一个新的阈值,如这个值为x,新的阈值就变成了0到x和x到255两个范围,划分好范围之后,我们可以对这两个部分执行不同的操作,比如矩阵内落在x到255范围内的元素全部改为255,而0到x范围内的值不变。这样的操作很常见,实现的方法也很简单,只需要调用threshold函数:
ret, dst = cv2.threshold(src, thresh, maxval, type)
给大家解释一下指其中的参数含义:
src:要输入的单通道图片,通常来说为灰度图
dst:处理后的图像矩阵
thresh:设置的阈值(要求输入0到255之间的整数值,经常以127为界)
maxval: 像素矩阵中元素最大值。通常情况下该值为255。
type:规定超过或小于阈值的元素处理方式。包含以下5种类型: cv2.THRESH_BINARY; cv2.THRESH_BINARY_INV; cv2.THRESH_TRUNC; cv2.THRESH_TOZERO;cv2.THRESH_TOZERO_INV
import cv2
import matplotlib.pyplot as plt
img=cv2.imread('show_dog.jpg')
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) # 获取灰度图
ret, thresh1 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY) # 二值黑白图
ret, thresh2 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY_INV) # 上图像素值取反
ret, thresh3 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TRUNC) # 超过阈值取最大
ret, thresh4 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TOZERO) # 低于阈值取0
ret, thresh5 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TOZERO_INV) # 上图取反
titles = ['Original Image', 'BINARY', 'BINARY_INV', 'TRUNC', 'TOZERO', 'TOZERO_INV']
images = [img_gray, 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()
我们获取到的图像有些时候是有强噪声干扰的,比如:
我们可以看到,这张图片里有着大量的白点,这些都属于噪声。对于这种图片,我们可以使用均值滤波来进行调整:
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('lenaNoise.png')
# 均值滤波
blur = cv2.blur(img, (3, 3))
cv2.imshow('blur', blur)
cv2.waitKey(0)
cv2.destroyAllWindows()
可以发现, cv2.blur()函数帮助我们把图像的噪点变得更平滑了。这个函数有两个常用参数,第一个参数是构成图像的矩阵,第二个参数是指定卷积核大小,卷积核多是n*n方阵,且n为奇数,通常等于3:
该函数作用方式为从像素矩阵的左上圈出第一个3×3区域,而后将中心的位置(红框所示)的值改为这九个数的平均值,然后将这个区域向右位移一个单位(入篮框所示)。在处理完最后一个3×3区域后,然后向下位移一个单位(如绿框所示),继续重复此前的求平均及移动的操作。
方框滤波操作方式基本和均值滤波一样,但多了两个常用参数:
cv2.boxFilter(img,-1,(3,3), normalize=True)
第一第三的参数和cv2.blur()函数是一样的,第二个参数-1代表处理后与原图像颜色通道一致,normalize为True代表做归一化(加和取平均),False则代表不做归一化,中间值超过255的值均记录为255。上代码:
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('lenaNoise.png')
# 做归一化,结果与均值滤波相同
box1 = cv2.boxFilter(img,-1,(3,3), normalize=True)
# 不做归一化,所有越界值都记录为255
box2 = cv2.boxFilter(img,-1,(3,3), normalize=False)
img_show=[img,box1,box2]
titles=['original','box1','box2']
# 使用matplotlib分割显示区域,显示图片使用cv2的cvtColor函数,保证颜色通道的正常
fig, ax = plt.subplots(3, 3) # ax的维度由第一个参数决定,当该值为1时,ax是一维的,只需要一个参数即可。
for i in range(len(img_show)):
ax[1,i].set_title(titles[i])
ax[1,i].imshow(cv2.cvtColor(img_show[i], cv2.COLOR_BGR2RGB))
for i in range(3):
for j in range(3):
ax[i,j].axis('off') # 关闭坐标轴显示
plt.show()
看看效果:
中值滤波弄与均值滤波操作类似,只是红框中的数字不是九个数的均值,而是中位数。终止滤波函数为:
cv2.medianBlur(src,ksize)
src时传入的图像矩阵,颜色通道可以是1,3,4,ksiz选择奇数,通常为3或5。当ksize为3或5时,矩阵内元素类型可以是8或16位无符号整数、32位浮点数。当ksize更大时,只能是8位无符号整数。下面我们看看效果:
import cv2
import numpy as np
img = cv2.imread('lenaNoise.png')
median = [cv2.medianBlur(img, 3),cv2.medianBlur(img, 7),cv2.medianBlur(img, 11)] # 中值滤波
# 将三个矩阵连接成一个
res = np.hstack((median[0],median[1],median[2]))
# hstack代表合成的矩阵行数不变,列数增加
# vstack代表合成矩阵列数不变,行数增加
cv2.imshow('median 3-5-11', res)
cv2.waitKey(0)
cv2.destroyAllWindows()
可以看出,当ksize增大时,图片的清晰度会快速降低,就像我们尽量选择较小的卷积核的原理一样。此外,这里介绍了合并图片的方法。但是这样的现实好像还是没有上面介绍的方式更直观。
高斯滤波是利用正态分布的特性对图像进行滤波。依据标准正态分布(u=0)的特点:
高斯滤波的关键在于我们认为与中心点距离近的像素,对中心点值的影响越大,比如:
这样的处理显然比求平均更为合理。那么下面我们来用代码实现这种滤波方法:
import cv2
img = cv2.imread('lenaNoise.png')
aussian = cv2.GaussianBlur(img, (5,5),1) #(5, 5)表示高斯矩阵的长与宽都是5
# 标准差取1
cv2.imshow('aussian', aussian)
cv2.waitKey(0)
cv2.destroyAllWindows()
以上就是今天的全部内容,代码并不难,可以仿写一下。此外,大家还可以参考一下opencv平滑方法介绍,以及图像矩阵的元素类型介绍。