添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
Python实现自适应中值滤波法去除椒盐噪声

Python实现自适应中值滤波法去除椒盐噪声

三、常用的图像去噪算法

3.1 灰度图的介绍和获取

在处理一张图片之前,通常需要读取这张图片,得到一个与RGB三维矩阵或者是灰度图的二维矩阵,本次课堂设计所处理的图片为灰度图,Gray Scale Image 或是Grey Scale Image,又称灰阶图。把白色与黑色之间按对数关系分为 若干 等级,称为灰度。灰度分为256阶。

在Python语言里有很多方法可以获取灰度图,PIL库提供了获取灰度图的方法Image.open();同时,opencv库提供了获取图片RGB数据的方法,图片中任何颜色都由红、绿、蓝三基色组成,假如原来某点的颜色为RGB(R,G,B),那么,我们可以平均值法,将其转换为灰度, Gray=(R+G+B)/3;


3.2 常见噪声的介绍

常见的图像噪声可以分为两种,椒盐噪声和高斯噪声。椒盐噪声为在图片中随机产生的灰度值的0或者255的的像素点,本课堂设计中,写了一个函数

def AddNoise(imarray, probility=0.05, method= "salt_pepper" ):

这个函数实现的功能就是给图片添加椒盐噪声。

高斯噪声是指它的 概率密度函数 服从 高斯分布 (即 正态分布 )的一类噪声。常见的高斯噪声包括起伏噪声、宇宙噪声、热噪声和散粒噪声等等。

3.3 滤波算法的介绍

常用的图像去噪的方法有均值滤波,中值滤波,高斯滤波;

均值滤波:有效的消除一些高斯噪声,但是很容易导致图像边的模糊。如果是需要做图像分割,使用该滤波方法会导致分割失败。不易选择均值滤波;均值滤波法的原理如下图,取1个像素点周围了8个像素点的均值,然后让这个像素点的值等于其余8个像素点的平均值。

图一 均值滤波法的原理

中值滤波:以像素为中心,指定的滑窗形状作为邻域,将邻域内的像素排序,将中值结果赋值给该邻域的像素。该方法容易去除一些孤立噪声,也能够保留大部分的边缘信息。但是前提是选择合适的滑窗,否则也容易造成图像模糊;中值滤波法的原理如下图,取1个像素点周围了8个像素点的中值,然后让这个像素点的值等于其余8个像素点的中值。

图一 中值滤波法的原理

高斯滤波:高斯滤波不是单纯的求平均值或者中值,而是调用一个二维离散的高斯函数去除噪声。能够保留更多的边缘细节,图像更为清晰,平滑效果也更加柔和;

高斯滤波的原理如下图:

图三 高斯滤波法的原理


四、程序的运行截图

下面两张图片分别为将RGB原彩色图片,转换后的灰度图。

图四、五 原彩色图和灰度图

加入椒盐噪声后的图片:

图六 加入椒盐噪声后的图片

中值滤波法处理后的图片:

图七 中值滤波后的图片

源代码:

import cv2
import numpy as np
from PIL import Image
cv2.waitKey(0)
#添加椒盐噪声
def AddNoise(imarray, probility=0.05, method="salt_pepper"):  # 灰度图像
    #获取图片的长和宽
    height, width = imarray.shape[:2]
    for i in range(height):
        for j in range(width):
            if np.random.random(1) < probility:  # 随机加盐或者加椒
                if np.random.random(1) < 0.5:
                    imarray[i, j] = 0
                else:
                    imarray[i, j] = 255
    return imarray
