频域滤波和空域滤波有着密不可分的关系。频域滤波器是通过对图像变化频率的控制来达到图像处理的目的,而空域滤波器是通过图像矩阵对模板进行卷积运算达到处理图像的效果。由卷积定理可知,空域上的卷积数值上等于图像和模板傅里叶变换乘积的反变换。
也就是说如果将空域上的模板进行离散傅里叶变化得到频域上的模板,那么用空域模板进行空域滤波和用得到的频域模板进行频域滤波最后结果是一样的,两种方法有时可以互换。
但需要注意的一点是,将原始图像与空域模板进行卷积运算,得到卷积结果的长度要比原来的图像长,就算对图像和模板进行填充,得到的卷积结果的第一位也不是模板在原始图像第一个像素处的卷积。
比如假设p位原始图像长度为P,q为卷积模板长度为Q,则由卷积的运算公式易得不产生混淆下图像的最小填充后尺寸为P+Q-1,填充后p,q为
运行如下程序
import numpy as np # 保留效数点后三位 np.set_printoptions(precision=3) # 不使用科学计数法 np.set_printoptions(suppress=True) p = np.array([[1,2,3,0,0],[4,5,6,0,0],[7,8,9,0,0],[0,0,0,0,0],[0,0,0,0,0]]) q = np.array([[1,1,1,0,0],[1,-8,1,0,0],[1,1,1,0,0],[0,0,0,0,0],[0,0,0,0,0]]) pp = np.fft.fft2(p) qq = np.fft.fft2(q) tt = pp*qq t = np.fft.ifft2(tt) print('p\n', p) print('q\n', q) print('t\n', t.real)
利用卷积定理可以得到卷积后的结果t为
从上述运行结果可知,虽然进行零填充可以有效避免混淆,但无法改变的一点是,卷积后图像的尺寸会变大。可以看出卷积后的结果填满了整个5×5的矩阵。理论上用模板在图像第一个像素处的卷积值(也就是3)来替代图像原来的第一个像素更加恰当——我们之前编写的空域滤波器的程序也是这么做的——而现在这个结果在卷积运算的(1,1)处。实际上真正在图像上的卷积结果位于t的中心处,即下面截图才是与原始图像相等大小的滤波结果。
因此要想得到和空域滤波器相同的结果,在填充和频域滤波之后提取图像时,就要将得到的处理结果的边缘去掉。假设模板大小位P×Q,则滤波后得到的边缘宽度为(floor(P/2), floor(Q/2))。
下面进行空域滤波和频域滤波的比较。比较步骤如下
(1)定义一个小尺寸的空域模板,用该模板进行空域滤波,获得滤波图像。
(2)根据空域滤波模板和原图像的大小计算频域模板的填充大小。
(3)将空域模板进行填充并乘以$(-1)^{x+y}$,然后进行傅里叶变换得到频域模板。
(4)用得到的频域模板进行频域滤波,并对滤波结果进行截取。
(5)空域滤波和频域滤波的结果显示比较。
其中对sobel算子的比较代码如下
import frequency_function as fre import airspace_filter as air import cv2 as cv import numpy as np import matplotlib.pyplot as plt original_image_test4 = cv.imread('test4.tif',0) '''比较对应的频域滤波器和空域滤波器是否等效''' # # 比较sobel算子 # # 得到空域sobel滤波函数 airspace_result_test1 = air.laplace_sharpen(original_image_test4, my_type='big') # 定义空域滤波模板 air_model = np.array([[1, 1, 1], [1, -8, 1], [1, 1, 1]]) # 计算模板填充后的尺寸 shape = (2*original_image_test4.shape[0], 2*original_image_test4.shape[1]) # 将空域模板填充到相应尺寸,变换为频域模板并将低频移至中心 fre_model = np.fft.fft2(fre.my_get_fp(fre.my_fill(air_model, shape))) # 用频域模板进行频域滤波 frequency_result_test1 = fre.myfunc_seldifine(original_image_test4, fre_model, output_offset=(1, 1)) # 将滤波结果的像素值转换到0~255 airspace_result_test1=air.show_edge(airspace_result_test1) frequency_result_test1=air.show_edge(frequency_result_test1) # 结果显示 plt.subplot(131) plt.imshow(original_image_test4) plt.title('original') plt.subplot(132) plt.imshow(airspace_result_test1) plt.title('spatial filter') plt.subplot(133) plt.imshow(frequency_result_test1) plt.title('frequency filter') plt.show()
比较结果为
可以看出两种方式效果是相同的。
对高斯低通滤波的比较代码
import frequency_function as fre import airspace_filter as air import cv2 as cv import numpy as np import matplotlib.pyplot as plt original_image_test1 = cv.imread('test1.pgm',0) original_image_test2 = cv.imread('test2.tif',0) original_image_test3 = cv.imread('test3_corrupt.pgm',0) original_image_test4 = cv.imread('test4.tif',0) # # 比较高斯滤波器 # # 得到空域高斯滤波函数 airspace_result_test1 = air.gaussion_blur_gray(original_image_test1, 7, 1.5) # 获得空域高斯滤波模板 air_model = air.get_gaussion_blur_retric(7, 1.5) # 计算模板填充后的尺寸 shape = (original_image_test1.shape[0] + 7, original_image_test1.shape[1] + 7) # 将空域模板填充到相应尺寸,变换为频域模板并将低频移至中心 fre_model = np.fft.fft2(fre.my_get_fp(fre.my_fill(air_model, shape))) # 用频域模板进行频域滤波 frequency_result_test1 = fre.myfunc_seldifine(original_image_test1, fre_model, output_offset=(3, 3)) # 滤波结果显示 plt.subplot(131) plt.imshow(original_image_test1) plt.title('original') plt.subplot(132) plt.imshow(airspace_result_test1) plt.title('spatial filter') plt.subplot(133) plt.imshow(frequency_result_test1) plt.title('frequency filter') plt.show()
比较结果为