python 图像平滑去噪(噪声+滤波器)

记录自己用python加opencv实现的图像处理的入门操作,各种平滑去噪滤波器的实现。
包括有:产生的椒盐噪声、高斯噪声等等,以及使用的中值滤波、平均滤波、高斯滤波等等。
分成了两部分来实现:一是自编写函数来实现,二是调用opencv中的相应函数,对比效果。

噪声的产生:分别是椒盐噪声和高斯噪声,原理的话可以参考别人的博客或我之后再补充,噪声就是在原来的图像上以一定的特殊规律给图像增添一些像素,使图像变得模糊等等。

1.噪声的自编写

椒盐噪声:
输入图像和自定义的噪声阈值,输出处理后的图像

# 向图片中添加椒盐噪声
def salt_pepper_noise(image, prob):  # prob:盐噪声阈值,由用户自己决定
    output = np.zeros(image.shape, np.uint8)
    thres = 1 - prob  # 胡椒噪声阈值
    for i in range(image.shape[0]):  # 遍历整个图片的灰度级
        for j in range(image.shape[1]):
            randomnum = random.random()  # 生成一个随机0-1之间的随机数
            if randomnum < prob:  # 如果随机数大于盐噪声阈值0.1,则将此位置灰度级的值设为0,即添加盐噪声
                output[i][j] = 0
            elif randomnum > thres:  # 如果随机数大于胡椒噪声阈值1-0.1,则将此位置灰度级的输出设为255,即添加胡椒噪声
                output[i][j] = 255
            else:  # 如果随机数处于两者之间,则此位置的灰度级的值等于原图的灰度级值
                output[i][j] = image[i][j]
    return output

高斯噪声:
输入图像,自定义的参数:均值、方差,输出的是处理后的图像

# 向图片中添加高斯噪声
def gasuss_noise(image, mean=0, var=0.001):         # mean : 均值,var : 方差
    image = np.array(image/255, dtype=float)
    noise = np.random.normal(mean, var ** 0.5, image.shape)  # 使用numpy库中的函数生成正态分布矩阵,对应数据分别为概率均值,概率标准差,图像的大小
    output = image + noise  # 输出结果为原图灰度级概率与噪声概率相加
    output_handle = np.array([[[0]*3 for i in range(output.shape[1])] for i in range(output.shape[0])], dtype=float)
    # 处理后最终输出矩阵将齐大小设置为与原图一样
    if output.min() < 0:  # 确定一个比较中间值
        low_clip = -1.
    else:
        low_clip = 0.
    for i in range (output.shape[0]):  # 遍历整个三位矩阵
        for j in range (output.shape[1]):
            for k in range (output.shape[2]):
                if output[i][j][k] < low_clip:  # 将输出的概率矩阵内的值限定在(-1,1)范围内
                    output_handle[i][j][k] = low_clip   # 使其之后*255变为灰度级时不会超出[0-255]的范围
                elif output[i][j][k] > 1.0:
                    output_handle[i][j][k] = 1.0
                else:
                    output_handle[i][j][k] = output[i][j][k]    # 在最大值和最小值之间的不变
    output = np.uint8(output_handle*255)   # 将处理后的灰度级转化为[0-255]的整数级
    return output

加性噪声:

# 向图片中添加加性噪声
def addrandom_noise(image,prob=0.1):
    output = image   # 将原始图像数据拷贝至输出矩阵
    n = random.randint(1, 1000) + int(prob*20000)
    for k in range(n-500):
        a = random.randint(0, 50)
        b = random.randint(0, 50)
        c = random.randint(0, 50)
        i = random.randint(0, image.shape[0]-1)
        j = random.randint(0, image.shape[1]-1)
        output[i][j][0] = 255-a
        output[i][j][1] = 255-b
        output[i][j][2] = 255-c
    for k in range(n):
        a = random.randint(0, 50)
        b = random.randint(0, 50)
        c = random.randint(0, 50)
        i = random.randint(0, image.shape[0]-1)
        j = random.randint(0, image.shape[1]-1)
        output[i][j][0] = a
        output[i][j][1] = b
        output[i][j][2] = c
    return output

2.平滑去噪滤波器的自编写

设计了均值滤波、中值滤波、高斯滤波,可分别对应处理以上的三种噪声,效果较好。
具体的对应情况可自己比较一下哦。

中值滤波:

