如何去除图像的运动模糊?

Viewed 97

有运动模糊的原图
image.png

网友已经可以做到的效果
image.png

2 Answers

法一:
观察模糊原图模糊,近似来源于沿某一方向直线运动导致,因此模糊核建立为直线模型,进一步采用维纳滤波去模糊得到如下效果:
image.png
耗时39ms左右,对应python可视化调参例程如下:

# === 模糊核生成 ===
def motion_blur_psf(length, angle):
    eps = 1e-3
    psf = np.zeros((length, length))
    center = length // 2
    tan_angle = np.tan(np.deg2rad(angle))
    if abs(tan_angle) <= 1:
        for i in range(length):
            offset = int(tan_angle * (i - center) + center)
            if 0 <= offset < length:
                psf[offset, i] = 1
    else:
        cot_angle = 1 / tan_angle
        for i in range(length):
            offset = int(cot_angle * (i - center) + center)
            if 0 <= offset < length:
                psf[i, offset] = 1
    psf /= psf.sum() + eps
    return psf

# === 维纳去模糊 ===
def wiener_deblur(blurred, psf, K):
    EPS = 1e-8
    h, w = blurred.shape

    psf_padded = np.zeros_like(blurred)
    ph, pw = psf.shape
    psf_padded[:ph, :pw] = psf
    # 中心化处理(避免频域错位)
    #psf_padded = np.roll(psf_padded, ph//4, axis=0)
    psf_padded = np.roll(psf_padded, int(-pw*0.9), axis=1)

    H = np.fft.fft2(psf_padded)
    G = np.fft.fft2(blurred)
    H_conj = np.conj(H)

    F_hat = G * H_conj / (np.abs(H)**2 + K + EPS)
    recovered = np.fft.ifft2(F_hat).real
    return np.clip(recovered, 0, 1)

def on_trackbar(val=None):
    length = cv2.getTrackbarPos('Length', 'Wiener Deblur') + 1
    angle = cv2.getTrackbarPos('Angle', 'Wiener Deblur')
    k_slider = cv2.getTrackbarPos('K x1000', 'Wiener Deblur')
    K = k_slider / 1000.0

    psf = motion_blur_psf(length, angle)
    restored = wiener_deblur(blurred_gray, psf, K)
    display = (restored * 255).astype(np.uint8)
    cv2.imshow('Wiener Deblur', display)

if __name__ == '__main__':
    img = cv2.imread('5wFpTQiqgAy.png', cv2.IMREAD_GRAYSCALE)
    blurred_gray = img.astype(np.float32) / 255.0

    cv2.namedWindow('Wiener Deblur', cv2.WINDOW_NORMAL)
    cv2.createTrackbar('Length', 'Wiener Deblur', 69, 200, on_trackbar)
    cv2.createTrackbar('Angle', 'Wiener Deblur', 131, 180, on_trackbar)
    cv2.createTrackbar('K x1000', 'Wiener Deblur', 1, 100, on_trackbar)

    on_trackbar()
    cv2.waitKey(0)
    cv2.destroyAllWindows()

速度较快,但不同运动模式的模糊需要根据情况建立不同的运动模糊核,非线性运动较难拟合

法二:
参考上海交大论文“A simple local minimal intensity prior and an improved algorithm for blind image deblurring”,基于Blind Deblurring的方式进行动态模糊恢复,得到如下结果:
image.png
采用论文对应的例程,在600x688的原图上耗时28s得到,更细致的调参应该可以提升效果,局限性是不同的图像(模糊方式,相机运动轨迹等不同)不适用同一组参数,可能需要重新调参,例程链接:https://github.com/FWen/deblur-pmp?tab=readme-ov-file
速度较慢但可以适配拟合非线性模糊

建议从最基本的weinar滤波开始试试

很棒。再提个建议,能不能在灵闪里用fft配维纳滤波的处理过程

f0e9df0cd98e4712a0eb1b7fb33e4efc.png
这个孔洞是模糊的,模糊原因是产品抖动造成的,这种方式是否可以用维纳滤波还原清晰度。

你可以用上面的python代码直接测一下看看