【数字图像处理系列五】图像滤波之空间滤波:图像平滑降噪和图像锐化


· 本系列python版本:python3.5.4

· 本系列opencv-python版本:opencv-python3.4.2.17

· 本系列使用的开发环境是jupyter notebook,是一个python的交互式开发环境,测试十分方便,并集成了vim操作,安装教程可参考:windows上jupyter notebook主题背景、字体及扩展插件配置(集成vim环境)


【数字图像处理系列三】图像增强:线性、 分段线性、 对数、 反对数、 幂律(伽马)变换、直方图均衡 一文中我们从图像灰度变换的角度阐述了图像增强的各种方式,本文我们将一起学习图像处理中重点的方式:图像滤波,图像滤波分为空间域滤波和频率域滤波,频率域滤波我们将在下一节重点说明。图像空间滤波对于图像处理主要体现在两个方面:

  1. 平滑图像,达到降低图像噪音的效果(平滑空间滤波)
  2. 锐化图像,主要目的是突出灰度的过渡部分,即突出图像的边缘(锐化空间滤波)

先上图,感受一下空间滤波对图像处理的效果(原图、经过拉普拉斯处理后的图像):
【数字图像处理系列五】图像滤波之空间滤波:图像平滑降噪和图像锐化
【数字图像处理系列五】图像滤波之空间滤波:图像平滑降噪和图像锐化




一、空间滤波原理


图像的空间滤波器有两大部分:

  1. 一个基于图像像素的矩形邻域
  2. 对矩形邻域包围的图像像素的操作方式

理解图像的矩形邻域如下图所示

【数字图像处理系列五】图像滤波之空间滤波:图像平滑降噪和图像锐化

将图像的左上角看做是空间域中的原点O,向下取为x轴,向右取为y轴,图中便显示了中心点(x,y)的一个3*3邻域。 每经过一个滤波产生一个新像素,新像素的坐标等于领域中心坐标(x,y),新像素的值是滤波操作的结果。而滤波器的类型也取决于邻域上操作的类型,如果邻域操作是线性操作,则滤波器称为线性空间滤波器;反之如果邻域操作是非线性操作,则滤波器称为非线性空间滤波器。

这里我们假设 f(x,y) 为原像素值,g(x,y) 为滤波后的像素值,则对于一个大小为M * N的图像使用大小为m * n的滤波器进行线性空间滤波,若令m=2a+1,n=2b+1,则邻域上线性操作可统一表达成下式:

【数字图像处理系列五】图像滤波之空间滤波:图像平滑降噪和图像锐化

其中x,y是可变的,以便w中的每个像素可访问f中的每个像素,我们一般称邻域内像素和滤波器模板的操作叫做卷积。下面将分别讲解平滑空间滤波器和锐化空间滤波器





二、平滑空间滤波器


1、均值滤波、加权均值滤波

均值滤波又称为线性空间滤波,利用邻域平均法,即用几个像素灰度的平均值来代替每个像素的灰度。有效抑制加性噪声,但容易引起图像模糊,尤其是会模糊图像边缘。通过下图便可看到均值滤波和加权均值滤波的区别:

【数字图像处理系列五】图像滤波之空间滤波:图像平滑降噪和图像锐化

其中左图是均值滤波,即邻域中每个像素权重相同,取邻域平均值作为中心像素点的滤波输出值,则滤波器模板计算公式为:

【数字图像处理系列五】图像滤波之空间滤波:图像平滑降噪和图像锐化

而右图滤波器模板则赋予中心点最高权重,然后随着距中心点距离的增加而减小系数值,其目的是在平滑处理中试图降低模糊,加权均值滤波器的操作如下是:

【数字图像处理系列五】图像滤波之空间滤波:图像平滑降噪和图像锐化

下面分别通过opencv-python提供的均值滤波和自定义均值滤波器两种方式实现图像的均值滤波:

import cv2
import copy
import random
import imutils
import numpy as np

img = cv2.imread('E:/peking_rw/ocr_project/base_prehandle/img/lena.png')
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

#利用opencv提供函数实现均值滤波
blur_img = cv2.blur(gray_img, (3, 3))

