¿Qué filtro de imagen se puede aplicar para eliminar el patrón cuadriculado de jpegs corruptos?

8

Tengo alrededor de 1.400 archivos JPEG que se han dañado de alguna manera y han perdido las imágenes de copia de seguridad. Todos parecen tener el mismo patrón de líneas cuadriculadas sobre cada una (es decir, la cuadrícula no cambia de una imagen a otra.

Así es como se ve una de estas imágenes:

ingrese la descripción de la imagen aquí

¿Existen técnicas de filtrado de imágenes en Matlab en particular o de otra manera que eliminen o suavicen este patrón de cuadrícula?

Stephen E
fuente
2
¿Puedes darnos más información sobre cómo estas imágenes se corrompieron? Este es un patrón extraño, ya que es muy local en píxeles, lo que requiere una alta resolución en el dominio de frecuencia, lo que implicaría un codificador JPEG horriblemente roto, ¿tal vez?
Marcus Müller
No estoy completamente seguro, lo siento. Las imágenes son parte de una base de datos que ha cambiado de manos varias veces y las personas no han sido tan cuidadosas como deberían (... estudiantes de grado). En cuanto al problema de píxeles locales, estoy de acuerdo. En algunas fotos que incluyen superficies de agua más oscuras, el patrón de cuadrícula es muy claro.
Stephen E
@ MarcusMüller: un decodificador JPEG horriblemente roto me parece más probable, aunque supongo que de cualquier manera es posible. De todos modos, en base al espaciado desigual y sin potencia de 2 de las líneas, me parece que las imágenes probablemente se han ampliado y codificado nuevamente después de la corrupción, por lo que, por desgracia, tratando de arreglarlas en el El dominio DCT es probablemente inútil. La solución de pintura de Maximilian Matthé a continuación es probablemente la mejor apuesta del OP.
Ilmari Karonen
1
Ah, y el OP definitivamente debería guardar una copia de seguridad de las imágenes antes de intentar arreglarlas de alguna manera, en caso de que alguien quiera volver a analizarlas. La pintura, por bien hecha que sea, siempre es una operación con pérdidas y tiene el potencial de introducir sesgos (ya que básicamente equivale a inventar datos falsos para reemplazar los píxeles corruptos). Y lo mismo ocurre con el filtrado medio o la eliminación de frecuencia también, o cualquier otra cosa que pueda ocultar este tipo de daño.
Ilmari Karonen
@IlmariKaronen Gracias por la sugerencia. Definitivamente trataré de ser más cuidadoso con estas imágenes.
Stephen E

Respuestas:

16

Puede usar un algoritmo de pintura estándar. Estos algoritmos reemplazan los píxeles marcados en una imagen con los valores de píxeles que rodean estos píxeles marcados. El desafío aquí es detectar la cuadrícula (mis pruebas parecen mostrar que no es una cuadrícula completamente regular). Entonces, se me ocurrió esta solución:

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)

La salida del programa es la siguiente:

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

Para detectar la red hice una solución rápida y sucia. Se puede mejorar mucho, pero muestra la idea inicial. El flujo general es:

  1. detectar la cuadrícula
  2. crear una máscara que describa qué píxeles están dañados por la cuadrícula
  3. pintar los píxeles corruptos.

Para la pintura, utilicé la operación de pintura OpenCV . Para detectar la cuadrícula, realicé la detección de bordes en dirección X e Y utilizando un filtro Sobel. Luego agrego todos los valores de borde en la dirección X e Y para encontrar picos, donde están las líneas de la cuadrícula. Luego, elijo los picos más altos como las coordenadas donde se estiman las líneas de la cuadrícula. No funciona perfectamente (por ejemplo, los bordes fuertes de la imagen se detectan falsamente como líneas de cuadrícula), pero muestra la idea. Se puede mejorar, por ejemplo, con la transformación de Hough para encontrar líneas, patear bordes muy fuertes, etc.

