阈值与平滑处理

Posted 有理想的打工人

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了阈值与平滑处理相关的知识,希望对你有一定的参考价值。

图像的阈值与滤波

图像阈值

上一节,我们提到过像素矩阵值的范围为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

    • cv2.THRESH_BINARY :超过阈值(thresh)部分取maxval(最大值),否则取0。变成真正意义上的黑白二值图像
    • cv2.THRESH_BINARY_INV:THRESH_BINARY的反转
    • cv2.THRESH_TRUNC:在阈值处截断,大于阈值部分设为最大值,否则不变
    • cv2.THRESH_TOZERO:大于阈值部分不改变,否则设为0
    • cv2.THRESH_TOZERO_INV:THRESH_TOZERO的反转
      下面我们用一个例子来看看处理结果:
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平滑方法介绍,以及图像矩阵的元素类型介绍

以上是关于阈值与平滑处理的主要内容,如果未能解决你的问题,请参考以下文章

[Python图像处理] 四十一.Python图像平滑万字详解(均值滤波方框滤波高斯滤波中值滤波双边滤波)

OpenCV中的图像处理 —— 图像阈值+图像平滑+形态转换

图像阈值与平滑处理

阈值与平滑处理

OpenCV图像处理应用(面向Python)之阈值与平滑处理

OpenCV图像处理应用(面向Python)之阈值与平滑处理