#在灰度图上手动实现均值滤波器
gray_avg_img = copy.deepcopy(gray_img)
for i in range(1, gray_img.shape[0]-1):
    for j in range(1, gray_img.shape[1]-1):
        sum_pix = sum([gray_img[l, k] for l in range(i-1, i+2) for k in range(j-1, j+2)])
        gray_avg_img [i, j] = int(sum_pix/9)

#在RGB彩色图上手动实现均值滤波器
rgb_avg_img = copy.deepcopy(img)
for i in range(1, img.shape[0]-1):
    for j in range(1, img.shape[1]-1):
        sum_b_pix = sum([img[l, k, 0] for l in range(i-1, i+2) for k in range(j-1, j+2)])
        sum_g_pix = sum([img[l, k, 1] for l in range(i-1, i+2) for k in range(j-1, j+2)])
        sum_r_pix = sum([img[l, k, 2] for l in range(i-1, i+2) for k in range(j-1, j+2)])
        rgb_avg_img [i, j] = [int(sum_b_pix/9), int(sum_g_pix/9), int(sum_r_pix/9)]

cv2.imshow('origin image', imutils.resize(img, 500))
cv2.imshow('gray image', imutils.resize(gray_img, 500))
cv2.imshow('blur image', imutils.resize(blur_img, 500))
cv2.imshow('gray average image', imutils.resize(gray_avg_img , 500))
cv2.imshow('rgb average  image', imutils.resize(rgb_avg_img , 500))
if cv2.waitKey(0) == 27:
    cv2.destroyAllWindows()


效果图如下:依次是原图、灰度图、基于灰度图opencv提供函数blur均值滤波效果、基于灰度图自定义均值滤波效果、基于彩色图自定义均值滤波效果
【数字图像处理系列五】图像滤波之空间滤波:图像平滑降噪和图像锐化
【数字图像处理系列五】图像滤波之空间滤波:图像平滑降噪和图像锐化
【数字图像处理系列五】图像滤波之空间滤波:图像平滑降噪和图像锐化
【数字图像处理系列五】图像滤波之空间滤波:图像平滑降噪和图像锐化
【数字图像处理系列五】图像滤波之空间滤波:图像平滑降噪和图像锐化




2、中值滤波

中值滤波是基于排序统计理论的一种能有效抑制噪声的非线性平滑滤波信号处理技术。中值滤波的特点即是首先确定一个以某个像素为中心点的邻域,然后将邻域中各像素的灰度值排序,取其中间值作为中心像素灰度的新值。中值滤波在对于椒盐噪音处理上效果很好



下面分别通过opencv-python提供的中值滤波和自定义中值滤波器两种方式实现图像的中值滤波,下面实验中我们尝试着对图像添加椒盐噪音然后进行使用中值滤波进行消除:

import cv2
import copy
import random
import imutils
import numpy as np

img = cv2.imread('E:/peking_rw/ocr_project/base_prehandle/img/old.jpg')
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

#给灰度图像自动添加椒盐噪音
pepper_img = copy.deepcopy(gray_img)
for i in range(gray_img.shape[0]):
    for j in range(gray_img.shape[1]):
        if random.randint(0, 20) == 0:
            pix = random.randint(250, 255)
            pepper_img[i, j] = pix

#opencv提供cv2.medianBlur()函数实现中值滤波
blur_img = cv2.medianBlur(pepper_img, 5)

#自实现中值滤波器
temp_arr = np.zeros((9))
median_img = copy.deepcopy(pepper_img)
for i in range(1, pepper_img.shape[0]-1):
    for j in range(1, pepper_img.shape[1]-1):
        temp_arr[0] = pepper_img[i-1, j-1]
        temp_arr[1] = pepper_img[i-1, j]
        temp_arr[2] = pepper_img[i-1, j+1]
        temp_arr[3] = pepper_img[i, j-1]
        temp_arr[4] = pepper_img[i, j]
        temp_arr[5] = pepper_img[i, j+1]
        temp_arr[6] = pepper_img[i+1, j-1]
        temp_arr[7] = pepper_img[i+1, j]
        temp_arr[8] = pepper_img[i+1, j+1]
        arr = np.sort(temp_arr)
        median_img[i, j] = arr[4]

