Welcher Bildfilter kann angewendet werden, um Gittermuster von beschädigten JPEGs zu entfernen?

8

Ich habe ungefähr 1.400 JPEGs, die irgendwie beschädigt wurden und die Backup-Images verloren haben. Sie scheinen alle das gleiche Gittermuster von Linien über jedem zu haben (dh das Gitter verschiebt sich nicht von Bild zu Bild.

So sieht eines dieser Bilder aus:

Geben Sie hier die Bildbeschreibung ein

Gibt es Bildfiltertechniken in Matlab, insbesondere oder auf andere Weise, die dieses Gittermuster entfernen oder glätten?

Stephen E.
quelle
2
Können Sie uns weitere Informationen darüber geben, wie diese Bilder beschädigt wurden? Dies ist ein seltsames Muster, da es sehr pixellokal ist und eine hohe Auflösung im Frequenzbereich erfordert, was möglicherweise einen schrecklich kaputten JPEG-Encoder bedeuten würde.
Marcus Müller
Ich bin mir nicht ganz sicher, sorry. Die Bilder sind Teil einer Datenbank, die einige Male den Besitzer gewechselt hat, und die Leute waren nicht so vorsichtig, wie sie sollten (... Studenten). In Bezug auf das pixellokale Problem stimme ich zu. Auf einigen Fotos mit dunkleren Wasseroberflächen ist das Gittermuster sehr hell.
Stephen E
@ MarcusMüller: Ein schrecklich kaputter JPEG- Decoder scheint mir wahrscheinlicher, obwohl ich denke , dass so oder so möglich ist. Auf jeden Fall scheint es mir, basierend auf dem ungleichmäßigen und nicht-2-Potenz-Abstand der Linien, dass die Bilder wahrscheinlich vergrößert und neu codiert wurden, nachdem die Beschädigung aufgetreten ist DCT-Domain ist wahrscheinlich zwecklos. Die unten stehende Inpainting-Lösung von Maximilian Matthé ist wahrscheinlich die beste Wahl für das OP.
Ilmari Karonen
1
Oh, und das OP sollte auf jeden Fall eine Sicherungskopie der Bilder speichern, bevor versucht wird, sie auf irgendeine Weise zu reparieren, nur für den Fall, dass jemand sie jemals erneut analysieren möchte. Das Inpainting, wie gut es auch gemacht wird, ist immer eine verlustbehaftete Operation und kann zu Verzerrungen führen (da es im Grunde genommen darum geht, gefälschte Daten zu erstellen, um die beschädigten Pixel zu ersetzen). Das Gleiche gilt auch für die Medianfilterung oder Frequenzentfernung oder für alles andere, was diese Art von Schaden verbergen könnte.
Ilmari Karonen
@IlmariKaronen Danke für den Tipp. Ich werde auf jeden Fall versuchen, mit diesen Bildern vorsichtiger umzugehen.
Stephen E

Antworten:

16

Sie können einen Standard-Inpainting-Algorithmus verwenden. Diese Algorithmen ersetzen markierte Pixel in einem Bild durch die Pixelwerte, die diese markierten Pixel umgeben. Die Herausforderung besteht hier darin, das Gitter zu erkennen (meine Tests scheinen zu zeigen, dass es kein vollständig reguläres Gitter ist). Also habe ich mir diese Lösung ausgedacht:

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)

Die Programmausgabe lautet wie folgt:

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

Um das Gitter zu erkennen, habe ich eine schnelle und schmutzige Lösung gefunden. Es kann viel verbessert werden, aber es zeigt die ursprüngliche Idee. Der allgemeine Ablauf ist:

  1. Erkennen Sie das Gitter
  2. Erstellen Sie eine Maske, die beschreibt, welche Pixel durch das Raster beschädigt werden
  3. Malen Sie die beschädigten Pixel.

Zum Inpainting habe ich OpenCV Inpaint verwendet. Zur Erkennung des Gitters habe ich eine Kantenerkennung in X- und Y-Richtung mit einem Sobel-Filter durchgeführt. Dann addiere ich alle Kantenwerte in X- und Y-Richtung, um Spitzen zu finden, bei denen sich die Gitterlinien befinden. Dann wähle ich die höchsten Spitzen als Koordinaten, bei denen die Gitterlinien geschätzt werden. Es funktioniert nicht perfekt (z. B. werden starke Kanten im Bild fälschlicherweise als Gitterlinien erkannt), aber es zeigt die Idee. Es kann zB durch Hough-Transformation verbessert werden, um Linien zu finden, sehr starke Kanten herauszuschmeißen usw.

