HOWTO · Python
OpenCV Dilate
In diesem Artikel erklären wir die morphologischen Transformationskonzepte wie Erosion und Dilatation, die wir verwenden, um Pixel von der Grenze eines bestimmten Objekts in einem Bild in OpenCV hinzuzufügen und zu entfernen.
Auf dieser Seite
Verwende cv2.dilate, um helle Vordergrundbereiche in einem Bild zu vergrößern. Bei OpenCV untersucht die Dilatation die Nachbarschaft jedes Pixels und erweitert den Vordergrund anhand eines strukturierenden Kernels. Derselbe Vorgang lässt sich auf Graustufen- und Binärbilder anwenden. Das folgende Beispiel verwendet ein Graustufenbild mit einem einzelnen hellen Pixel, damit der Effekt leicht zu erkennen ist.
Was die Dilatation in OpenCV bewirkt
Morphologische Operationen verarbeiten ein Bild mithilfe eines Kernels, der auch Strukturelement genannt wird. In einem Binärbild werden Vordergrundpixel üblicherweise weiß (255) und Hintergrundpixel schwarz (0) dargestellt. Bei der Dilatation erhält jedes Ausgabepixel den Maximalwert aus der Kernel-Nachbarschaft. Dadurch wachsen helle Bereiche, und nahe beieinanderliegende helle Komponenten können zusammenwachsen. Bei der Erosion wird stattdessen das Minimum der Nachbarschaft verwendet, sodass helle Bereiche schrumpfen.
Die Nachbarschaft gleitet über das Bild, ähnlich wie das lokale Fenster bei der 2D-Faltung. Die Dilatation ermittelt jedoch das Maximum der Nachbarschaft, statt eine gewichtete Summe zu berechnen. Ein deutschsprachiges Ziel für diese Seite ist in der bereitgestellten Bestandsaufnahme nicht verfügbar. Bei Graustufeneingaben hellt diese Maximumsoperation ebenfalls lokale Bereiche auf; sie ist nicht auf eine strikte Maske mit nur zwei Werten beschränkt.
Dilatation mit Python und OpenCV anwenden
Dieses eigenständige Beispiel verwendet ein kleines Graustufenbild mit einem einzelnen hellen Pixel und einer rechteckigen Nachbarschaft von 3 × 3. Wenn OpenCV und NumPy installiert sind, kommt cv2.dilate zum Einsatz. Andernfalls wendet die Ausweichlösung aus der Python-Standardbibliothek dieselbe Regel mit dem Maximum der Nachbarschaft an, sodass sich das Beispiel trotzdem ausführen lässt.
Der Code und die angezeigten Bezeichnungen oder Ausgaben in diesem Abschnitt bleiben auf Englisch.
import importlib.util
image = [
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 255, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
]
if importlib.util.find_spec("cv2") and importlib.util.find_spec("numpy"):
import cv2
import numpy as np
kernel = np.ones((3, 3), dtype=np.uint8)
dilated = cv2.dilate(np.array(image, dtype=np.uint8), kernel, iterations=1).tolist()
else:
dilated = [
[
max(image[y][x] for y in range(max(0, row - 1), min(5, row + 2))
for x in range(max(0, col - 1), min(5, col + 2)))
for col in range(5)
]
for row in range(5)
]
print(dilated)
[[0, 0, 0, 0, 0], [0, 255, 255, 255, 0], [0, 255, 255, 255, 0], [0, 255, 255, 255, 0], [0, 0, 0, 0, 0]]
Für einen dateibasierten Ablauf lädst du eine Graustufenquelle mit cv2.imread("input.png", cv2.IMREAD_GRAYSCALE) und prüfst anschließend, ob der zurückgegebene Wert nicht None ist, bevor du cv2.dilate aufrufst. Ein ungültiger Pfad oder eine nicht unterstützte Datei kann None ergeben; auf diesem Wert lässt sich keine Morphologieoperation ausführen, die ein Bild liefert. Bewahre Eingabe- und Ausgabe-Arrays getrennt auf, wenn du sie später vergleichen möchtest.
Wie Kernel und Iterationen die Dilatation beeinflussen
Der Kernel legt die Nachbarschaft und deren Form fest. Ein größerer Kernel untersucht einen größeren Bereich und vergrößert helle Merkmale im Allgemeinen stärker. Ein rechteckiger Kernel eignet sich für gleichmäßiges Wachstum in horizontaler und vertikaler Richtung; ein elliptischer oder kreuzförmiger Kernel verändert die Geometrie der Nachbarschaft. Wähle Abmessungen und Form passend zu den Lücken und Merkmalen, die du beeinflussen möchtest, und prüfe das Ergebnis anschließend anhand repräsentativer Bilder.
Das Argument iterations wiederholt die Dilatation. Mit jeder weiteren Iteration verstärkt sich das Wachstum, sodass sich schmale Lücken schließen und benachbarte Bereiche verschmelzen können. Beginne mit einer Iteration und einem kleinen Kernel und passe dann jeweils nur eine Einstellung an. Ein optisch stärkerer Effekt ist nicht automatisch besser: Zu starkes Wachstum kann feine Details beseitigen.
Dilatation mit Erosion, Opening und Closing vergleichen
Die Erosion lässt helle Vordergrundbereiche schrumpfen, die Dilatation lässt sie wachsen. Beim Opening folgt auf eine Erosion eine Dilatation. Abhängig vom Kernel und vom Bild kann dadurch kleines helles Detail entfernt werden, während größere Strukturen erhalten bleiben. Beim Closing folgt auf eine Dilatation eine Erosion; dadurch können kleine dunkle Lücken in hellen Strukturen gefüllt werden. Diese Abläufe stellen nicht garantiert jedes ursprüngliche Pixel wieder her: Ihre Wirkung hängt vom Strukturelement und den Merkmalen des Bildes ab.
Verwende Opening, wenn kleines helles Rauschen das Problem ist, und Closing, wenn es um kleine dunkle Löcher oder Unterbrechungen in einem hellen Vordergrund geht. Bei dunklen Objekten auf hellem Hintergrund solltest du zuerst festlegen, welche Polarität als Vordergrund gelten soll. Möglicherweise musst du das Bild invertieren, bevor du dieselben Überlegungen anwendest.
Vordergrundpolarität und Ausgabe verstehen
Die einfache Dilatation von OpenCV behandelt höhere Pixelwerte als die Werte, die sich ausbreiten. In einem Binärbild mit hellen Bereichen auf dunklem Hintergrund breitet sich der weiße Vordergrund in den benachbarten schwarzen Hintergrund aus. Bei einem Foto mit dunklem Text auf einer weißen Seite ist die helle Seite der Bereich mit den hohen Werten. Die Dilatation vergrößert daher den Seitenbereich und kann den dunklen Text dünner erscheinen lassen. Deshalb kann das Ergebnis der intuitiven Vorstellung widersprechen, dass das Objekt selbst größer wird.
Soll der dunkle Text selbst wachsen, invertiere das Graustufenbild, dilatiere das invertierte Bild und invertiere anschließend das Ergebnis zurück. Bei einem Farbbild wird jeder Kanal als Bilddaten verarbeitet. Verwende eine einkanalige Graustufen- oder Binärmaske, wenn der gewünschte Vordergrund eine Form oder Beschriftung und nicht eine Farbintensität ist.
Häufige Probleme mit Eingabe und Anzeige prüfen
Prüfe vor der Verarbeitung, ob die Quelle geladen wurde und die Kernel-Abmessungen zu den Bilddetails passen. Ein breiter Kernel oder viele Iterationen können getrennte Komponenten zusammenführen oder schmale Lücken entfernen. Wenn sich die Ausgabe nicht zu verändern scheint, prüfe, ob der ausgewählte Vordergrund heller als seine Umgebung ist und ob die Kernel-Nachbarschaft benachbarte Pixel umfasst, die für die Änderung relevant sind. Größe und Form des Kernels bestimmen, welche lokalen Werte einbezogen werden. Daher kann ein Kernel auch Merkmale beeinflussen, die größer sind als er selbst.
OpenCV liest Farbbilder in der Kanalreihenfolge BGR ein, während Matplotlib ein Array mit drei Kanälen als RGB interpretiert. Wandle ein BGR-Bild mit cv2.cvtColor(image, cv2.COLOR_BGR2RGB) um, bevor du es mit matplotlib.pyplot.imshow darstellst. Übergib bei Graustufen-Arrays cmap="gray", damit die Anzeige eine Graustufen-Farbskala verwendet. Eine Abweichung der Anzeigefarben beeinflusst die Visualisierung, nicht die Dilatationsberechnung selbst.