可以应用哪个图像过滤器从损坏的 jpeg 中删除网格图案?

信息处理 图像处理 matlab 噪音 JPEG 图案
2022-01-10 18:10:35

我有大约 1,400 个 jpeg,它们以某种方式损坏并且丢失了备份图像。它们似乎都有相同的网格线图案(即网格不会从图像转移到图像。

以下是其中一张图片的样子:

在此处输入图像描述

Matlab 中是否有任何图像过滤技术可以消除或平滑这种网格图案?

2个回答

您可以使用标准的修复算法。这些算法用围绕这些标记像素的像素值替换图像中的标记像素。这里的挑战是检测网格(我的测试似乎表明它不是一个完全规则的网格)。所以,我想出了这个解决方案:

from PIL import Image
import requests
from io import BytesIO
import cv2

url = "http://i.stack.imgur.com/Ahrnl.jpg"
response = requests.get(url)
img = Image.open(BytesIO(response.content))

plt.imshow(img)
A = np.array(img)
A2 = A.copy()
A_gray = cv2.cvtColor(A, cv2.COLOR_RGB2GRAY)


# Do some rough edge detection to find the grid
sX = cv2.Sobel(A_gray, cv2.CV_64F, 1, 0, ksize=3)
sY = cv2.Sobel(A_gray, cv2.CV_64F, 0, 1, ksize=3)
sX[sX<0] = 0
sY[sY<0] = 0

plt.subplot(221)
plt.imshow(sX)

plt.subplot(222)
plt.imshow(sY)

plt.subplot(223)
# the sum operation projects the edges to the X or Y-axis. 
# The 0.2 damps the high peaks a little
eX = (sX**.2).sum(axis=0)  
eX = np.roll(eX, -1) # correct for the 1-pixel offset due to Sobel filtering
plt.plot(eX)

plt.subplot(224)
eY = (sY**.2).sum(axis=1)
eY = np.roll(eY, -1)
plt.plot(eY)

mask = np.zeros(A2.shape[:2], dtype=np.uint8)
mask[eY>480,:] = 1
mask[:, eX>390] = 1


A2[mask.astype(bool),:] = 255
plt.figure()
plt.subplot(221)
plt.imshow(A)

plt.subplot(222)
plt.imshow((A2))

restored = cv2.inpaint(A, mask, 1, cv2.INPAINT_NS)
plt.subplot(223)
plt.imshow(restored)

程序输出如下:

在此处输入图像描述

在此处输入图像描述

为了检测网格,我做了一个快速而肮脏的解决方案。它可以改进很多,但它显示了最初的想法。一般流程是:

  1. 检测网格
  2. 创建一个掩码,描述哪些像素被网格破坏
  3. 修复损坏的像素。

对于修复,我使用了 OpenCV修复操作。为了检测网格,我使用 Sobel 滤波器在 X 和 Y 方向进行边缘检测。然后我将 X 方向和 Y 方向上的所有边缘值相加,以找到网格线所在的峰值。然后,我选择最高峰作为估计网格线的坐标。它并不完美(例如图像中的强边缘被错误地检测为网格线),但它显示了这个想法。它可以通过例如霍夫变换来找到线,踢出非常强的边缘等来改进。

或者,如果所有图像的网格确实相同,那么您可以对所有图像联合执行网格检测,这将产生更好的精度(只需执行上述技术,但在选择峰值之前,将结果从所有图片)。更详细地说,您将计算所有图像的 eX 并将所有这些 eX 添加到单个向量中。该向量将具有更清晰的峰值结构,并且可以更轻松地进行阈值处理。

我尝试了一个非常简单的算法,在该图像的 R 和 G 通道上运行 3x3 中值滤波器,效果很好。 在此处输入图像描述 python代码非常简单:

import scipy.signal as sp
from scipy import ndimage

image = ndimage.imread('Ahrnl.jpg', flatten=False)
image_filtered = np.array(image)
for i in range(2) :
  image_filtered[:,:,i] = sp.medfilt2d(image[:,:,i])

或者,您可以使用此问题中讨论的频域过滤:https ://stackoverflow.com/questions/34027840/removing-periodic-noise-from-an-image-using-the-fourier-transform

图像的傅立叶变换清楚地显示了与这种周期性噪声相对应的光谱中的一些重复“点”。 在此处输入图像描述

正如马克西米利安所指出的,后一种方法只有在噪声是完全周期性的情况下才能很好地工作,而这里的情况似乎并非如此。

我尝试运行一个非常愚蠢的滤波器,它在 x 和 y 方向上以 9 的倍数为中心将 5x5 平方的频率箱归零​​,它(某种程度上)抑制了噪声,但在不包含噪声的位置引入了伪影(例如天空)。

也许可以通过仔细的陷波滤波器设计做得更好,而不是直接将 FFT 箱归零(在实践中永远不要这样做!)并且只在存在噪声的图像区域应用滤波器(即不过滤天空)。

在此处输入图像描述