cv2.imshow('pepper image', imutils.resize(pepper_img, 600))
cv2.imshow('blur image', imutils.resize(blur_img, 600))
cv2.imshow('median image', imutils.resize(median_img, 600))
if cv2.waitKey(0) == 27:
    cv2.destroyAllWindows()


效果图如下:依次是含椒盐噪音图、经过cv2.medianBlur()函数处理后的图像、经过自定义中值滤波器滤波后图像

【数字图像处理系列五】图像滤波之空间滤波:图像平滑降噪和图像锐化
【数字图像处理系列五】图像滤波之空间滤波:图像平滑降噪和图像锐化
【数字图像处理系列五】图像滤波之空间滤波:图像平滑降噪和图像锐化



除了中值滤波外,还有一种非线性滤波是最值滤波,最值滤波是去邻域中的最大值最为新像素值,在搜寻一幅图像最亮点时非常有用。





三、锐化空间滤波器


写在前面上节提到的图像平滑是通过模糊图像达到图像降噪的目的,但同时存在一个问题就是会使得图像的边缘被淡化。因此本节图像锐化滤波恰相反,图像平滑是一个积分的过程,图像锐化便是通过图像微分增强边缘和其他突变,削弱灰度变换缓慢的区域。

在图像微分锐化操作中,对于一阶微分的任何定义需要保证以下三点:

  1. 在恒定灰度区域的微分值为零
  2. 在灰度台阶或斜坡处微分值非零
  3. 沿着斜坡的微分值非零

同样类比得对于二阶微分的任何保证以下三点:

  1. 在恒定区域微分值为零
  2. 在灰度台阶或斜坡的起点处微分值非零
  3. 沿着斜坡的微分值非零

1、二阶微分图像锐化—laplacian算子

首先一个二维图像函数 f(x,y) 的拉普拉斯算子定义为:

【数字图像处理系列五】图像滤波之空间滤波:图像平滑降噪和图像锐化

拉普拉斯变换是一个线性算子,在x方向上离散化有:

【数字图像处理系列五】图像滤波之空间滤波:图像平滑降噪和图像锐化

在y方向离散化有:

【数字图像处理系列五】图像滤波之空间滤波:图像平滑降噪和图像锐化

从上面三个式子可以得出离散拉普拉斯算子是:

【数字图像处理系列五】图像滤波之空间滤波:图像平滑降噪和图像锐化

上面公式便是拉普拉斯算子中一种计算方式,等价于下图中的laplacian模板1,自然laplacian模板2也可以类比写出离散算子公式:

【数字图像处理系列五】图像滤波之空间滤波:图像平滑降噪和图像锐化

注:由于拉普拉斯是一种微分算子,因此其强调的是图像中灰度的变换,忽视图像灰度变换缓慢的区域。因此我们通过laplacian算子得出的是图像更多的是边缘线,因此,我们可以将原图和拉普拉斯图像叠加在一起,可以复原背景特性并且保持拉普拉斯锐化处理的效果,由此得出下面公式:

【数字图像处理系列五】图像滤波之空间滤波:图像平滑降噪和图像锐化

对于上面展示的拉普拉斯模板1和拉普拉斯模板2,常数c取-1,也有其他模板,这里不再详述


下面给出利用opencv函数和自实现上述拉普拉斯模板的应用实例:

import cv2
import copy
import random
import imutils
import numpy as np

img = cv2.imread('E:/peking_rw/ocr_project/base_prehandle/img/blurry_moon.jpg')

#手动实现拉普拉斯滤波,使用上述laplacian模板1
lap_img1 = copy.deepcopy(img)
for i in range(1, img.shape[0]-1):
    for j in range(1, img.shape[1]-1):
        temp = img[i+1, j] + img[i-1, j] + img[i, j+1] + img[i, j-1] -4*img[i, j]
        lap_img1[i, j] = img[i, j] - temp

