文章目录
第四章 频率域滤波
滤波器:抑制或最小化某些频率的波或振荡的装置或材料
频率:自变量单位变化期间,一个周期函数重复相同值序列的次数
在开始实验之前,可以先看一下三篇文章了解一下傅里叶变换
1、实现图像的傅里叶变换,显示其幅度谱的图像(0 频在显示图像的中间位置)
M×N
图像的二维离散傅里叶变换的公式为
F
(
u
,
v
)
=
∑
x
=
0
M
−
1
∑
y
=
0
N
−
1
f
(
x
,
y
)
e
−
2
π
(
u
x
M
+
v
y
N
)
F(u,v)=\sum_{x=0}^{M-1} \sum_{y=0}^{N-1}f(x,y)e^{-2\pi(\frac{ux}{M}+\frac{vy}{N})}
F(u,v)=x=0∑M−1y=0∑N−1f(x,y)e−2π(Mux+Nvy)
但在实际的实现中,如果自己编写相关的代码,速度是很慢的。可以调用NumPy
自带的快速傅里叶变换的方法来显示图像的幅度谱
由于经过傅里叶变换后的图像像素值比较大,所以还需要用对数函数来使之归到0-255之间,中间各个过程的图像如下所示
在频谱中心化后的图像中,中间是低频,四周都是高频未经过频谱中心化的图像则相反
实现的代码如下所示:
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
img_path = "man.jpg"
src = np.array(Image.open(img_path).convert("L"))
dft_src = np.fft.fft2(src)
log_src = np.log(1 + np.abs(dft_src))
ctr_src = np.fft.fftshift(log_src)
img_list = [src, dft_src, log_src, ctr_src]
img_list_name = ["原图像", "DFT图像", "DFT+对数变换图像", "中心化图像"]
plt.rcParams['font.family'] = ['sans-serif']
plt.rcParams['font.sans-serif'] = ['SimHei']
_, img_xy = plt.subplots(2, 2, figsize=(12, 12))
for i in range(2):
for j in range(2):
img_xy[i][j].imshow(np.abs(img_list[i * 2 + j]), cmap="gray")
img_xy[i][j].set_title(img_list_name[i * 2 + j], size=20)
img_xy[i][j].axis("off")
plt.show()
2、用理想低通滤波器在频率域实现低通滤波
从这里往下代码重叠度比较高,因为基本原理是相同的
理想低通滤波器(ILPF)的滤波器传递函数为
H
(
u
,
v
)
=
{
1
D
(
u
,
v
)
≤
D
0
0
D
(
u
,
v
)
>
D
0
H(u, v)=\left\{\begin{array}{ll} 1 & D(u, v) \leq D_{0} \\ 0 & D(u, v)>D_{0} \end{array}\right.
H(u,v)={10D(u,v)≤D0D(u,v)>D0
D ( u , v ) = [ ( u − M / 2 ) 2 + ( v − N / 2 ) 2 ] 1 / 2 D(u,v)=[(u-M/2)^2+(v-N/2)^2]^{1/2} D(u,v)=[(u−M/2)2+(v−N/2)2]1/2
将理想低通滤波器其用不同的方式可视化表达出来
实现的方式:
- 对图像做傅里叶变换并使得频谱中心化
- 设定滤波的半径,并以图像中心为圆心画圆
- 圆内的滤波器值设为1,圆外为0
- 逆中心化和逆傅里叶变换
低通滤波得到的结果如下所示
图中总共设置了5种滤波的半径,可以观察到,低通滤波一是模糊,二是会有振铃效应,出现振铃效应的主要原因是理想滤波器在频域是一个门函数,但是在时域对应的是一个sinc
函数,而频域的相乘就是时域的卷积。
时域卷积sinc
函数就是对该函数进行搬移与叠加,那自然就有一圈圈波纹产生,也就是我们所谓的振铃效应
理想低通滤波器实现的代码如下所示
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
def fourier_trans(src):
"""
fourier transformation
source: source image
ctr_src: spectrum after fourier transformation and centralization
plt_src: spectrum after log transformation
"""
fft_src = np.fft.fft2(src)
ctr_src = np.fft.fftshift(fft_src)
plt_src = np.log(np.abs(ctr_src))
return ctr_src, plt_src
def inv_fourier_trans(src):
"""
inverse fourier transformation
src: spectrums
ifft_img: the image after inverse fourier transformation
"""
inv_ctr_img = np.fft.ifftshift(src)
ifft_img = np.fft.ifft2(inv_ctr_img)
return ifft_img
def idea_low_pass_filter(source, radius=5):
"""
LPF
source: source image
radius: size for low pass filter
"""
# get the paras
filter_radius = radius
img = source
# set paras for filter
height, weight = img.shape
center_h = int(height / 2)
center_w = int(weight / 2)
# initialize filter
low_pass_filter = np.zeros_like(img)
# set the low pass area
for i in range(height):
for j in range(weight):
dist_from_center = np.sqrt(np.power((i - center_h), 2) + np.power((j - center_w), 2))
if dist_from_center < radius:
low_pass_filter[i][j] = 1
# filter the image
filtered_img = np.multiply(img, low_pass_filter)
return filtered_img
img_path = "man.jpg"
src = np.array(Image.open(img_path).convert("L"))
fft_src, _ = fourier_trans(src)
img_list = [src]
radius_list = ['origin', 5, 15, 30, 50, 100]
for i in radius_list[1:]:
img_list.append(inv_fourier_trans(idea_low_pass_filter(fft_src, i)))
img_list_name = radius_list
_, img_xy = plt.subplots(2, 3, figsize=(12, 12))
for i in range(2):
for j in range(3):
img_xy[i][j].imshow(np.abs(img_list[i * 3 + j]), cmap="gray")
img_xy[i][j].set_title(img_list_name[i * 3 + j], size=20)
img_xy[i][j].axis("off")
plt.show()
3、用理想高通滤波器在频率域实现低通滤波
理想高通滤波器(IHPF)滤波器传递函数为
H
(
u
,
v
)
=
{
0
D
(
u
,
v
)
≤
D
0
1
D
(
u
,
v
)
>
D
0
H(u, v)=\left\{\begin{array}{ll}0 & D(u, v) \leq D_{0} \\1 & D(u, v)>D_{0}\end{array}\right.
H(u,v)={01D(u,v)≤D0D(u,v)>D0
D ( u , v ) = [ ( u − M / 2 ) 2 + ( v − N / 2 ) 2 ] 1 / 2 D(u,v)=[(u-M/2)^2+(v-N/2)^2]^{1/2} D(u,v)=[(u−M/2)2+(v−N/2)2]1/2
将理想高通滤波器用不同的方式可视化表达出来
实现的方式:
- 对图像做傅里叶变换并使得频谱中心化
- 设定滤波的半径,并以图像中心为圆心画圆
- 圆内的滤波器值设为0,圆外为1
- 逆中心化和逆傅里叶变换
实现的效果如下所示:
实现的代码如下所示:
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
def fourier_trans(src):
"""
fourier transformation
source: source image
ctr_src: spectrum after fourier transformation and centralization
plt_src: spectrum after log transformation
"""
fft_src = np.fft.fft2(src)
ctr_src = np.fft.fftshift(fft_src)
plt_src = np.log(np.abs(ctr_src))
return ctr_src, plt_src
def inv_fourier_trans(src):
"""
inverse fourier transformation
src: spectrums
ifft_img: the image after inverse fourier transformation
"""
inv_ctr_img = np.fft.ifftshift(src)
ifft_img = np.fft.ifft2(inv_ctr_img)
return ifft_img
def idea_high_pass_filter(source, radius=5):
"""
HPF
source: source image
radius: size for High pass filter
"""
# get the paras
filter_radius = radius
img = source
# set paras for filter
height, weight = img.shape
center_h = int(height / 2)
center_w = int(weight / 2)
# initialize filter
high_pass_filter = np.ones_like(img)
# set the high pass area
for i in range(height):
for j in range(weight):
dist_from_center = np.sqrt(np.power((i - center_h), 2) + np.power((j - center_w), 2))
if dist_from_center < radius:
high_pass_filter[i][j] = 0
# filter the image
filtered_img = np.multiply(img, high_pass_filter)
return filtered_img
img_path = "man.jpg"
src = np.array(Image.open(img_path).convert("L"))
fft_src, _ = fourier_trans(src)
img_list = [src]
radius_list = ['origin', 5, 15, 30, 50, 100]
for i in radius_list[1:]:
img_list.append(inv_fourier_trans(idea_high_pass_filter(fft_src, i)))
img_list_name = radius_list
_, img_xy = plt.subplots(2, 3, figsize=(12, 12))
for i in range(2):
for j in range(3):
img_xy[i][j].imshow(np.abs(img_list[i * 3 + j]), cmap="gray")
img_xy[i][j].set_title(img_list_name[i * 3 + j], size=20)
img_xy[i][j].axis("off")
plt.show()
4、用巴特沃斯低通滤波器和高斯低通滤波器实现图像的低通滤波
4.1 巴特沃斯低通滤波器
巴特沃斯低通滤波器(BLPF)滤波器传递函数为
H
(
u
,
v
)
=
1
1
+
[
D
(
u
,
v
)
/
D
0
]
2
n
H(u, v)=\frac{1}{1+\left[D(u, v) / D_{0}\right]^{2 n}}
H(u,v)=1+[D(u,v)/D0]2n1
D ( u , v ) = [ ( u − M / 2 ) 2 + ( v − N / 2 ) 2 ] 1 / 2 D(u,v)=[(u-M/2)^2+(v-N/2)^2]^{1/2} D(u,v)=[(u−M/2)2+(v−N/2)2]1/2
将巴特沃斯低通滤波器用不同的方式可视化表达出来
实现的效果如下所示(采用2阶巴特沃斯低通滤波器):
观察可以发现,巴特沃斯低通滤波器虽然依然有模糊,但基本上可以说没有振铃效应
观察不同阶数的巴特沃斯低通滤波器的空间表示(从左到右分别是1阶,2阶,5阶,),可以发现(低阶)“振”的部分减少了,虽然1阶不存在振铃效应,但是低通性不好,所以之前的实现采用了2阶,振铃效应也是基本不可见
但是高阶的巴特沃斯低通滤波器依然有,比如以下的20阶巴特沃斯低通滤波器
实现的代码如下所示
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
def fourier_trans(src):
"""
fourier transformation
source: source image
ctr_src: spectrum after fourier transformation and centralization
plt_src: spectrum after log transformation
"""
fft_src = np.fft.fft2(src)
ctr_src = np.fft.fftshift(fft_src)
plt_src = np.log(np.abs(ctr_src))
return ctr_src, plt_src
def inv_fourier_trans(src):
"""
inverse fourier transformation
src: spectrums
ifft_img: the image after inverse fourier transformation
"""
inv_ctr_img = np.fft.ifftshift(src)
ifft_img = np.fft.ifft2(inv_ctr_img)
return ifft_img
def butterworth_low_pass_filter(source, radius=5, order=1):
# get the paras
filter_radius = radius
img = source
# set paras for filter
height, weight = img.shape
center_h = int(height / 2)
center_w = int(weight / 2)
# initialize filter
butterworth_low_pass_filter = np.zeros_like(img)
# set the pass area
for i in range(height):
for j in range(weight):
dist_from_center = np.sqrt(np.power((i - center_h), 2) + np.power((j - center_w), 2))
butterworth_low_pass_filter[i][j] = 1 / (1 + np.power(dist_from_center / radius, 2 * order))
# filter the image
filtered_img = np.multiply(img, butterworth_low_pass_filter)
return filtered_img
img_path = "man.jpg"
src = np.array(Image.open(img_path).convert("L"))
fft_src, _ = fourier_trans(src)
img_list = [src]
radius_list = ['origin', 5, 15, 30, 50, 100]
for i in radius_list[1:]:
img_list.append(inv_fourier_trans(butterworth_low_pass_filter(fft_src, i, 2)))
img_list_name = radius_list
_, img_xy = plt.subplots(2, 3, figsize=(12, 12))
for i in range(2):
for j in range(3):
img_xy[i][j].imshow(np.abs(img_list[i * 3 + j]), cmap="gray")
img_xy[i][j].set_title(img_list_name[i * 3 + j], size=20)
img_xy[i][j].axis("off")
plt.show()
4.2 高斯低通滤波器
高斯低通滤波器(GLPF)滤波器传递函数为
H
(
u
,
v
)
=
e
−
D
2
(
u
,
v
)
/
2
D
0
2
H(u, v)=e^{-D^{2}(u, v) / 2 D_{0}^{2}}
H(u,v)=e−D2(u,v)/2D02
D ( u , v ) = [ ( u − M / 2 ) 2 + ( v − N / 2 ) 2 ] 1 / 2 D(u,v)=[(u-M/2)^2+(v-N/2)^2]^{1/2} D(u,v)=[(u−M/2)2+(v−N/2)2]1/2
将高斯低通滤波器其用不同的方式可视化表达出来
实现的效果如下所示:
可以观察到,高斯低通滤波器同样是模糊但是没有振铃效应
实现的代码如下所示:
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
def fourier_trans(src):
"""
fourier transformation
source: source image
ctr_src: spectrum after fourier transformation and centralization
plt_src: spectrum after log transformation
"""
fft_src = np.fft.fft2(src)
ctr_src = np.fft.fftshift(fft_src)
plt_src = np.log(np.abs(ctr_src))
return ctr_src, plt_src
def inv_fourier_trans(src):
"""
inverse fourier transformation
src: spectrums
ifft_img: the image after inverse fourier transformation
"""
inv_ctr_img = np.fft.ifftshift(src)
ifft_img = np.fft.ifft2(inv_ctr_img)
return ifft_img
def guass_low_pass_filter(source, radius=5):
# get the paras
filter_radius = radius
img = source
# set paras for filter
height, weight = img.shape
center_h = int(height / 2)
center_w = int(weight / 2)
# initialize filter
guass_low_pass_filter = np.zeros_like(img)
# set the pass area
for i in range(height):
for j in range(weight):
dist_from_center = np.sqrt(np.power((i - center_h), 2) + np.power((j - center_w), 2))
guass_low_pass_filter[i][j] = np.exp(-(np.power(dist_from_center, 2) / np.power(radius, 2)))
# filter the image
filtered_img = np.multiply(img, guass_low_pass_filter)
return filtered_img
img_path = "man.jpg"
src = np.array(Image.open(img_path).convert("L"))
fft_src, _ = fourier_trans(src)
img_list = [src]
radius_list = ['origin', 5, 15, 30, 50, 100]
for i in radius_list[1:]:
img_list.append(inv_fourier_trans(guass_low_pass_filter(fft_src, i)))
img_list_name = radius_list
_, img_xy = plt.subplots(2, 3, figsize=(12, 12))
for i in range(2):
for j in range(3):
img_xy[i][j].imshow(np.abs(img_list[i * 3 + j]), cmap="gray")
img_xy[i][j].set_title(img_list_name[i * 3 + j], size=20)
img_xy[i][j].axis("off")
plt.show()
5、用巴特沃斯高通滤波器和高斯高通滤波器实现图像的高频增强
5.1 巴特沃斯高通滤波器
巴特沃斯高通滤波器(BHPF)滤波器传递函数为
H
(
u
,
v
)
=
1
1
+
[
D
0
/
D
(
u
,
v
)
/
]
2
n
H(u, v)=\frac{1}{1+\left[D_{0}/D(u, v) / \right]^{2 n}}
H(u,v)=1+[D0/D(u,v)/]2n1
D ( u , v ) = [ ( u − M / 2 ) 2 + ( v − N / 2 ) 2 ] 1 / 2 D(u,v)=[(u-M/2)^2+(v-N/2)^2]^{1/2} D(u,v)=[(u−M/2)2+(v−N/2)2]1/2
将巴特沃斯高通滤波器用不同的方式可视化表达出来
实现的效果如下所示:
实现的代码如下所示:
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
def fourier_trans(src):
"""
fourier transformation
source: source image
ctr_src: spectrum after fourier transformation and centralization
plt_src: spectrum after log transformation
"""
fft_src = np.fft.fft2(src)
ctr_src = np.fft.fftshift(fft_src)
plt_src = np.log(np.abs(ctr_src))
return ctr_src, plt_src
def inv_fourier_trans(src):
"""
inverse fourier transformation
src: spectrums
ifft_img: the image after inverse fourier transformation
"""
inv_ctr_img = np.fft.ifftshift(src)
ifft_img = np.fft.ifft2(inv_ctr_img)
return ifft_img
def butterworth_high_pass_filter(source, radius=5, order=2):
# get the paras
filter_radius = radius
img = source
# set paras for filter
height, weight = img.shape
center_h = int(height / 2)
center_w = int(weight / 2)
# initialize filter
butterworth_high_pass_filter = np.zeros_like(img)
# set the pass area
for i in range(height):
for j in range(weight):
dist_from_center = np.sqrt(np.power((i - center_h), 2) + np.power((j - center_w), 2))
if dist_from_center != 0:
butterworth_high_pass_filter[i][j] = 1 / (1 + np.power(radius / dist_from_center, 2 * order))
# filter the image
filtered_img = np.multiply(img, butterworth_high_pass_filter)
return filtered_img
img_path = "man.jpg"
src = np.array(Image.open(img_path).convert("L"))
fft_src, _ = fourier_trans(src)
img_list = [src]
radius_list = ['origin', 5, 15, 30, 50, 100]
for i in radius_list[1:]:
img_list.append(inv_fourier_trans(butterworth_high_pass_filter(fft_src, i)))
img_list_name = radius_list
_, img_xy = plt.subplots(2, 3, figsize=(12, 12))
for i in range(2):
for j in range(3):
img_xy[i][j].imshow(np.abs(img_list[i * 3 + j]), cmap="gray")
img_xy[i][j].set_title(img_list_name[i * 3 + j], size=20)
img_xy[i][j].axis("off")
plt.show()
5.2 高斯高通滤波器
高斯高通滤波器(GHPF)滤波器传递函数为
H
(
u
,
v
)
=
1
−
e
−
D
2
(
u
,
v
)
/
2
D
0
2
H(u, v)=1-e^{-D^{2}(u, v) / 2 D_{0}^{2}}
H(u,v)=1−e−D2(u,v)/2D02
D ( u , v ) = [ ( u − M / 2 ) 2 + ( v − N / 2 ) 2 ] 1 / 2 D(u,v)=[(u-M/2)^2+(v-N/2)^2]^{1/2} D(u,v)=[(u−M/2)2+(v−N/2)2]1/2
将高斯高通滤波器用不同的方式可视化表达出来
实现的效果如下所示
至此,三种高通滤波器(理想、巴特沃兹,高通)都已经表示了出来,他们的空间表示如下所示(与前面顺序对应),可以看出三者在振铃效应上的区别
实现的代码如下所示
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
def fourier_trans(src):
"""
fourier transformation
source: source image
ctr_src: spectrum after fourier transformation and centralization
plt_src: spectrum after log transformation
"""
fft_src = np.fft.fft2(src)
ctr_src = np.fft.fftshift(fft_src)
plt_src = np.log(np.abs(ctr_src))
return ctr_src, plt_src
def inv_fourier_trans(src):
"""
inverse fourier transformation
src: spectrums
ifft_img: the image after inverse fourier transformation
"""
inv_ctr_img = np.fft.ifftshift(src)
ifft_img = np.fft.ifft2(inv_ctr_img)
return ifft_img
def guass_high_pass_filter(source, radius = 5):
# get the paras
filter_radius = radius
img = source
# set paras for filter
height,weight = img.shape
center_h = int(height/2)
center_w = int(weight/2)
# initialize filter
guass_high_pass_filter = np.zeros_like(img)
# set the pass area
for i in range(height):
for j in range(weight):
dist_from_center = np.sqrt(np.power((i-center_h),2) + np.power((j-center_w),2))
guass_high_pass_filter[i][j] = 1 - np.exp(-(np.power(dist_from_center,2)/np.power(radius,2)))
# filter the image
filtered_img = np.multiply(img, guass_high_pass_filter)
return filtered_img
img_path = "man.jpg"
src = np.array(Image.open(img_path).convert("L"))
fft_src, _ = fourier_trans(src)
img_list = [src]
radius_list = ['origin', 5, 15, 30, 50, 100]
for i in radius_list[1:]:
img_list.append(inv_fourier_trans(guass_high_pass_filter(fft_src, i)))
img_list_name = radius_list
_, img_xy = plt.subplots(2, 3, figsize=(12, 12))
for i in range(2):
for j in range(3):
img_xy[i][j].imshow(np.abs(img_list[i * 3 + j]), cmap="gray")
img_xy[i][j].set_title(img_list_name[i * 3 + j], size=20)
img_xy[i][j].axis("off")
plt.show()