OpenCV---005(图像滤波(1))

图像滤波(1)

在图像采集的过程中可能会产生很多的噪声,所以对图像滤波是图像预处理中重要的一步

原图像:
image

图像卷积

卷积常用在信号处理中 图像信息可以看为一种信号 对于图像的卷积
给出一个卷积模板,然后再原图像种进行卷积计算 可以看为一个卷积模板
在原图像上进行移动 后对卷积模板覆盖范围进行计算并求和作为中心像素的
输出值。在原图像上由左到右 由上到下进行卷积计算 卷积模板被称为卷积核
是一个固定大小的矩阵

图像卷积可以分为五步:
    1.模板旋转180度 由于绝大多数的卷积模板是对称的,所以大多数情况可以省略
    2.将卷积模板放在原图像中需要卷积的地方
    3.卷积模板的系数乘像素值 后求和得到值
    4.将结果放在 原图像卷积模板中心对应的位置
    5.将卷积模板左到右 上到下移动 到全部
    (但是只能对原图像的中心区域进行卷积)

    为了解决边缘问题,将图像扩大一圈0

    因为卷积的原因 最后的像素点值可能越界 所以进行归一化
    让卷积模板的全部值和为1


opencv提供函数:
    dst = cv.fitlter2D(src,ddepth,kernel,[borderType])
    ddepth 输出图像的深度
    kernel 卷积核 多为 3*3 5*5
    borderType 边缘外扩方法选择
点击查看代码

        import cv2 as cv
        import numpy as np
        import sys
        
        if __name__ == '__main__':
            kernel1 = np.array([[1] * 3 for i in range(3)], dtype='float32')
            kernel1 = kernel1 / 9
            img = cv.imread('../preview.jpg', )
            img = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
            if img is None:
                print('读取失败')
                sys.exit()
        
            res = cv.filter2D(img, -1, kernel=kernel1)
        
            cv.imshow('old', img)
            cv.imshow('ker', res)
        
            cv.waitKey(0)
        
            cv.destroyAllWindows()

噪声的种类和生成

常见的噪音有四种 分别为椒盐噪音 高斯噪音 乘性噪音 泊松噪音

椒盐噪音:
    又被叫做脉冲噪音,随机改变图像中像素点的像素值 产生黑白的颗粒

    生成方法:
        output = np.random.randint(low,high,size,dtype)
        椒盐噪音为随机的 所以直接用np的random的randint
        
        步骤:
        1.确定噪声添加位置
        2.确定噪声种类 
        3.修改图像的灰度值
        4.得到图像
点击查看代码
        import cv2 as cv
        import numpy as np
        import sys
        
        
        def add_noisy(image, n=10000):
            ret = image.copy()
            w, h = image.shape[:2]
            for i in range(n):
                # 噪声产生位置
                x = np.random.randint(1, w)
                y = np.random.randint(1, h)
                if np.random.randint(0, 2) == 0:
                    # 产生白色颗粒
                    res[x, y] = 255
                else:
                    res[x, y] = 0
            return ret
        
        if __name__ == '__main__':
            img = cv.imread('../preview.jpg')
            if img is None:
                print('import img error')
                sys.exit()
            
            img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
        
            res = add_noisy(img)
        
            cv.imshow('noisy_img', res)
        
            cv.waitKey(0)
            cv.destroyAllWindows()

image

高斯噪声:
    指噪声分布符合高斯分布及正态分布 主要产生原因由于拍摄时的场地较暗且亮度不均匀,高斯噪声出现在
    图像中的全部位置

    同样可以使用numpy来模拟高斯噪声 
    np.random.normal(loc,scale,size)
    loc: 高斯分布的平均值
    scale: 标准差

    '''
        def add_gauss_noisy(img, mean=0, val=0.01):
            size = img.shape
            img = img / 255
            gauss = np.random.normal(mean, val, size)
            noise = img + gauss
            return noise
    '''

image

区别不是很大

滤波算法

滤波是为了去除图像中不重要的内容 使图像更加清晰 例如: 去除图像中的噪音 提取某些信息等
根据滤波目的 图像滤波分为了 : 消除图像噪音的滤波 和 提取图像中关键数据的滤波
图像滤波的要求 : 1.不能破坏图像的轮廓和边缘信息 2.图像处理过后更加清晰

图像滤波使用的滤波器决定了滤波操作的作用:
噪声信号集中在高频 所以 使用滤波器允许低频和中频可以去除图像中的噪音
对于纹理变化的区域 信号频率很高 使用高通滤波器 可以达到锐化边缘的目的

图像滤波分为线性滤波和非线性滤波

线性滤波

线性滤波常用的有 均值滤波 方框滤波 高斯滤波 图像的线性滤波和图像的卷积有相似的地方

均值滤波:
    ret = cv.blur(src,ksize)
    ksize: 给出大小,自动给出卷积核

    特点: 滤波器越大 返还图像越模糊
