深度CV基础——图像噪声和滤波

一,图像噪声

1.图像噪声的概念:

图像噪声是图像在获取或是传输过程中受到随机信号干扰,妨碍人们对图像理解及分析处理的信号。很多时候将图像噪声看做多维随机过程,因而描述噪声的方法完全可以借用随机过程的描述, 也就是使用随机过程的描述,也就是用它的高斯分布函数概率密度分布函数。图像噪声的产生来自图像获取中的环境条件和传感元器件自身的质量,图像在传输过程中产生图像噪声的主要因素是所用的传输信道受到了噪声的污染。

2.信噪比:

在噪声的概念中,通常采用信噪比(Signal-Noise Rate, SNR)衡量图像噪声。通俗的讲就是信号占多少,噪声占多少,SNR越小,噪声占比越大。在这里,采用信号像素点的占比充当SNR,以衡量所添加噪声的多少。

举个例,假设一张图像的宽x高 = 10x10 ,共计100个像素,想让其中20个像素点变为噪声,其余80 个像素点保留原值,则这里定义的SNR=80/100 = 0.8 。

3.高斯噪声

一个正常的高斯采样分布公式G(d), 得到输出像素Pout.
Pout = Pin + XMeans + sigma *G(d)
其中d为一个线性的随机数,G(d)是随机数的高斯分布随机值。Pin是一个输入像素。
给一副数字图像加上高斯噪声的处理顺序如下:

  1. 输入参数sigma 和 X mean
  2. 以系统时间为种子产生一个伪随机数
  3. 将伪随机数带入G(d)得到高斯随机数
  4. 根据输入像素计算出输出像素
  5. 重新将像素值放缩在[0 ~ 255]之间
  6. 循环所有像素
  7. 输出图像
    如下示例:

    代码如下:
import cv2
import random

def GaussianNoise(src, means, sigma, percetage):
    NoiseImg = src
    # 获取需要加入噪点的个数
    NoiseNum = int(percetage * NoiseImg.shape[0] * NoiseImg.shape[1])
    for i in range(NoiseNum):
        # 产生和之前不一样的随机值 对边缘不处理
        randX = random.randint(0, src.shape[0] - 1)
        randY = random.randint(0, src.shape[1] - 1)
        # 此处原有像素值上面加上随机数
        NoiseImg[randX, randY] = NoiseImg[randX, randY] + random.gauss(means, sigma=sigma)
        # 对像素值进行限幅
        if NoiseImg[randX, randY] < 0:
            NoiseImg[randX, randY] = 0
        if NoiseImg[randX, randY] > 255:
            NoiseImg[randX, randY] = 255

    return NoiseImg


if __name__ == '__main__':
    img = cv2.imread('lenna.png', 0)
    img1 = GaussianNoise(img, 8, 4, 0.7)

    img = cv2.imread('lenna.png')
    img2 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    cv2.imshow('source', img2)
    cv2.imshow('lenna_GaussianNoise', img1)

    cv2.waitKey(0)

4.椒盐噪声

椒盐噪声又称为脉冲噪声,它是一种随机出现的白点(像素值最大)或者黑点(像素值最小)。
椒盐噪声 = 椒噪声 (pepper noise)+ 盐噪声(salt noise)。 椒盐噪声的值为0(椒)或者255(盐)。前者是低灰度噪声,后者属于高灰度噪声。一般两种噪声同时出现,呈现在图像(灰度图)上就是黑白杂点。对于彩色图像,也有可能表现为在单个像素BGR三个通道随机出现的255或0。
对于图像上面加上椒盐噪声的步骤如下:

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

    代码如下:
import cv2
import numpy as np
import random


def PeperNoise(src, percetage):
    NoiseImg = src
    NoiseNum = int(percetage * NoiseImg.shape[0] * NoiseImg.shape[1])
    for i in range(NoiseNum):
        # 随机生成要改变像素值的像素点坐标
        randx = random.randint(0, src.shape[0] - 1)
        randy = random.randint(0, src.shape[1] - 1)
        # 使用random.random()生成0-1的浮点数 所以白点和黑点各一半概率
        if random.random() < 0.5:
            NoiseImg[randx, randy] = 0
        else:
            NoiseImg[randx, randy] = 255

    return NoiseImg

