877
30.16
Wie funktioniert ein Medianfilter?
30.16 Wie funktioniert ein Medianfilter?
Das linke Foto in Abbildung 30.10 ist so stark »verschneit«, dass es schwerfällt, etwas zu
erkennen. Kaum zu glauben, dass man durch ein relativ einfaches Computerprogramm fast
alle fehlerhaften Stellen reparieren kann. Das rechte Bild zeigt das Ergebnis einer so genann-
ten Medianfilterung. Obwohl es genauso viel Bildinformation wie das Original enthält, ist
es doch viel besser wahrnehmbar. Alte analoge Filme und Fotos, die durch viele Kratzer unan-
sehnlich geworden sind, werden mit ähnlichen Techniken »digital nachbearbeitet«.
Abb. 30.10: Medianfilterung eines Bildes mit vielen Störpixeln
Wie funktioniert ein Medianfilter? Abbildung 30.11 zeigt die Grundidee des Verfahrens. Für
jedes Pixel erstellt man eine Liste, in der das Pixel und seine acht Nachbarpixel aufgeführt
sind. Die Pixel werden durch Zahlenwerte repräsentiert, im einfachen Fall eines Schwarz-
Weiß-Bildes sind das Grauwerte, d.h. Zahlen zwischen 0 (Schwarz) und 255 (Weiß). Von die-
ser Liste benötigt man den Median. Wenn die Liste aus neun Pixeln sortiert ist, ist der
Median der mittlere Wert, das fünfte Pixel. Das zentrale Pixel wird schließlich durch das
Median-Pixel ersetzt. Auf diese Weise wurde das Pixel an seine Umgebung angepasst.
Abb. 30.11: Die Arbeitsweise eines Medianfilters: Das zentrale Pixel wird durch den Median
seiner Umgebung ersetzt.
Kapitel 30
Rechnen mit NumPy
878
Das folgende Python-Programm implementiert diese Idee. Die Besonderheit ist, dass nicht
in einer komplexen Wiederholungsanweisung jedes Pixel einzeln berechnet wird, sondern
dass Array-Operationen verwendet werden. Das ist viel effizienter.
Aus dem gestörten Bild wird ein zweidimensionales Array
a gebildet. Die Randpixel lassen
sich nicht filtern, deshalb ignorieren wir sie und betrachten nur das Innere des Bildes ohne
den Rand, also
a[1:-1, 1:-1]. Zu diesem Inneren wird ein dreidimensionales Array b
berechnet. Dieses Array enthält zu jedem Pixel von a[1:-1, 1:-1] (in der dritten Dimen-
sion) eine Sequenz mit neun Elementen, die die quadratische Umgebung des korrespondie-
renden Pixels darstellen. Jetzt kommt der Clou: Die neun Elemente dieser Sequenz werden
nun nicht für jedes Pixel des Bildes einzeln ermittelt, sondern auf einen Schlag für das
gesamte Array. Dazu werden aus dem Originalbild rechteckige Bereiche herauskopiert und
den nullten, ersten, zweiten ... Elementen der dritten Dimension des neuen Arrays
jeweils durch eine einzige mächtige Operation zugewiesen. Beispiel: Jedes Pixel im
Bereich
a[:-2, :-2] ist der obere linke Nachbar des korrespondierenden Pixels im Bereich
a[1:-1, 1:-1] (siehe Abbildung 30.12).
Abb. 30.12: Beispiele für Bereiche im Array a
Man kann sich das Array b auch als dreidimensionale Version des Bildes mit neun Schich-
ten vorstellen. Die ursprünglichen Pixel des Bildes sind in der Mitte, in der fünften Schicht.
Die erste Schicht besteht aus den oberen linken Nachbarn, die zweite Schicht besteht aus
den oberen Nachbarn, die dritte Schicht besteht aus den oberen rechten Nachbarn, die vierte
Schicht besteht aus den linken Nachbarn usw.
Skript:
# medianfilter.py
import PIL
import numpy as np
import matplotlib.pyplot as plt
FNAME = "elephant_damaged.png"
def medianfilter(a):
879
30.16
Wie funktioniert ein Medianfilter?
Erläuterung:
#1: Zum Inneren des gestörten Bildes wird ein dreidimensionales Array aus Nullen gebil-
det. Damit ist schon einmal eine Struktur vorgegeben. Nun werden in neun Schritten die
Nullen »schichtweise« durch Grauwerte ersetzt.
#2: Die erste Schicht (Index 0) in der dritten Dimension des Arrays b sind die oberen linken
Nachbarn der korrespondierenden Pixel. Die ersten Nullen im Array
b werden durch die
Grauwerte der oberen linken Nachbarn ersetzt.
#3: Die zweite Schicht (Index 1) sind die oberen Nachbarn der korrespondierenden Pixel.
#4: Die dritte Schicht (Index 2) sind die oberen rechten Nachbarn. Und so weiter. Das drei-
dimensionale Array
b wird aus neun Schichten in Richtung Achse 2 aufgebaut.
#5: Zurückgegeben wird ein zweidimensionales Array, das aus den Medianen in Richtung
Achse 2 besteht. Das bedeutet: Das zurückgegebene Array zeigt das Originalbild (allerdings
ohne Rand), bei dem jedes Pixel durch den Median seiner Nachbarpixel ersetzt worden ist.
Das ist das mediangefilterte Bild.
#6: Hier wird eine Bilddatei geöffnet, ein PIL.Image-Objekt erzeugt und mit dessen Hilfe
ein zweidimensionales Array mit Grauwerten
(0, ..., 255) erschaffen.
#7: Das Raster für die beiden Bilddarstellungen besteht aus einer Zeile und zwei Spalten.
Die nun kommende Darstellung hat die laufende Nummer 1.
#8: Das gestörte Originalbild wird gezeigt. Mit cmap=plt.cm.gray wird festgelegt, dass die
Zahlen des Arrays als Graustufen zu interpretieren sind.
h, w = a.shape
b = np.zeros((h-2, w-2, 9)) #1
b[:, :, 0] = a[:-2, :-2] #2
b[:, :, 1] = a[:-2,1:-1] #3
b[:, :, 2] = a[:-2, 2:] #4
b[:, :, 3] = a[1:-1, :-2]
b[:, :, 4] = a[1:-1,1:-1]
b[:, :, 5] = a[1:-1, 2:]
b[:, :, 6] = a[2:, :-2]
b[:, :, 7] = a[2:,1:-1]
b[:, :, 8] = a[2:, 2:]
return np.median(b, axis=2) #5
img = np.array(PIL.Image.open(FNAME)) #6
plt.subplot(1, 2, 1) #7
plt.imshow(img,cmap=plt.cm.gray) #8
plt.axis("off") #9
plt.subplot(1, 2, 2)
plt.imshow(medianfilter(img), cmap=plt.cm.gray) #10
plt.axis("off")
plt.show()

Get Python 3 - Lernen und professionell anwenden now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.