• 阈值与平滑处理


    图像阈值

    上一节,我们提到过像素矩阵值的范围为0到255,但有些时候我们需要人为的设定一个新的阈值,如这个值为x,新的阈值就变成了0到x和x到255两个范围,划分好范围之后,我们可以对这两个部分执行不同的操作,比如矩阵内落在x到255范围内的元素全部改为255,而0到x范围内的值不变。这样的操作很常见,实现的方法也很简单,只需要调用threshold函数:

    ret, dst = cv2.threshold(src, thresh, maxval, type)
    
    • 1

    给大家解释一下指其中的参数含义:

    • 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()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    在这里插入图片描述

    图像平滑

    均值滤波

    我们获取到的图像有些时候是有强噪声干扰的,比如:
    在这里插入图片描述
    我们可以看到,这张图片里有着大量的白点,这些都属于噪声。对于这种图片,我们可以使用均值滤波来进行调整:

    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()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述
    可以发现, cv2.blur()函数帮助我们把图像的噪点变得更平滑了。这个函数有两个常用参数,第一个参数是构成图像的矩阵,第二个参数是指定卷积核大小,卷积核多是n*n方阵,且n为奇数,通常等于3:
    在这里插入图片描述
    该函数作用方式为从像素矩阵的左上圈出第一个3×3区域,而后将中心的位置(红框所示)的值改为这九个数的平均值,然后将这个区域向右位移一个单位(入篮框所示)。在处理完最后一个3×3区域后,然后向下位移一个单位(如绿框所示),继续重复此前的求平均及移动的操作。

    方框滤波

    方框滤波操作方式基本和均值滤波一样,但多了两个常用参数:

    cv2.boxFilter(img,-1,(3,3), normalize=True)
    
    • 1

    第一第三的参数和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()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    看看效果:
    在这里插入图片描述

    中值滤波

    中值滤波弄与均值滤波操作类似,只是红框中的数字不是九个数的均值,而是中位数。终止滤波函数为:

    cv2.medianBlur(src,ksize) 
    
    • 1

    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()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述
    可以看出,当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()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述
    以上就是今天的全部内容,代码并不难,可以仿写一下。此外,大家还可以参考一下opencv平滑方法介绍,以及图像矩阵的元素类型介绍

  • 相关阅读:
    Games101-Chapter14-Ray Tracing 2
    DHCP的原理和配置
    倍福控制器搭建IgH环境
    java100-集合类简介
    行为设计模式之状态模式
    汽车行业消费者洞察|车载屏幕是否越大越多就越好?
    shopify商店Google购物广告2022教程
    【Elasticsearch】数据简单操作(二)
    什么是浮动?什么是文档流?清除浮动的几种方式及原理?什么是BFC,如何触发BFC,BFC的作用
    Jenkins拉分支代码 + tortoiseGit删除分支
  • 原文地址:https://blog.csdn.net/weixin_54929649/article/details/126315743