Skip to content

Latest commit

 

History

History
267 lines (203 loc) · 11.8 KB

8.图像去噪(图像平滑).md

File metadata and controls

267 lines (203 loc) · 11.8 KB

图像噪声

由于图像采集、处理等过程都存在一定的误差而存在响应的噪声。其中,噪声包括高斯噪声、均匀分布噪声、脉冲噪声(椒盐噪声)等

高斯噪声(Gaussian noise) 由于高斯噪声在空间和频域中数学上的易处理性,这种噪声(也称为正态噪声)模型经常被用于实践中。高斯随机变量z的Probability Density Function(PDF)由下式给出: $$ p(z)=\frac{1}{\sqrt{2 \pi} \sigma} e^{\frac{-(z-\mu)^{2}}{2 \sigma^{2}}} $$ 其中z表示灰度值,μ表示z的平均值或期望值,σ表示z的标准差。标准差的平方σ2称为z的方差。高斯函数的曲线如图所示。

当z服从上式的高斯分布时候,其值有70%落在[(μ-σ),(μ+σ)]内,有95%落在[(μ-2σ),( μ+2σ)]范围内。

均匀分布噪声 (Uniform noise) 均匀噪声分布的概率密度: $$ p(z)=\left{\begin{array}{l}{\frac{1}{b-a}, a \leq z \leq b} \ {0, { 其他}}\end{array}\right. $$ 概率密度函数的期望值和方差可由下式给出: $$ \mu=\frac{a+b}{2} \quad \sigma^{2}=\frac{(b-a)^{2}}{12} $$ 脉冲噪声(椒盐噪声) (双极)脉冲噪声的PDF: $$ p(z)=\left{\begin{array}{ll}{P_{a}} & {z=a} \ {P_{b}} & {z=b} \ {0} & 其他{}\end{array}\right. $$ 如果b>a,灰度值b在图像中将显示为一个亮点,a的值将显示为一个暗点。若Pa或Pb为零,则脉冲噪声称为单极脉冲。如果Pa和Pb均不可能为零,尤其是它们近似相等时,脉冲噪声值将类似于随机分布在图像上的胡椒和盐粉微粒。由于这个原因,双极脉冲噪声也称为椒盐噪声。同时,它们有时也称为散粒和尖峰噪声。

噪声脉冲可以是正的,也可以是负的。在一幅图像中,脉冲噪声总是数字化为最小值或最大值(纯黑或纯白)。负脉冲以一个黑点(胡椒点)出现在图像中。由于相同的原因,正脉冲以白点(盐点)出现在图像中。

图像平滑(图像模糊)

在已知噪声模型的基础上,对噪声的空间域滤波。

主要包括:均值滤波器、中值滤波器、修正后的阿尔法均值滤波器、最大/最小滤波器、中点滤 波器。

均值滤波器(Mean Filters) 采用均值滤波模板对图像噪声进行滤除。令${S_{x y}}$ 表示中心在(x, y)点,尺寸为m×n 的矩形子图像窗口的坐标组。 均值滤波器 $$ \hat{f}(x, y)=\frac{1}{m n} \sum_{(s, t) \in S_{x y}} g(s, t) $$ 由一个归一化卷积框完成的。它只是用卷积框覆盖区域所有像素的平均值来代替中心元素。可以使用函数 cv2.blur() 和 cv2.boxFilter() 来完这个任务。我们需要设定卷积框的宽和高。下面是一个 3x3 的归一化卷积框: $$ K=\frac{1}{9}\left[\begin{array}{lll}{1} & {1} & {1} \ {1} & {1} & {1} \ {1} & {1} & {1}\end{array}\right] $$ 注意:如果你不想使用归一化卷积框,你应该使用 cv2.boxFilter(),这时要传入参数 normalize=False。

cv2.blur(src, dst, ksize, anchor, borderType)

参数意义如下:

  • src:输入图像
  • dst:输出图像
  • ksize:卷积核的大小
  • anchor:默认值 (-1,-1) ,表示核中心
  • borderType:边界类型

例子

def img_show(name,img):
    """matplotlib图像显示函数
    name:字符串,图像标题
    img:numpy.ndarray,图像
    """
    if len(img.shape) == 3:
        img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
    plt.imshow(img,'gray')
    #plt.xticks([])
    #plt.yticks([])
    plt.xlabel(name,fontproperties='FangSong',fontsize=12)
    

if __name__=="__main__":

    img1 = cv2.imread("Fig0333(a)(test_pattern_blurring_orig).tif")
    
    img2 = cv2.blur(img1,(5,5))
    plt.figure(figsize=(10,8),dpi=80)
    plt.subplot(121)
    img_show('原图',img1)
    plt.subplot(122)
    img_show('均值滤波',img2)

高斯模糊(Gaussian Blur) $$ G(x, y)=e^{-\frac{x^{2}+y^{2}}{2 \sigma^{2}}} $$ 由于Gaussian函数有着一些良好的特性,对二维连续Gaussian分布经采样、量化,并使模板归一化,便可得到二维Gaussian滤波模板。 $$ K=\frac{1}{16}\left[\begin{array}{ccc}{1} & {2} & {1} \ {2} & {4 } & {2} \ {1} & {2} & {1}\end{array}\right] $$ ${\sigma}$是高斯分布的标准差,又称滤波器的尺度,决定了高斯滤波器作用邻域的空间范围。随着逐渐远离滤波中心,G(x,y)权值逐渐减小到零,这表明离滤波器中心较近的像素比远处的像素更重要。因此,高斯低通滤波器是一种加权均值滤波器。

把卷积核换成高斯核(简单来说,方框不变,将原来每个方框的值是相等的,现在里面的值是符合高斯分布的,方框中心的值最大,其余方框根据距离中心元素的距离递减,构成一个高斯小山包。原来的求平均数现在变成求加权平均数,全就是方框里的值)。实现的函数是 cv2.GaussianBlur()。我们需要指定高斯核的宽和高(必须是奇数)。以及高斯函数沿 X,Y 方向的标准差。如果我们只指定了 X 方向的的标准差,Y 方向也会取相同值。如果两个标准差都是 0,那么函数会根据核函数的大小自己计算。高斯滤波可以有效的从图像中去除高斯噪音。如果你愿意的话,你也可以使用函数 cv2.getGaussianKernel() 自己构建一个高斯核。 如果要使用高斯模糊的话,上边的代码应该写成:

GaussianBlur(src, ksize, sigmaX, sigmaY, borderType)
#0是指根据窗口大小(5,5)来计算高斯函数标准差
blur = cv2.GaussianBlur(img,(5,5),0)

参数意义如下:

  • src:输入图像
  • ksize:卷积核的大小
  • sigmaX:在X方向高斯分布的标准差(二维高斯核函数可以拆分成水平方向和竖直方向的一维高斯核函数)
  • sigmaY:在Y方向高斯分布的标准差(如果只会设置sigmaX,默认sigmaY=sigmaX)
  • borderType:边界类型

例子:对椒盐噪声的图像进行高斯模糊

def img_show(name,img):
    """matplotlib图像显示函数
    name:字符串,图像标题
    img:numpy.ndarray,图像
    """
    if len(img.shape) == 3:
        img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
    plt.imshow(img,'gray')
    #plt.xticks([])
    #plt.yticks([])
    plt.xlabel(name,fontproperties='FangSong',fontsize=12)
    

if __name__=="__main__":

    img1 = cv2.imread("Fig0335(a)(ckt_board_saltpep_prob_pt05).tif")
    
#    img2 = cv2.blur(img1,(5,5))
    img2 = cv2.GaussianBlur(img1,(7,7),0)
    img3 = cv2.GaussianBlur(img1,(7,7),5)
    img4 = cv2.GaussianBlur(img1,(7,7),10)
    
    plt.figure(figsize=(10,8),dpi=80)
    plt.subplot(221)
    img_show('原图',img1)
    plt.subplot(222)
    img_show('高斯模糊($\sigma$=0)',img2)    
    plt.subplot(223)
    img_show('高斯模糊($\sigma$=5)',img3)
    plt.subplot(224)
    img_show('高斯模糊($\sigma$=10)',img4)

中值滤波器(Median filter) $$ \hat{f}(x, y)=\underset{(s, t) \in S_{x y}}{\operatorname{Med}}{g(s, t)} $$ 中值滤波可去掉椒盐噪声,平滑效果优于均值滤波,在抑制随机噪声的同时能保持图像边缘少受模糊。

这个滤波器经常用来去除椒盐噪声。前面的滤波器都是用计算得到的一个新值来取代中心像素的值,而中值滤波是用中心像素周围(也可以使他本身)的值来取代它。它能有效的去除噪声。卷积核的大小也应该是一个奇数。

median = cv2.medianBlur(src,dst,ksize)

参数意义如下:

  • src:输入图像
  • dst:输出图像
  • ksize:卷积核的大小

例子

def img_show(name,img):
    """matplotlib图像显示函数
    name:字符串,图像标题
    img:numpy.ndarray,图像
    """
    if len(img.shape) == 3:
        img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
    plt.imshow(img,'gray')
    #plt.xticks([])
    #plt.yticks([])
    plt.xlabel(name,fontproperties='FangSong',fontsize=12)
    

if __name__=="__main__":

    img1 = cv2.imread("gooey.jpg")
  
    img2 = cv2.medianBlur(img1,5)
    
    plt.figure(figsize=(10,8),dpi=80)
    plt.subplot(121)
    img_show('原图',img1)
    plt.subplot(122)
    img_show('中值滤波',img2)    

双边滤波(bilateral Filter)

函数 cv2.bilateralFilter() 能在保持边界清晰的情况下有效的去除噪音。但是这种操作与其他滤波器相比会比较慢。我们已经知道高斯滤波器是求中心点邻近区域像素的高斯加权平均值。这种高斯滤波器只考虑像素之间的空 间关系,而不会考虑像素值之间的关系(像素的相似度)。所以这种方法不会考虑一个像素是否位于边界。因此边界也会别模糊掉,而这正不是我们想要。双边滤波在同时使用空间高斯权重和灰度值相似性高斯权重。空间高斯函 数确保只有邻近区域的像素对中心点有影响,灰度值相似性高斯函数确保只有与中心像素灰度值相近的才会被用来做模糊运算。所以这种方法会确保边界不会被模糊掉,因为边界处的灰度值变化比较大。

双边滤波是一种非线性的滤波方法,是结合图像的空间邻近度和像素值相似度的一种折中处理,同时考虑空域信息和灰度相似性,优点是可以做边缘保存。在边缘附近,离得较远的像素不会对边缘上的像素值影响太多,这样就保证了边缘附近像素值的保存。但是由于保存了过多的高频信息,对于彩色图像里的高频噪声,双边滤波器不能很好地滤掉,只能对低频噪声很好地滤波。

cv2.bilaralFilter(src,dst,d,sigmaColor,sigmaSpace,borderType=BORDER_DEFAULT)
#9 邻域直径,两个75分别是空间高斯函数标准差,灰度值相似性高斯函数标准差
blur = cv2.bilateralFilter(img,9,75,75)

参数意义如下:

  • src:输入图像
  • dst:输出图像
  • d:表示在过滤过程中每个像素邻域的直径。如果这个值被设为非正数,那么opencv会从第五个参数sigmaSpace来计算出它。
  • sigmaColor:颜色空间滤波器的sigma值,这个参数的值越大,就表明该像素领域内有越宽广的颜色会被混到一起
  • sigmaSpace:坐标空间滤波器的sigma值,坐标空间的标注方差。它的数值越大,意味着越远的像素会相互影响,从而使更大的区域中足够相似的颜色获取相同的颜色,当d>0时,d指定了尺寸,此参数没什么用,否则,d正比于这个参数值。
  • borderType:用于推断图像外部像素的某种边界模式。

例子

def img_show(name,img):
    """matplotlib图像显示函数
    name:字符串,图像标题
    img:numpy.ndarray,图像
    """
    if len(img.shape) == 3:
        img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
    plt.imshow(img,'gray')
    #plt.xticks([])
    #plt.yticks([])
    plt.xlabel(name,fontproperties='FangSong',fontsize=12)
    

if __name__=="__main__":

    img1 = cv2.imread("gooey.jpg")

    img2 = cv2.bilateralFilter(img1,9,75,75)
    
    plt.figure(figsize=(10,8),dpi=80)
    plt.subplot(121)
    img_show('原图',img1)
    plt.subplot(122)
    img_show('双边滤波',img2)