# 中值滤波 a为要处理的图像  windowsize为采用的模版大小
def medianfliter(a, windowsize):
    output = a
    if windowsize == 3 :
        output1 = np.zeros(a.shape, np.uint8)
        for i in range(1, output.shape[0]-1):  # 求齐周围9个方格与模版进行冒泡排序
            for j in range(1, output.shape[1]-1):
                value1 = [output[i-1][j-1], output[i-1][j], output[i-1][j+1], output[i][j-1], output[i][j], output[i][j+1], output[i+1][j-1], output[i+1][j], +output[i+1][j+1]]
                np.sort(value1)   # 对这九个数进行排序
                value = value1[4]    # 中值为排序后中间这个数的正中间
                output1[i-1][j-1] = value
    elif windowsize == 5:
        output1 = np.zeros(a.shape, np.uint8)
        for i in range(2, output.shape[0]-2):       # 求齐周围25个方格与模版进行卷积
            for j in range(2, output.shape[1]-2):
                value1 = [output[i-2][j-2],output[i-2][j-1],output[i-2][j],output[i-2][j+1],output[i-2][j+2],output[i-1][j-2],output[i-1][j-1],output[i-1][j],output[i-1][j+1],\
                            output[i-1][j+2],output[i][j-2],output[i][j-1],output[i][j],output[i][j+1],output[i][j+2],output[i+1][j-2],output[i+1][j-1],output[i+1][j],output[i+1][j+1],\
                            output[i+1][j+2],output[i+2][j-2],output[i+2][j-1],output[i+2][j],output[i+2][j+1],output[i+2][j+2]]
                value1.sort()   # 对这九个数进行排序
                value = value1[12]    # 中值为排序后中间这个数的正中间
                output1[i-2][j-2] = value   # 将计算结果填入原本位置
    else :
        print('模版大小输入错误,请输入3或5,分别代表3*3或5*5模版!')
    return output1

均值滤波:

# 均值滤波 a为要处理的图像  windowsize为采用的模版大小
def meanflite(a, windowsize):
    output = a
    if windowsize == 3:
        window = np.ones((3, 3)) / 3 ** 2  # 生成3*3模版
        output1 = np.zeros(a.shape, np.uint8)
        for i in range(1, output.shape[0] - 1):  # 求齐周围9个方格与模版进行卷积
            for j in range(1, output.shape[1] - 1):
                value = (output[i - 1][j - 1] * window[0][0] + output[i - 1][j] * window[0][1] + output[i - 1][j + 1] *
                         window[0][2] + \
                         output[i][j - 1] * window[1][0] + output[i][j] * window[1][1] + output[i][j + 1] * window[1][
                             2] +\
                         output[i + 1][j - 1] * window[2][0] + output[i + 1][j] * window[2][1] + output[i + 1][j + 1] *
                         window[2][2])
                output1[i - 1][j - 1] = value  # 将计算结果填入原本位置
    elif windowsize == 5:
        window = np.ones((5, 5)) / 5 ** 2  # 生成5*5模版
        output1 = np.zeros(a.shape, np.uint8)
        for i in range(2, output.shape[0] - 2):  # 求齐周围25个方格与模版进行卷积
            for j in range(2, output.shape[1] - 2):
                value = (output[i - 2][j - 2] * window[0][0] + output[i - 2][j - 1] * window[0][1] + output[i - 2][j] *
                         window[0][2] + output[i - 2][j + 1] * window[0][3] + output[i - 2][j + 2] * window[0][4] + \
                         output[i - 1][j - 2] * window[1][0] + output[i - 1][j - 1] * window[1][1] + output[i - 1][j] *
                         window[1][2] + output[i - 1][j + 1] * window[1][3] + output[i - 1][j + 2] * window[1][4] + \
                         output[i][j - 2] * window[2][0] + output[i][j - 1] * window[2][1] + output[i][j] * window[2][
                             2] + output[i][j + 1] * window[2][3] + output[i][j + 2] * window[2][4] + \
                         output[i + 1][j - 2] * window[3][0] + output[i + 1][j - 1] * window[3][1] + output[i + 1][j] *
                         window[3][2] + output[i + 1][j + 1] * window[3][3] + output[i + 1][j + 2] * window[3][4] + \
                         output[i + 2][j - 2] * window[4][0] + output[i + 2][j - 1] * window[4][1] + output[i + 2][j] *
                         window[4][2] + output[i + 2][j + 1] * window[4][3] + output[i + 2][j + 2] * window[4][4])
                output1[i - 2][j - 2] = value  # 将计算结果填入原本位置
    else:
        print('模版大小输入错误,请输入3或5,分别代表3*3或5*5模版!')

    return output1