if __name__ == '__main__':
    img = cv2.imread('lenna.png', 0)
    img1 = PeperNoise(img, 0.7)

    img = cv2.imread('lenna.png')
    img2 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    cv2.imshow('source', img2)
    cv2.imshow('lenna_GaussianNoise', img1)

    cv2.waitKey(0)

5.总结

对于图像噪声来说改变的就是图像像素点的像素值(灰度值),有可能这种改变服从某种分布(高斯分布,泊松分布等)或者有别的规律,但是最终都是改变像素值,需要加入噪声的时候也可以直接调用对应的接口。
调用OpenCV库实现如下:

import cv2 as cv
import numpy as np
from PIL import Image
from skimage import util

'''
def random_noise(image, mode='gaussian', seed=None, clip=True, **kwargs):
功能:为浮点型图片添加各种随机噪声
参数:
image:输入图片(将会被转换成浮点型),ndarray型
mode: 可选择,str型,表示要添加的噪声类型
	gaussian:高斯噪声
	localvar:高斯分布的加性噪声,在“图像”的每个点处具有指定的局部方差。
	poisson:泊松噪声
	salt:盐噪声,随机将像素值变成1
	pepper:椒噪声,随机将像素值变成0或-1,取决于矩阵的值是否带符号
	s&p:椒盐噪声
	speckle:均匀噪声(均值mean方差variance),out=image+n*image
seed: 可选的,int型,如果选择的话,在生成噪声前会先设置随机种子以避免伪随机
clip: 可选的,bool型,如果是True,在添加均值,泊松以及高斯噪声后,会将图片的数据裁剪到合适范围内。如果谁False,则输出矩阵的值可能会超出[-1,1]
mean: 可选的,float型,高斯噪声和均值噪声中的mean参数,默认值=0
var:  可选的,float型,高斯噪声和均值噪声中的方差,默认值=0.01(注:不是标准差)
local_vars:可选的,ndarry型,用于定义每个像素点的局部方差,在localvar中使用
amount: 可选的,float型,是椒盐噪声所占比例,默认值=0.05
salt_vs_pepper:可选的,float型,椒盐噪声中椒盐比例,值越大表示盐噪声越多,默认值=0.5,即椒盐等量
--------
返回值:ndarry型,且值在[0,1]或者[-1,1]之间,取决于是否是有符号数
'''

img = cv.imread("lenna.png")
noise_gs_img=util.random_noise(img,mode='gaussian')

cv.imshow("source", img)
cv.imshow("lenna",noise_gs_img)
#cv.imwrite('lenna_noise.png',noise_gs_img)
cv.waitKey(0)
cv.destroyAllWindows()

二,图像滤波

1.图像滤波的一些简单的基础概念:

  1. 图像滤波,即在尽量保留图像细节特征的条件下对目标图像的噪声进行抑制,是图像预处理中不可缺少的操作,其处理效果的好坏将直接影响到后续图像处理和分析的有效性和可靠性。
  2. 消除图像中的噪声成分叫作图像的平滑化或滤波操作。信号或图像的能量大部分集中在幅度谱的低频和中频段是很常见的,而在较高频段,感兴趣的信息经常被噪声淹没。因此一个能降低高频成分幅度的滤波器就能够减弱噪声的影响。
  3. 平滑滤波是低频增强的空间域滤波技术。它的目的有两类:一类是模糊;另一类是消除噪音。空间域的平滑滤波一般采用简单平均法进行,就是求邻近像元点的平均亮度值。邻域的大小与平滑的效果直接相关, 邻域越大平滑的效果越好,但邻域过大,平滑会使边缘信息损失的越大,从而使输出的图像变得模糊,因此需合理选择邻域的大小。
  4. 关于滤波器,一种形象的比喻法是:我们可以把滤波器想象成一个包含加权系数的窗口,当使用这个滤波器平滑处理图像时,就把这个窗口放到图像之上,透过这个窗口来看我们得到的图像。

2.均值滤波:

均值滤波,是图像处理中最常用的手段,从频率域观点来看均值滤波是一种低通滤波器,高频信号将会去掉,因此可以帮助消除图像尖锐噪声,实现图像平滑,模糊等功能。理想的均值滤波是用每个像素和它周围像素计算出来的平均值替换图像中每个像素。

•从左到右从上到下计算图像中的每个像素,最终得到处理后的图像。
•均值滤波可以加上两个参数,即迭代次数,Kernel数据大小。
•一个相同的Kernel,但是多次迭代就会效果越来越好。
•同样,迭代次数相同,Kernel矩阵越大,均值滤波的效果就越明显。
深度CV基础——图像噪声和滤波_第1张图片
降低噪声的同时使图像产生模糊,特别是景物的边缘和细节部分。

3.中值滤波

中值滤波也是消除图像噪声最常见的手段之一,特别是消除椒盐噪声,中值滤波的效果要比均值滤波更好。中值滤波跟均值滤波唯一不同是,不是用均值来替换中心每个像素,而是将周围像素和中心像素排序以后,取中值。
一个3X3大小的中值滤波如下:
深度CV基础——图像噪声和滤波_第2张图片
优点:抑制效果很好,画面的清析度基本保持;
缺点:对高斯噪声的抑制效果不是很好。

4.最大最小值滤波

最大最小值滤波是一种比较保守的图像处理手段,与中值滤波类似,首先要排序周围像素和中心像素值,然后将中心像素值与最小和最大像素值比较,如果比最小值小,则替换中心像素为最小值, 如果中心像素比最大值大,则替换中心像素为最大值。
一个Kernel矩阵为3X3的最大最小值滤波如下:
深度CV基础——图像噪声和滤波_第3张图片

5.双边滤波

一种同时考虑了像素空间差异与强度差异的滤波器,因此具有保持图像边缘的特性
下面显示高斯滤波器
深度CV基础——图像噪声和滤波_第4张图片
其中W是权重,i和j是像素索引。公式中可以看出,权重只和像素之间的空间距离有关系,无论图像的内容是什么,都有相同的滤波效果。
双边滤波器,它只是在原有高斯函数的基础上加了一项:
深度CV基础——图像噪声和滤波_第5张图片
其中 I 是像素的强度值,所以在强度差距大的地方(边缘),权重会减小,滤波效应也就变小。总体而言,在像素强度变换不大的区域,双边滤波有类似于高斯滤波的效果,而在图像边缘等强度梯度较大的地方,可以保持梯度。

6.限幅滤波(又称程序判断滤波)

• 方法: 根据经验判断,确定两次采样允许的最大偏差值(设为top)每次检测到新值时判断:如果本次值与上次值之差<=top,则本次值有效 如果本次值与上次值之差>top,则本次值无效,放弃本次值,用上次值代替本次值
•优点: 能有效克服因偶然因素引起的脉冲干扰
•缺点: 无法抑制周期性的干扰;平滑度差

7.上述滤波的Opencv接口:

上述使用椒盐噪声为源图像做滤波处理:
深度CV基础——图像噪声和滤波_第6张图片

import cv2
import numpy as np
from PIL import Image
from skimage import util
import matplotlib.pyplot as plt

img = cv2.imread("lenna.png", 0)
noise_gs_img=util.random_noise(img, mode='pepper', amount=0.7)

########     四个不同的滤波器    #########

# 均值滤波
img_mean = cv2.blur(img, (5,5))

# 高斯滤波
img_Guassian = cv2.GaussianBlur(img,(5,5),0)

# 中值滤波
img_median = cv2.medianBlur(img, 5)

# 双边滤波
img_bilater = cv2.bilateralFilter(img,9,75,75)

# 展示不同的图片
titles = ['srcImg', 'mean', 'Gaussian', 'median', 'bilateral']
imgs = [noise_gs_img, img_mean, img_Guassian, img_median, img_bilater]

for i in range(5):
    plt.subplot(2,3,i+1)#注意,这和matlab中类似,没有0,数组下标从1开始
    plt.imshow(imgs[i])
    plt.title(titles[i])
plt.show()

你可能感兴趣的:(智能车笔记,python,深度学习,opencv,机器学习)