Alternativamente, si la cuadrícula es realmente la misma para todas las imágenes, entonces puede realizar la detección de la cuadrícula conjuntamente para todas las imágenes, lo que produciría una precisión mucho mejor (solo realice la técnica anterior, pero antes de elegir los picos, resuma los resultados de todas las imágenes). Con más detalle, calcularía eX para todas las imágenes y agregaría todas estas eX juntas en un solo vector. Este vector tendrá una estructura de pico mucho más clara y el umbral puede hacerse más fácilmente.

Maximilian Matthé
fuente
¡Gracias por su aporte! ¡Tu resultado aquí es realmente bueno! Voy a intentar esto. Descargo de responsabilidad: soy muy novato en el procesamiento de imágenes, por lo que me llevará algún tiempo trabajar por mi cuenta, pero lo marcaré resuelto ya que funciona muy bien en su extremo. ¿En qué entorno estás ejecutando este algoritmo? Creo que la detección indeseable de bordes en instrumentación e infraestructura en la imagen no será un gran problema ya que la mayoría de las imágenes no incluyen nada de eso y son solo Tundra y / o agua. ¿Cómo haces para sumar los picos de todas las imágenes?
Stephen E
¡Gracias! El entorno es Python y acabo de agregar una nota sobre lo que quiero decir al resumir los picos de todas las imágenes.
Maximilian Matthé
3

Probé un algoritmo realmente simple de ejecutar un filtro mediano de 3x3 en los canales R y G de esa imagen y funciona bastante bien. ingrese la descripción de la imagen aquí El código de Python es realmente simple:

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])

Alternativamente, puede usar el filtrado de dominio de frecuencia como se describe en esta pregunta: /programming/34027840/removing-periodic-noise-from-an-image-using-the-fourier-transform

La transformación de Fourier de su imagen muestra claramente algunos "puntos" repetidos en el espectro correspondiente a este ruido periódico. ingrese la descripción de la imagen aquí

Como señaló Maximilian, este último método funciona bien solo si el ruido es perfectamente periódico, lo que no parece ser el caso aquí.

Intenté ejecutar un filtro realmente estúpido que pone a cero 5x5 cuadrados de intervalos de frecuencia centrados alrededor de múltiplos de 9 en ambas direcciones xey, y (más o menos) suprime el ruido pero introduce artefactos en ubicaciones que no contienen ruido (por ejemplo, el cielo).

Quizás se pueda hacer mejor con un diseño cuidadoso de filtro de muesca en lugar de poner a cero directamente los contenedores FFT (¡ nunca lo haga en la práctica! ) Y solo aplicar el filtro en las regiones de la imagen donde está presente el ruido (es decir, no filtrar el cielo).

ingrese la descripción de la imagen aquí

Atul Ingle
fuente
en su última línea, creo que simplemente filtra el canal rojo dos veces (el último índice debe ser i, no 0)
Maximilian Matthé
@ MaximilianMatthé buena captura! (Afortunadamente, mi código real que ejecuté estaba bien: P)
Atul Ingle
Con respecto al método de transformación de Fourier: esto solo funciona de manera confiable, si la cuadrícula es realmente regular (es decir, la misma distancia entre todas las líneas). No pude (al menos no rápidamente) encontrar parámetros de modo que pudiera dibujar una cuadrícula regular encima de las líneas corruptas. Entonces, el método de Fourier tampoco podría eliminar este ruido no exactamente periódico.
Maximilian Matthé
@ MaximilianMatthé tiene razón: el método FFT es complicado ya que el ruido no es un patrón perfectamente periódico. Pero podría funcionar con un diseño de filtro de muesca cuidadoso. Tal vez.
Atul Ingle
¡Gracias por su aporte! Probé un filtro de mediana de 3x3 en Matlab y, aunque eliminó la cuadrícula (en su mayoría), no me gustó la disminución en el detalle de la imagen (deben aparecer en una ventana emergente en una aplicación de mapeo web)
Stephen E