高斯滤波:

ef gaussian(im):
    im = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
    b = np.array([[2, 4,  5,  2,  2],
               [4, 9,  12, 9,  4],
               [5, 12, 15, 12, 5],
               [4, 9,  12, 9,  4],
               [2, 4,  5,  4,  2]]) / 156
    kernel = np.zeros(im.shape)
    kernel[:b.shape[0], :b.shape[1]] = b

    fim = np.fft.fft2(im)
    fkernel = np.fft.fft2(kernel)
    fil_im = np.fft.ifft2(fim * fkernel)

    return abs(fil_im).astype(int)

3.自编写函数的主程序

我用到的包有:numpy、matplotlib.pyplot、cv2、random
主程序很好理解,读入原图,再对原图调用各种函数进行处理,再以子图的形式展示出来。

if __name__ == "__main__":
    image = cv2.imread('whl.jpg')

    plt.subplot(4, 2, 1)
    plt.imshow(image)
    plt.axis('off')
    plt.title('Original')

    salt = salt_pepper_noise(image, 0.05)

    plt.subplot(4, 2, 2)
    plt.imshow(salt)
    plt.axis('off')
    plt.title('salt')

    gauss = gasuss_noise(image)

    plt.subplot(4, 2, 3)
    plt.imshow(gauss)
    plt.axis('off')
    plt.title('gauss')

    random = addrandom_noise(image)

    plt.subplot(4, 2, 4)
    plt.imshow(random)
    plt.axis('off')
    plt.title('random')

    median = medianfliter(salt, 3)

    plt.subplot(4, 2, 5)
    plt.imshow(median)
    plt.axis('off')
    plt.title('median')

    mean = meanflite(random, 3)

    plt.subplot(4, 2, 6)
    plt.imshow(mean)
    plt.axis('off')
    plt.title('mean')

    gaussout = gaussian(gauss)

    plt.subplot(4, 2, 7)
    plt.imshow(gaussout)
    plt.axis('off')
    plt.title('gaussout')

    plt.show()

效果展示为:
在这里插入图片描述

4.opencv实现噪声+滤波器

以opencv中的函数实现各种噪声的产生和滤波器的编写更为简单,基本一行代码就可以实现调用,以下是我的整个程序:

# 图像去噪平滑滤波
# 使用opencv的自带函数实现,与自编写作比较
# 产生椒盐噪声,高斯噪声等
# 使用中值滤波,平均滤波,高斯滤波,方框滤波

import numpy as np
import cv2
import matplotlib.pyplot as plt


# 加噪声
def noise(img):
    out = img
    rows, cols, chn = img.shape
    for i in range(5000):
        x = np.random.randint(0, rows)
        y = np.random.randint(0, cols)
        out[x, y, :] = 255
    return out


if __name__ == "__main__":
    image = cv2.imread('whl.jpg')

    plt.subplot(3, 2, 1)
    plt.imshow(image)
    plt.axis('off')
    plt.title('Original')

    noise_img = noise(image)

    plt.subplot(3, 2, 2)
    plt.imshow(noise_img)
    plt.axis('off')
    plt.title('noise')

    # 均值滤波
    result1 = cv2.blur(noise_img, (5, 5))

    plt.subplot(3, 2, 3)
    plt.imshow(result1)
    plt.axis('off')
    plt.title('mean')

    # 方框滤波
    result2 = cv2.boxFilter(noise_img, -1, (5, 5), normalize=1)

    plt.subplot(3, 2, 4)
    plt.imshow(result2)
    plt.axis('off')
    plt.title('box')

    # 高斯滤波
    result3 = cv2.GaussianBlur(noise_img, (3, 3), 0)

    plt.subplot(3, 2, 5)
    plt.imshow(result3)
    plt.axis('off')
    plt.title('gaussian')

    # 中值滤波
    result4 = cv2.medianBlur(noise_img, 3)

    plt.subplot(3, 2, 6)
    plt.imshow(result4)
    plt.axis('off')
    plt.title('median')

    plt.show()

效果展示为:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Wadewhl/article/details/112234076