如何使用 FFT 去除图像中的重复图案

How to remove repititve pattern from an image using FFT

我的代码:

from skimage.io import imread, imsave
from matplotlib import pyplot as plt
import numpy as np

img = imread('skin.jpg')

R = img[...,2]
G = img[...,1]
B = img[...,0]

f1 = np.fft.fft2(R)
fshift1 = np.fft.fftshift(f1)
phase_spectrumR = np.angle(fshift1)
magnitude_spectrumR = 20*np.log(np.abs(fshift1))

f2 = np.fft.fft2(G)
fshift2 = np.fft.fftshift(f2)
phase_spectrumG = np.angle(fshift2)
magnitude_spectrumG = 20*np.log(np.abs(fshift2))

f3 = np.fft.fft2(B)
fshift3 = np.fft.fftshift(f3)
phase_spectrumB = np.angle(fshift3)
magnitude_spectrumB = 20*np.log(np.abs(fshift2))

#===============================
# LPF # HPF
magR = np.zeros_like(R) #  = fshift1 # 
magR[magR.shape[0]//4:3*magR.shape[0]//4,
 magR.shape[1]//4:3*magR.shape[1]//4] = np.abs(fshift1[magR.shape[0]//4:3*magR.shape[0]//4,
  magR.shape[1]//4:3*magR.shape[1]//4]) # =0 #
resR = np.abs(np.fft.ifft2(np.fft.ifftshift(magR)))
resR = R - resR
#===============================
magnitude_spectrumR
plt.subplot(221)
plt.imshow(R, cmap='gray')
plt.title('Original')

plt.subplot(222)
plt.imshow(magnitude_spectrumR, cmap='gray')
plt.title('Magnitude Spectrum')

plt.subplot(223)
plt.imshow(phase_spectrumR, cmap='gray')
plt.title('Phase Spectrum')

plt.subplot(224)
plt.imshow(resR, cmap='gray')
plt.title('Processed')

plt.show()

这里有一个简单有效的线性过滤策略来去除水平线伪影:

大纲:

  1. 通过在垂直维度上寻找图像功率谱中的峰值来估计失真的频率。函数 scipy.signal.welch 对此很有用。

  2. 设计两个滤波器:截止频率刚好低于失真频率的高通滤波器和截止频率接近直流的低通滤波器。我们将垂直应用高通滤波器,水平应用低通滤波器,以尝试隔离失真。我们将使用 scipy.signal.firwin 来设计这些过滤器,尽管有很多方法可以做到这一点。

  3. 将恢复后的图像计算为“image − (hpf ⊗ lpf) ∗ image”。

代码:

# Copyright 2021 Google LLC.
# SPDX-License-Identifier: Apache-2.0

import numpy as np
from scipy.ndimage import convolve1d
from scipy.signal import firwin, welch

def remove_lines(image, distortion_freq=None, num_taps=65, eps=0.025):
  """Removes horizontal line artifacts from scanned image.
  Args:
    image: 2D or 3D array.
    distortion_freq: Float, distortion frequency in cycles/pixel, or
      `None` to estimate from spectrum.
    num_taps: Integer, number of filter taps to use in each dimension.
    eps: Small positive param to adjust filters cutoffs (cycles/pixel).
  Returns:
    Denoised image.
  """
  image = np.asarray(image, float)
  if distortion_freq is None:
    distortion_freq = estimate_distortion_freq(image)

  hpf = firwin(num_taps, distortion_freq - eps,
               pass_zero='highpass', fs=1)
  lpf = firwin(num_taps, eps, pass_zero='lowpass', fs=1)
  return image - convolve1d(convolve1d(image, hpf, axis=0), lpf, axis=1)

def estimate_distortion_freq(image, min_frequency=1/25):
  """Estimates distortion frequency as spectral peak in vertical dim."""
  f, pxx = welch(np.reshape(image, (len(image), -1), 'C').sum(axis=1))
  pxx[f < min_frequency] = 0.0
  return f[pxx.argmax()]

示例:

在人像图像上,estimate_distortion_freq 估计失真频率为 0.1094 cycles/pixel(周期为 9.14 像素)。过滤“image − (hpf ⊗ lpf) ∗ image”的传递函数如下所示:

这是 remove_lines 的过滤输出:

在皮肤图像上,estimate_distortion_freq 估计失真频率为 0.08333 cycles/pixel(周期为 12.0 像素)。 remove_lines:

的过滤输出

两个示例中的失真大部分都已消除。它并不完美:在肖像图像上,在顶部和底部边界附近仍然可以看到一些波纹,这是使用大型滤波器或傅立叶方法时的典型缺陷。尽管如此,它还是比原始图像有了很好的改进。