如何使用 FFT 从图像中删除重复模式

Bil*_*lal 8 python filtering fft image-processing

  • 我有由扫描仪生成的带有重复图案(水平白线)的肤色图像,该扫描仪使用一排传感器来感知照片。

    原始图像 原始图像2

  • 我的问题是如何使用 FFT 有效地对图像进行去噪,而不会对图像质量产生太大影响,有人告诉我,我必须手动抑制幅度谱中出现的线,但我不知道该怎么做,可以请告诉我该怎么做?

  • 我的方法是使用快速傅立叶变换(FFT)逐通道对图像进行去噪。

  • 我尝试过傅里叶域中的 HPF 和 LPF,但结果并不好,如您所见:

结果

我的代码:

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()
Run Code Online (Sandbox Code Playgroud)

Pas*_*uer 9

这是一个简单有效的线性滤波策略,用于消除水平线伪影:

\n

大纲:

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

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

    \n
  4. \n
  5. 将恢复的图像计算为“image \xe2\x88\x92 (hpf \xe2\x8a\x97 lpf) \xe2\x88\x97 image”。

    \n
  6. \n
\n

代码:

\n
# Copyright 2021 Google LLC.\n# SPDX-License-Identifier: Apache-2.0\n\nimport numpy as np\nfrom scipy.ndimage import convolve1d\nfrom scipy.signal import firwin, welch\n\ndef remove_lines(image, distortion_freq=None, num_taps=65, eps=0.025):\n  """Removes horizontal line artifacts from scanned image.\n  Args:\n    image: 2D or 3D array.\n    distortion_freq: Float, distortion frequency in cycles/pixel, or\n      `None` to estimate from spectrum.\n    num_taps: Integer, number of filter taps to use in each dimension.\n    eps: Small positive param to adjust filters cutoffs (cycles/pixel).\n  Returns:\n    Denoised image.\n  """\n  image = np.asarray(image, float)\n  if distortion_freq is None:\n    distortion_freq = estimate_distortion_freq(image)\n\n  hpf = firwin(num_taps, distortion_freq - eps,\n               pass_zero=\'highpass\', fs=1)\n  lpf = firwin(num_taps, eps, pass_zero=\'lowpass\', fs=1)\n  return image - convolve1d(convolve1d(image, hpf, axis=0), lpf, axis=1)\n\ndef estimate_distortion_freq(image, min_frequency=1/25):\n  """Estimates distortion frequency as spectral peak in vertical dim."""\n  f, pxx = welch(np.reshape(image, (len(image), -1), \'C\').sum(axis=1))\n  pxx[f < min_frequency] = 0.0\n  return f[pxx.argmax()]\n
Run Code Online (Sandbox Code Playgroud)\n

例子:

\n

在肖像图像上,estimate_distortion_freq估计失真频率为 0.1094 周期/像素(9.14 像素的周期)。过滤“image \xe2\x88\x92 (hpf \xe2\x8a\x97 lpf) \xe2\x88\x97 image”的传递函数如下所示:

\n

滤波器传递函数

\n

这是过滤后的输出remove_lines

\n

肖像图像上的过滤输出

\n

在皮肤图像上,estimate_distortion_freq估计失真频率为 0.08333 周期/像素(12.0 像素的周期)。过滤后的输出remove_lines

\n

皮肤图像上的过滤输出

\n

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

\n

  • 在 [您分享的示例结果](https://imgur.com/KlYg98c) 中,输入图像中的失真似乎具有更长的周期,大约 20 像素,而皮肤图像的失真周期为 12 像素。因此,未经调整的相同带阻滤波器将不会有效。您可以编辑您的问题以包含第二个示例中的输入图像以及有关此失真来自何处的更多信息(如果有的话)吗?这将帮助我和其他潜在的人了解这里讨论的扭曲范围,并提出更好的解决方案。 (2认同)
  • @Bilal,感谢您分享肖像图像示例并更新问题。基于此,我用修改后的策略替换了我的答案,我认为该策略效果更好。请看一看。 (2认同)