'''
    def mean_wash(img, ksize):
        img = cv.blur(img, ksize)
        return img
'''

方框滤波:
    均值滤波的一般形式 只是不将元素值进行平均 而是直接用其和
    ret = cv.boxFilter(src,ddepth,ksize)



高斯滤波:
    因为现实情况中很容易引入高斯噪声 所以对针对高斯噪声的滤波是必要的

    cv.GaussianBlur(src,ksize,sigmaX,sigmaY)
    sigmaX: 在x轴上的标准偏差 
    sigmaY: 在y轴上的标准偏差

    该函数可以根据输入的参数自动生成滤波器
    ksize可以不是正方形 并且可以为0 为0可以自动计算出大小

    当sigmaX和sigmaY 都为0的时候 表示根据滤波器的大小计算两个方向上的标准差数值

    为了得到明确的结果
    一般会确定 ksize sigmaX sigmaY 的值

image

利用高斯滤波处理椒盐噪音和高斯噪音

非线性滤波

非线性滤波的结果不是滤波器内的像素值进行线性组合得到的,其计算过程可能包含了排序 逻辑运算等等
因为线性滤波是所有像素值的线性组合 所以 噪音也会被包含进去,噪音只是更柔性 而非消失
常见的非线性滤波有: 中值滤波 双边滤波

中值滤波:
    中值滤波是使用滤波器内的所有像素的中值来代替滤波器中心位置的像素值 是一种基于排序统计理论的能够
    有效抑制噪音的非线性信号处理方法 , 不用想就知道肯定对椒盐噪音的处理效果很好
    
    res = cv.medianBlur(src,ksize)
    ksize: 不是给出一个() 而是一个 大于1的奇数

image

利用中值滤波处理椒盐噪音 效果very good

双边滤波:
    一种经典的可以保留图片边缘信息的滤波算法 
    双边滤波是一种综合考虑滤波器内空域信息和图像灰度的相似度的滤波算法
    可以在保留信息的基础上去除噪声。
    img = cv.bilateralFilter(src,d,sigmaColor,sigmaSpace)
    d: 滤波器的直径 当大于5时 函数会变慢 d越大 越糊

    第三个参数越大 像素邻域的越多颜色会被混到一起 越大越糊
    第四个参数越大 越远的像素点会相会影响        
    第三第四个参数大于150后会有较明显效果 小于10时效果很小

image

据说有美颜效果

代码汇总:

点击查看代码
import cv2 as cv
import numpy as np
import sys


def double_wash(img, d=5, sigColor=50, sigSpace=50):
    img = img.copy()
    img = cv.bilateralFilter(img, d, sigColor, sigSpace)
    return img


def median_wash(img, ksize):
    img = img.copy()
    img = cv.medianBlur(img, ksize)
    return img


def gauss_wash(img, ksize=(3, 3), sigX=10, sigY=20):
    img = img.copy()
    img = cv.GaussianBlur(img, ksize, sigX, sigY)
    return img


def mean_wash(img, ksize):
    img = img.copy()
    img = cv.blur(img, ksize)
    return img


def box_wash(img, ksize):
    img = img.copy()
    img = cv.boxFilter(img, -1, ksize, normalize=False)
    return img


def add_gauss_noisy(img, mean=0, val=0.01):
    size = img.shape
    img = img / 255
    gauss = np.random.normal(mean, val, size)
    noise = img + gauss
    return noise


def add_noisy(image, n=10000):
    ret = image.copy()
    w, h = image.shape[:2]
    for i in range(n):
        # 噪声产生位置
        x = np.random.randint(1, w)
        y = np.random.randint(1, h)
        if np.random.randint(0, 2) == 0:
            # 产生白色颗粒
            ret[x, y] = 255
        else:
            ret[x, y] = 0
    return ret


if __name__ == '__main__':
    img = cv.imread('../preview.jpg')
    img2 = cv.imread('../img_test.jpg')
    if img is None:
        print('import img error')
        sys.exit()

    img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)

    # cv.imshow('old', img)

    res1 = add_noisy(img)

    res2 = add_gauss_noisy(img)
    # cv.imshow('noisy', res1)
    # cv.imshow('gauss', res2)

    res1_wash = gauss_wash(res1, (7, 7))
    res2_wash = gauss_wash(res2, (5, 5))

    median_res = median_wash(res1, 3)


    double_res = double_wash(img2, 5, 200, 200)

    # cv.imshow('wash1', res1_wash)
    # cv.imshow('wash2', res2_wash)
    # cv.imshow('wash3', median_res)
    cv.imshow('old',img2)
    cv.imshow('wash4', double_res)
    cv.waitKey(0)
    cv.destroyAllWindows()

posted @ 2022-03-12 19:54  cc学习之路  阅读(81)  评论(0)    收藏  举报