#手动实现拉普拉斯滤波,使用上述laplacian模板2
lap_img2 = copy.deepcopy(img)
for i in range(1, img.shape[0]-1):
    for j in range(1, img.shape[1]-1):
        temp = img[i-1, j-1] + img[i-1, j] + img[i-1, j+1] + img[i, j-1] + \
                img[i, j+1] + img[i+1, j-1] + img[i+1, j] + img[i+1, j+1] - 8*img[i, j]
        lap_img2[i, j] = img[i, j] - temp

#使用opencv自带函数实现,使用上述laplacian模板1
kernel = np.array([[0, 1, 0], [1, -4, 1], [0, 1, 0]]) #定义了卷积核,对每一个像素进行操作
lapkernel_img = cv2.filter2D(img, -1, kernel)
lap_img3 = img - lapkernel_img

cv2.imshow('origin image', imutils.resize(img, 400))
cv2.imshow('laplacian image1', imutils.resize(lap_img1, 400))
cv2.imshow('laplacian image2', imutils.resize(lap_img2, 400))
cv2.imshow('laplacian image3', imutils.resize(lap_img3, 400))
if cv2.waitKey(0) == 27:
    cv2.destroyAllWindows()


效果图如下,顺序既是上述程序的输出顺序:
【数字图像处理系列五】图像滤波之空间滤波:图像平滑降噪和图像锐化
【数字图像处理系列五】图像滤波之空间滤波:图像平滑降噪和图像锐化
【数字图像处理系列五】图像滤波之空间滤波:图像平滑降噪和图像锐化
【数字图像处理系列五】图像滤波之空间滤波:图像平滑降噪和图像锐化




2、非锐化掩蔽

非锐化掩蔽的思路便是应原图像减去平滑的图像,这样便得到强调边缘的图像,然后再和原图像相加,便达到强调图像边缘的效果,具体步骤如下:

  1. 模糊原图像
  2. 从原图像减去模糊图像(产生的差值图像称为模板)
  3. 将模板和原图像相加

则将上述思路换算成数学公式便是:

【数字图像处理系列五】图像滤波之空间滤波:图像平滑降噪和图像锐化

然后在原图像加上模板的一个权重部分:

【数字图像处理系列五】图像滤波之空间滤波:图像平滑降噪和图像锐化

k>1时我们称该处理为高提升滤波,当k<1时则是不强调非锐化模板的作用

下面提供代码实现如下:

import cv2
import copy
import random
import imutils
import numpy as np

img = cv2.imread('E:/peking_rw/ocr_project/base_prehandle/img/blurry_moon.jpg')
blur_img = cv2.blur(img, (5, 5))

mask_img = img - blur_img
sharp_mask_img = img + mask_img

cv2.imshow('origin image', imutils.resize(img, 400))
cv2.imshow('blur image', imutils.resize(blur_img, 400))
cv2.imshow('mask image', imutils.resize(mask_img, 400))
cv2.imshow('sharpen mask image', imutils.resize(sharp_mask_img, 400))
if cv2.waitKey(0) == 27:
    cv2.destroyAllWindows()



3、cv2.filter2D()自定义卷积核滤波

opencv-python中提供cv2.filter2D()函数可实现自定义内核和图像进行卷积操作,cv2.filter2D()一般定义为:

cv2.filter2D(img, -1, kernel)   #参数三kernel是卷积核; 参数二ddepth输入值为-1时,目标图像和原图像深度保持一致

下面我们提供实例展示对图像滤波的效果:

import cv2
import copy
import random
import imutils
import numpy as np

img = cv2.imread('E:/peking_rw/ocr_project/base_prehandle/img/old.jpg')
kernel = np.array([[0, -1, 0], [0, 5, 0], [0, -1, 0]]) #自定义了卷积核,对每一个像素进行操作
new_img = cv2.filter2D(img, -1, kernel)

cv2.imshow('origin image', imutils.resize(img, 400))
cv2.imshow('new image', imutils.resize(new_img, 400))
if cv2.waitKey(0) == 27:
    cv2.destroyAllWindows()

根据自定义的卷积核 kernel = np.array([[0, -1, 0], [0, 5, 0], [0, -1, 0]]) 得到的滤波效果如下:
【数字图像处理系列五】图像滤波之空间滤波:图像平滑降噪和图像锐化
【数字图像处理系列五】图像滤波之空间滤波:图像平滑降噪和图像锐化