imgProc-ex2
实验二:图像复原
实验目的
- 利用反向滤波和维纳滤波进行降质图像复原,比较不同参数选择对复原结果的影响。
实验
实验内容
- 利用反向滤波方法进行图像复原;
- 利用维纳滤波方法进行图像复原。
实验环境
- macOS 14.1 Sonoma(Apple M1 PRO)
- PyCharm/Python3.10
- OpenCV-Python
实验原理及过程
-
输入图像采用实验 1 所获取的图像,对输入图像采用运动降质模型,如下式所示
-
读取灰度图:
1
2
3
4
5
6# 读入彩图,转换灰图
image = cv.imread('../lena512color.png')
gray_lena = color2gray(image)
print(gray_lena.shape)
# (512, 512)
N = 512 -
生成PSF的傅立叶变换(降质系统的传递函数)
-
先定义函数,再利用列表推导式生成矩阵(数组)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17def H(u, v):
"""
psf的fft
:param u:
:param v:
:return:
"""
a, b = 0.02, 0.02
T = 1
tmp = np.pi * (a * u + b * v)
if tmp == 0:
return T
return (T / tmp) * np.sin(tmp) * np.exp(-1j * tmp)
H_func = np.array(
[[H(u, v) for v in arange(-N / 2, N / 2)] for u in arange(-N / 2, N / 2)],
dtype=np.complex128) -
-
运动降质实现如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19def make_blur(src_img, psf):
"""
运动降质
:param src_img: 原始图片
:param psf: psf的fft
:return: 降质图片
"""
# fft + shift
fft_src_img = fftshift(fft2(src_img))
# 降质
G = fft_src_img * psf
# 逆(fft + shift)
G_ifft = ifft2(ifftshift(G))
# 转为uint8
g_img = np.abs(G_ifft)
return g_img
gray_lena_blurred = make_blur(gray_lena, H_func)
imgWrite(gray_lena_blurred, "实验二:图像复原/gray_lena_blurred.png")-
降质后图像(gray_lena_blurred)如下:
-
-
-
没有噪声的情况下,对降质后的图像进行反向滤波和维纳滤波操作,得到复原图像
-
反向滤波(无噪声):
-
傅立叶变换估计:
- 猜测由于python的精度问题,会有极小值问题(测试),而是会有这种小数字,会导致变的极大,导致傅立叶变换出现问题。
- 助教给出的解决方案是建议我使用频域上的直接反向滤波,但这好像并没有什么实际意义
- 故手动添上一个,这会避免上述极小值被除导致的异常。但是并不会达到理论上几乎完美(因为本身也会有abs/real的量化)的反向滤波效果。(后续实验均在此基础上进行)
1
2
3
4
5
6
7
8
9
10
11
12
13
14eps = 1e-3
def inverse(g_src_img, psf):
"""
无噪反向滤波
:param g_src_img: 降质图像
:param psf: psf的fft
:return: 滤波处理后的图像
"""
fft_G_img = fftshift(fft2(g_src_img))
# 精度问题,需添加eps
F = fft_G_img / (psf + eps)
F_ifft = ifft2(ifftshift(F))
f_img = np.abs(F_ifft)
return f_img -
反向滤波实现:
1
2
3# 逆滤波
inv_gray_lena = inverse(gray_lena_blurred, H_func)
imgWrite(inv_gray_lena, "实验二:图像复原/inv_gray_lena.png")-
反向滤波效果图(inv_gray_lena)如下:
-
-
-
维纳滤波:
-
傅立叶变换估计:
-
目前测试取,后续会最优求解
-
-
维纳滤波实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17def wiener(g_src_img, psf, k):
"""
weiner滤波
:param g_src_img: 降质图像
:param psf: psf的fft
:param k: 常数
:return: 滤波处理后的图像
"""
fft_G_img = fftshift(fft2(g_src_img))
F = (np.abs(psf * psf) / (np.abs(psf) ** 2 + k)) * fft_G_img / psf
F_ifft = ifft2(ifftshift(F))
f_img = np.abs(F_ifft)
return f_img
# wiener滤波
wiener_gray_lena = wiener(gray_lena_blurred, H_func, 0.05)
imgWrite(wiener_gray_lena, "实验二:图像复原/wiener_gray_lena.png")-
维纳滤波效果图(wiener_gray_lena)如下:
-
-
-
-
对降质后的图像施加均值为 0,方差为 10 的高斯噪声,对降质后的图像进行反向滤波和维纳滤波操作,得到复原图像。
-
添加高斯噪声(使用ex1的函数)
1
2
3# 添加高斯噪声
gray_lena_blurred_gauss = addGaussNoise(gray_lena_blurred, 10)
imgWrite(gray_lena_blurred_gauss, "实验二:图像复原/gray_lena_blurred_gauss.png")-
添加噪声后的降质图像(gray_lena_blurred_gauss)如下:
-
-
对降质有噪图像进行反向滤波:
1
2
3# 高斯逆滤波
inv_gray_lena_gauss = inverse(gray_lena_blurred_gauss, H_func)
imgWrite(inv_gray_lena_gauss, "实验二:图像复原/inv_gray_lena_gauss.png")-
效果图(inv_gray_lena_gauss)如下,可见无法复原:
-
-
对降质有噪图像进行维纳滤波:
1
2
3# 高斯wiener滤波
wiener_gray_lena_gauss = wiener(gray_lena_blurred_gauss, H_func, 0.05)
imgWrite(wiener_gray_lena_gauss, "实验二:图像复原/wiener_gray_lena_gauss.png")-
效果图(wiener_gray_lena_gauss)如下,可以复原,但仍有噪点:
-
-
-
在加噪声的情况下,对每一种方法通过计算复原出来的图像的峰值信噪比,进行最优参数的选择,包括反向滤波方法中进行复原的区域半径(这里指恢复频谱边缘到图像中心的像素点距离,实验时统一用像素个数/图像宽高像素数)、维纳方法中的噪声对信号的频谱密度比值𝐾。
-
最优参数寻找思路:
- 设定最优参数遍历区间,计算复原图像与原灰度图的PSNR,保留最大值及其对应参数,该参数即为最优参数。(一开始只保留了最大值PSNR,但后续要画图,故将代码改为保留PSNR和参数列表)
-
反向滤波最优复原半径:
-
反向滤波(复原半径)实现:本质上是一个低通滤波器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15def inverse_H(g_src_img, r):
"""
反向滤波(r)
:param g_src_img: 降质加噪图像
:param r: 复原半径
:return:
"""
h = np.array(
[[1 / H(u, v) if u ** 2 + v ** 2 <= r ** 2 else 0 for v in arange(-N / 2, N / 2)]
for u in arange(-N / 2, N / 2)], dtype=np.complex128)
fft_G_img = fftshift(fft2(g_src_img))
F = fft_G_img * h
F_ifft = ifft2(ifftshift(F))
f_img = np.abs(F_ifft)
return f_img -
最优半径寻找实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16def optimal_inverse(src_img, g_src_img, minr, maxr):
"""
寻找反向滤波最优复原半径
:param src_img: 原始灰度图
:param g_src_img: 降质加噪图
:param minr: 最小半径
:param maxr: 最大半径
:return: 最大psnr及其对应r
"""
psnr_lst, r_lst = [], arange(minr, maxr, 0.1)
for r in r_lst:
i_img = inverse_H(g_src_img, r)
psnr_lst.append(psnr(src_img, i_img))
subplot(211)
plot(r_lst, psnr_lst, ls="-", label="Radius")
return np.max(psnr_lst), r_lst[np.argmax(psnr_lst)]
-
-
维纳滤波最优频谱密度比值K:
-
最优频谱密度比值寻找实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16def optimal_wiener(src_img, g_src_img, mink, maxk):
"""
寻找最优频谱密度比值
:param src_img: 原始灰度图
:param g_src_img: 降质加噪图
:param mink: 最小k
:param maxk: 最大k
:return: 最大psnr及其对应k
"""
psnr_lst, k_lst = [], arange(mink, maxk, 0.01)
for k in k_lst:
w_img = wiener(g_src_img, H_func, k)
psnr_lst.append(psnr(src_img, w_img))
subplot(212)
plot(k_lst, psnr_lst, ls="-", label="K")
return np.max(psnr_lst), k_lst[np.argmax(psnr_lst)]
-
-
最优值寻找,并画图:
1
2
3print(f"inverse-blurred-gauss-PSNR:{optimal_inverse(gray_lena, gray_lena_blurred_gauss, 32, 35)}")
print(f"wiener-blurred-gauss-PSNR:{optimal_wiener(gray_lena, gray_lena_blurred_gauss, 0.01, 0.1)}")
savefig("实验二:图像复原/opt-psnr.png", dpi=300)-
统计图(opt-psnr.png)如下:
-
对于降质有噪图像最优参数为:半径
-
-
-
将降质图像和利用最优参数恢复后的图像同时显示出来,以便比较
-
恢复图像(compare)对比如下(顺序与ppt一致):
-
最优参数与PSNR如下:
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 lzhのBLOG!