数字图像处理之椒盐噪声和中值滤波

0、所有的代码基于python3 + opecv3.3
1、椒盐噪声和中值滤波
  椒盐噪声(salt-and-pepper noise)是由图像传感器,传输信道,解码处理等产生的黑白相间的亮暗点噪声。
  所谓椒盐,椒就是黑,盐就是白,椒盐噪声就是在图像上随机出现黑色白色的像素。椒盐噪声是一种因为信号脉冲强度引起的噪声,产生该噪声的算法也比较简单。
  椒盐噪声往往由图像切割引起,去除脉冲干扰及椒盐噪声最常用的算法是中值滤波。大量的实验研究发现,由摄像机拍摄得到的图像受离散的脉冲、椒盐噪声和零均值的高斯噪声的影响较严重。噪声给图像处理带来很多困难,对图像分割、特征提取、图像识别等具有直接影响。因此,实时采集的图像需进行滤波处理。消除图像中的噪声成份叫做图像的平滑化或滤波操作。滤波的目的有两个:一是抽出对象的特征作为图像识别的特征模式;二是为适应计算机处理的要求,消除图像数字化时所混入的噪声。对滤波处理的要求有两条:一是不能损坏图像轮廓及边缘等重要信息;二是使图像清晰,视觉效果好。
  我们使用信噪比(Signal NoiseRate)衡量图像噪声,图象的信噪比应该等于信号与噪声的功率谱之比,但通常功率谱难以计算,有一种方法可以近似估计图象信噪比,即信号与噪声的方差之比(其实在均值为零的情况下,功率就是方差)。首先计算图象所有像素的局部方差,将局部方差的最大值认为是信号方差,最小值是噪声方差,求出它们的比值,再转成dB数,最后用经验公式修正。
  如果是灰度图像的话,SNR=(洁净图片中的像素点的灰度值之和)/abs(噪声图片的灰度值之和-洁净图片中的灰度值之和)为该图像的信噪比。
  给一副数字图像加上椒盐噪声的步骤如下:

  1. 指定信噪比 SNR (其取值范围在[0, 1]之间)
  2. 计算总像素数目 SP, 得到要加噪的像素数目 NP = SP * (1-SNR)
  3. 随机获取要加噪的每个像素位置P(i, j)
  4. 指定像素值为255或者0。
  5. 重复3,4两个步骤完成所有像素的NP个像素
  6. 输出加噪以后的图像
import cv2
import numpy as np

filename = "d:/1.jpg"
winname = "figure"
img = cv2.imread(filename)

def addSaltNoise():
    # 指定信噪比
    SNR = 0.9
    # 获取总共像素个数
    size = img.size
    # 因为信噪比是 SNR ,所以噪声占据百分之10,所以需要对这百分之10加噪声
    noiseSize = int(size * (1 - SNR))
    # 对这些点加噪声
    for k in range(0, noiseSize):
        # 随机获取 某个点
        xi = int(np.random.uniform(0, img.shape[1]))
        xj = int(np.random.uniform(0, img.shape[0]))
        # 增加噪声
        if img.ndim == 2:
            img[xj, xi] = 255
        elif img.ndim == 3:
            img[xj, xi] = 0
    cv2.imshow(winname, img)
    cv2.waitKey(0)

def main():
    addSaltNoise()

if __name__ == '__main__':
    main()

执行效果如下
原始图像:
这里写图片描述
信噪比为0.9的时候:
这里写图片描述
信噪比为0.7的时候:
这里写图片描述
信噪比为0.5的时候:
这里写图片描述
信噪比为0.1的时候:
这里写图片描述

通过对已经被椒盐噪声污染的图片进行中值滤波

import cv2
import numpy as np

def addSaltNoise(img,snr):
    # 指定信噪比
    SNR = snr
    # 获取总共像素个数
    size = img.size
    # 因为信噪比是 SNR ,所以噪声占据百分之10,所以需要对这百分之10加噪声
    noiseSize = int(size * (1 - SNR))
    # 对这些点加噪声
    for k in range(0, noiseSize):
        # 随机获取 某个点
        xi = int(np.random.uniform(0, img.shape[1]))
        xj = int(np.random.uniform(0, img.shape[0]))
        # 增加噪声
        if img.ndim == 2:
            img[xj, xi] = 255
        elif img.ndim == 3:
            img[xj, xi] = 0
    return img

def removeSaltNoise():
    filename = "d:/1.jpg"
    # 得到加噪声之后的图像
    img = addSaltNoise(cv2.imread(filename),0.9)
    # 进行中值滤波
    lbimg = cv2.medianBlur(img, 3)
    cv2.imshow('src', img)
    cv2.imshow('dst', lbimg)
    cv2.waitKey(0)

def main():
    removeSaltNoise()

if __name__ == '__main__':
    main()

效果如下:
被污染之后的图像(信噪比0.9的椒盐噪声):
这里写图片描述
经过中值滤波之后的图像:
这里写图片描述
真实的图像:
这里写图片描述
显然仅仅通过中值滤波还不够。因此调整中值滤波器,也就是cv2.medianBlur(img, 3)这个函数的参数,首先说一下中值滤波。
  中值滤波(Median filter)是一种典型的非线性滤波技术,基本思想是用像素点邻域灰度值的中值来代替该像素点的灰度值,该方法在去除脉冲噪声、椒盐噪声的同时又能保留图像边缘细节,中值滤波是基于排序统计理论的一种能有效抑制噪声的非线性信号处理技术,其基本原理是把数字图像或数字序列中一点的值用该点的一个邻域中各点值的中值代替,让周围的像素值接近的真实值,从而消除孤立的噪声点,对于斑点噪声(speckle noise)和椒盐噪声(salt-and-pepper noise)来说尤其有用,因为它不依赖于邻域内那些与典型值差别很大的值。中值滤波器在处理连续图像窗函数时与线性滤波器的工作方式类似,但滤波过程却不再是加权运算。
  中值滤波在一定的条件下可以克服常见线性滤波器如最小均方滤波、方框滤波器、均值滤波等带来的图像细节模糊,而且对滤除脉冲干扰及图像扫描噪声非常有效,也常用于保护边缘信息, 保存边缘的特性使它在不希望出现边缘模糊的场合也很有用,是非常经典的平滑噪声处理方法。这个函数的定义是

def medianBlur(src,ksize,dst=None)  
其中src代表原图像,dst代表输出文件,缺省值为None,ksize代表孔径的线性尺寸,是int类型的大于一的奇数

以上程序ksize的值比较小,效果不太好,现在进行调整效果如下
ksize = 5的时候(貌似更清晰了):
这里写图片描述
ksize = 7的时候(更清晰了,是不是ksize的值越大越好呢):
这里写图片描述
ksize = 9的时候:
这里写图片描述
ksize = 21的时候(虽然椒盐噪声没了,但是图像也变的模糊了,因为ksize太大了,把有用的信息也用中值代替了,误差就逐渐显现出来了):
这里写图片描述
来个极端的,ksize = 101的时候(已经模糊不清了。。。):
这里写图片描述
虽然ksize(模板大小为ksize * ksize)越大可以有效的消除噪声,但是会使边界模糊,因此对ksize的选择直接影响图片的质量。

猜你喜欢

转载自blog.csdn.net/tsfx051435adsl/article/details/78251739