#中值滤波法
def medianBlur(image, ksize=2 ):
    中值滤波,去除椒盐噪声
    args:
        image:输入图片数据,要求为灰度图片
        ksize:滤波窗口大小
    return:
        中值滤波之后的图片
    rows, cols = image.shape[:2]
    # 输入校验
    half = ksize // 2
    startSearchRow = half
    endSearchRow = rows - half - 1
    startSearchCol = half
    endSearchCol = cols - half - 1
    dst = np.zeros((rows, cols), dtype=np.uint8)
    # 中值滤波
    for y in range(startSearchRow, endSearchRow):
        for x in range(startSearchCol, endSearchCol):
            window = []
            for i in range(y - half, y + half + 1):
                for j in range(x - half, x + half + 1):
                    window.append(image[i][j])
            # 取中间值
            window = np.sort(window, axis=None)
            if len(window) % 2 == 1:
                medianValue = window[len(window) // 2]
            else:
                medianValue = int((window[len(window) // 2] + window[len(window) // 2 + 1]) / 2)
            dst[y][x] = medianValue
    return dst
#自适应中值滤波法
def amp_medianBlur(img, ksize=2 ):
    # 图像边缘扩展
    #为保证边缘的像素点可以被采集到,必须对原图进行像素扩展。
    #一般设置的最大滤波窗口为7,所以只需要向上下左右各扩展3个像素即可采集到边缘像素。
    m,n = img.shape[:2]
    Nmax = 3
    imgn = np.zeros((m + 2 * Nmax, n + 2 * Nmax),dtype=np.uint8)
    imgn[ Nmax : (m + Nmax ) , Nmax : (n + Nmax ) ] = img[:,:,0].copy() # 将原图覆盖在imgn的正中间
    # 下面开始向外扩展,即把边缘的像素向外复制
    imgn[0: Nmax, Nmax: n + Nmax]=img[0: Nmax, 0 : n,0].copy() # 扩展上边界
    imgn[0: m + Nmax, n + Nmax : n + 2 * Nmax]=imgn[0: m+Nmax, n: n + Nmax].copy() # 扩展右边界
    imgn[m + Nmax: m + 2 * Nmax, Nmax : n + 2 * Nmax]=imgn[m : m + Nmax,Nmax : n + 2 * Nmax].copy() #扩展下边界
    imgn[0: m + 2 * Nmax,0: Nmax]=imgn[0: m + 2 * Nmax,Nmax : 2 * Nmax].copy() # 扩展左边界
    re = imgn.copy()  # 扩展之后的图像
    # 得到不是噪声点的中值
    for i in range(Nmax,m+Nmax+1):
        for j in range(Nmax,n+Nmax+1):
            r = 1 # 初始向外扩张1像素,即滤波窗口大小为3
            while r!=Nmax+1: #当滤波窗口小于等于7时(向外扩张元素小于4像素)
                W = imgn[i - r-1:i + r,j - r-1: j + r].copy()
                Imin,Imax  = np.min(W),np.max(W) # 最小灰度值 # 最大灰度值
                # 取中间值
                window = np.sort(W, axis=None)
                if len(window) % 2 == 1:
                    Imed = window[len(window) // 2]
                else:
                    Imed = int((window[len(window) // 2] + window[len(window) // 2 + 1]) / 2)
                if Imin < Imed and Imed < Imax: # 如果当前窗口中值不是噪声点,那么就用此次的中值为替换值
                    break;
                else:
                    r = r + 1; #否则扩大窗口,继续判断,寻找不是噪声点的中值
                # 判断当前窗口内的中心像素是否为噪声,是就用前面得到的中值替换,否则不替换
            if Imin < imgn[i, j] and imgn[i, j] < Imax:  # 如果当前这个像素不是噪声,原值输出
                re[i, j] = imgn[i, j].copy()
            else:  # 否则输出邻域中值
                re[i, j] = Imed
    return re
#读取图片
image = cv2.imread("sgs.png")
width = image.shape[0]
height = image.shape[1]
grayimg = np.zeros([width,height,1],np.uint8)
for i in range(height):
    for j in range(width):
        grayimg[i,j] = 0.299 * image[i,j][0] + 0.587 * image[i,j][1] +  0.114 * image[i,j][2]
cv2.imshow('srcImage', image)
cv2.imshow('grayImage', grayimg)
img_addnoise = AddNoise(grayimg)
cv2.imshow('addnoise_Image', img_addnoise)
#remig2 = amp_medianBlur(img_addnoise)