Wenn das Raster für alle Bilder wirklich gleich ist, können Sie alternativ die Rastererkennung für alle Bilder gemeinsam durchführen, was zu einer viel besseren Genauigkeit führen würde (führen Sie einfach die oben beschriebene Technik aus, aber fassen Sie die Ergebnisse aus zusammen, bevor Sie die Peaks auswählen alle Bilder). Im Detail würden Sie eX für alle Bilder berechnen und alle diese eX zu einem einzigen Vektor addieren. Dieser Vektor hat eine viel klarere Peakstruktur und die Schwellenwertbildung kann einfacher durchgeführt werden.

Maximilian Matthé
quelle
Danke für deinen Beitrag! Ihr Ergebnis hier ist wirklich schön! Ich werde es versuchen. Haftungsausschluss: Ich bin ein Anfänger in der Bildverarbeitung, daher werde ich einige Zeit brauchen, um mich selbst durchzuarbeiten, aber es wird als gelöst markiert, da es auf Ihrer Seite so gut funktioniert. In welcher Umgebung führen Sie diesen Algorithmus aus? Ich denke, dass eine unerwünschte Kantenerkennung in Bezug auf Instrumentierung und Infrastruktur im Bild kein großes Problem darstellt, da die meisten Bilder nichts davon enthalten und nur Tundra und / oder Wasser sind. Wie addieren Sie die Spitzen aller Bilder?
Stephen E
Vielen Dank! Die Umgebung ist Python und ich habe gerade einen Hinweis hinzugefügt, was ich mit dem Aufsummieren der Peaks für alle Bilder meine.
Maximilian Matthé
3

Ich habe einen wirklich einfachen Algorithmus ausprobiert, bei dem ein 3x3-Medianfilter auf den R- und G-Kanälen dieses Bildes ausgeführt wird, und er funktioniert recht gut. Geben Sie hier die Bildbeschreibung ein Der Python-Code ist wirklich einfach:

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

Alternativ können Sie die Frequenzbereichsfilterung wie in dieser Frage beschrieben verwenden: /programming/34027840/removing-periodic-noise-from-an-image-using-the-fourier-transform

Die Fourier-Transformation Ihres Bildes zeigt deutlich einige wiederholte "Punkte" im Spektrum, die diesem periodischen Rauschen entsprechen. Geben Sie hier die Bildbeschreibung ein

Wie Maximilian betonte, funktioniert diese letztere Methode nur dann gut, wenn das Rauschen perfekt periodisch ist, was hier nicht der Fall zu sein scheint.

Ich habe versucht, einen wirklich dummen Filter zu verwenden, der 5x5 Quadrate von Frequenzbereichen, die um ein Vielfaches von 9 in x- und y-Richtung zentriert sind, auf Null setzt und das Rauschen (irgendwie) unterdrückt, aber Artefakte an Orten einführt, die kein Rauschen enthalten (z Himmel).

Mit einem sorgfältigen Notch-Filter-Design kann man es vielleicht besser machen, anstatt die FFT-Bins direkt auf Null zu setzen ( in der Praxis niemals! ) Und den Filter nur in Bereichen des Bildes anzuwenden, in denen das Rauschen vorhanden ist (dh den Himmel nicht filtern).

Geben Sie hier die Bildbeschreibung ein

Atul Ingle
quelle
In Ihrer letzten Zeile, glaube ich, filtern Sie den roten Kanal nur zweimal (letzter Index sollte i sein, nicht 0)
Maximilian Matthé
@ MaximilianMatthé guter Fang! (Zum Glück war mein tatsächlicher Code, den ich ausgeführt habe, in Ordnung: P)
Atul Ingle
Zur Fourier-Transformationsmethode: Dies funktioniert nur dann zuverlässig, wenn das Gitter wirklich regelmäßig ist (dh der gleiche Abstand zwischen allen Linien). Ich konnte keine Parameter finden (zumindest nicht schnell), so dass ich ein reguläres Gitter über die beschädigten Linien zeichnen konnte. Dann wäre die Fourier-Methode auch nicht in der Lage, dieses nicht genau periodische Rauschen zu entfernen.
Maximilian Matthé
@ MaximilianMatthé Sie haben Recht - Die FFT-Methode ist schwierig, da das Rauschen nicht perfekt periodisch ist. Es könnte jedoch mit einem sorgfältigen Kerbfilterdesign funktionieren. Könnte sein.
Atul Ingle
Danke für deinen Beitrag! Ich habe einen 3x3-Medianfilter in Matlab ausprobiert und während er das Gitter entfernte (meistens), mochte ich die Detailverringerung des Bildes nicht (sie müssen in einem Popup in einer Web-Mapping-Anwendung angezeigt werden.
Stephen E