Bildverarbeitung · Python · Flächenmessung
OpenCV mit Python: Pixelanzahl und Konturfläche richtig vergleichen
Warum liefert OpenCV für dasselbe Objekt unterschiedliche Flächen? Eine binäre Maske enthält diskrete Bildpunkte; eine Kontur beschreibt eine geometrische Begrenzung. Wer Grenzwerte zwischen diesen Darstellungen überträgt, kann kleine Merkmale falsch bewerten. Dieser Leitfaden zeigt mit Python, wann connectedComponentsWithStats und wann contourArea zur Fragestellung passen.
Die Beispiele verwenden ausschließlich synthetische Masken. Die Zahlen sind nachvollziehbare Rechenergebnisse dieser Beispiele, keine Messwerte aus Kundenprojekten. Die vorgelagerte Segmentierung behandelt der Beitrag zu festen, Otsu- und adaptiven Schwellwerten.
Pixelanzahl und Konturfläche beantworten verschiedene Fragen
CC_STAT_AREA gibt die Anzahl der Pixel einer zusammenhängenden Komponente an. contourArea berechnet dagegen die von einer Kontur eingeschlossene Fläche mit der Greenschen Formel. Die offizielle OpenCV-API-Referenz [1] weist ausdrücklich darauf hin, dass beide Werte abweichen können. Bei selbstüberschneidenden Konturen ist besondere Vorsicht erforderlich.
Für eine Vorgabe wie „Wie viele Vordergrundpixel gehören zu diesem segmentierten Fleck?“ ist die Komponentenstatistik ein direkter Ausgangspunkt. Geht es um die Geometrie einer Begrenzung oder um weitere Formmerkmale, sind Konturen zweckmäßig. Den Zusammenhang mit Umfang, Momenten und Begrenzungsrechtecken erläutert das Tutorial zu Konturmerkmalen [3].
Die technische Auswahl sollte deshalb mit einer Definition beginnen: Zählen Löcher zur Fläche? Werden berührende Objekte gemeinsam ausgewertet? Bezieht sich ein Grenzwert auf Bildpunkte, eine geometrische Bildfläche oder eine physische Fläche am Bauteil? Ohne diese Festlegung ist ein numerisch präzises Ergebnis fachlich mehrdeutig.
Python-Beispiel: Quadrat und Quadrat mit Loch vergleichen
Benötigt werden Python, NumPy und OpenCV. Geprüft wurde der Code mit OpenCV 4.13.0 und NumPy 2.5.4. Als area_comparison.py speichern und mit python area_comparison.py ausführen. Er lädt keine Bilder und schreibt keine Dateien. Für eine eigene Maske verlangt die Funktion ein nicht leeres, zweidimensionales uint8-Array mit Werten 0 und 255.
import cv2 as cv
import numpy as np
def compare_areas(mask, connectivity=8):
if not isinstance(mask, np.ndarray):
raise ValueError("Expected a NumPy array.")
if mask.ndim != 2 or mask.dtype != np.uint8 or mask.size == 0:
raise ValueError("Expected a non-empty 2-D uint8 mask.")
if not np.isin(mask, [0, 255]).all():
raise ValueError("Mask values must be 0 or 255.")
if connectivity not in (4, 8):
raise ValueError("Connectivity must be 4 or 8.")
count, labels, stats, _ = cv.connectedComponentsWithStats(
mask, connectivity=connectivity, ltype=cv.CV_32S
)
contours, _ = cv.findContours(
mask, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE
)
return {
"objects": count - 1,
"pixel_areas": sorted(
int(stats[i, cv.CC_STAT_AREA]) for i in range(1, count)
),
"outer_contour_areas": sorted(
float(cv.contourArea(c)) for c in contours
),
}
if __name__ == "__main__":
square = np.zeros((20, 20), dtype=np.uint8)
square[5:15, 5:15] = 255
ring = square.copy()
ring[8:12, 8:12] = 0
print("OpenCV:", cv.__version__)
print("square:", compare_areas(square))
print("ring:", compare_areas(ring))
Das gefüllte Quadrat hat 100 Vordergrundpixel und eine äußere Konturfläche von 81. Seine Kontur verläuft zwischen den äußersten Pixelkoordinaten: zehn Pixelpositionen ergeben in jeder Richtung neun Koordinatenschritte. Nach dem Ausschneiden des 4 × 4 Pixel großen Lochs bleiben 84 Vordergrundpixel; die äußere Konturfläche bleibt 81.
Diese Abweichung ist im Beispiel erwartet. Die Funktion gibt zwei getrennte Listen zurück. Sie ordnet einzelne Konturen ausdrücklich keiner Komponentenkennung zu. Wer eine gemeinsame Tabelle pro Objekt benötigt, muss diese Zuordnung gesondert implementieren und prüfen.
Drei Fehlerquellen bei der Objektauswertung
1. Löcher mit einer äußeren Kontur übersehen
RETR_EXTERNAL ist hier bewusst gewählt: Der Code betrachtet nur äußere Konturen. Ein Loch ändert diese äußere Begrenzung im Beispiel nicht. Für eine rasterbasierte Materialfläche werden die Hintergrundpixel des Lochs dagegen nicht mitgezählt. Soll die innere Geometrie beschrieben werden, muss die Konturhierarchie ausgewertet werden; den Einstieg liefert das OpenCV-Konturtutorial [2].
Eine einfache Regel „äußere Fläche minus alle inneren Flächen“ braucht bei verschachtelten Inseln eine überprüfte Hierarchielogik. Ein anderer Retrieval-Modus allein definiert noch keine fachlich richtige Materialfläche. Für die konkrete Aufgabe empfiehlt sich zuerst ein kleines Gegenbeispiel mit bekannten Löchern und Inseln.
2. Diagonalen Kontakt unterschiedlich zählen
Die Komponentenfunktion unterstützt 4er- und 8er-Nachbarschaft. Zwei nur diagonal benachbarte Vordergrundpixel werden im ersten Fall getrennt und im zweiten gemeinsam gezählt. Label 0 gehört zum Hintergrund, deshalb zieht das Beispiel beim Objektzähler eins ab. Details stehen in Referenz [1].
Diese Wahl sollte dokumentiert bleiben. Ein Kratzer mit diagonaler Pixelkette kann sonst nach einer Parameteränderung plötzlich aus mehreren Objekten bestehen. Die Konturermittlung erhält den Parameter connectivity nicht; die beiden Auswertungswege sind daher kein automatisch identischer Objektkatalog.
3. Aus einer Pixelzahl ungeprüft Quadratmillimeter machen
Eine Flächenangabe im Bild ist noch keine überprüfte Bauteilfläche. Für eine physische Bewertung müssen Geometrie, Skalierung und zulässiger Arbeitsbereich geklärt sein. Der Leitfaden zur Kamerakalibrierung behandelt die geometrischen Voraussetzungen. Eine einzelne Umrechnungszahl darf nicht ohne Prüfung auf andere Abstände oder eine andere Kamerakonfiguration übertragen werden.
Ein pragmatischer Prüfplan
- Messgröße benennen: beispielsweise Vordergrundpixel einer Komponente, mit expliziter Loch- und Nachbarschaftsregel.
- Bekannte Masken prüfen: gefülltes Rechteck, Loch, Einzelpixel, diagonaler Kontakt und vollständig leere Maske.
- Randfälle ergänzen: angeschnittene Objekte am Bildrand, schmale Brücken und kleine Segmentierungsfehler. Erwartungen vor dem Vergleich festhalten.
- Reale Aufnahmen bewerten: dieselbe Auswertung unter zulässigen Aufnahmebedingungen mit fachlich geprüften Referenzen vergleichen.
- Konfiguration protokollieren: Maskenerzeugung, ROI, Nachbarschaft, Flächendefinition, Softwareversionen und Akzeptanzkriterium gemeinsam dokumentieren.
Dieser Prüfplan ist eine eigene technische Empfehlung. Er ersetzt keine anwendungsspezifische Freigabe. Insbesondere beweist ein bestandener Test mit synthetischen Masken nur, dass die vereinbarte Rechenlogik für diese Fälle funktioniert. Die Qualität der Segmentierung echter Merkmale muss separat untersucht werden.
Häufige Fragen
Ist die kleinere Konturfläche ein Rundungsfehler?
Beim gezeigten Quadrat nicht. Die beiden Ergebnisse folgen verschiedenen Flächendefinitionen. Ein pauschaler Korrekturaufschlag würde die Definition verschleiern und wäre für andere Formen nicht begründet.
Welche Methode soll ich für kleine Fehlerstellen verwenden?
Wenn die Entscheidung ausdrücklich von der Anzahl segmentierter Bildpunkte abhängt, beginnen Sie mit der Pixelanzahl pro Komponente. Prüfen Sie zusätzlich, ob kleine Änderungen der Maske die Entscheidung unvertretbar verändern. Ein anderer Flächenalgorithmus kann eine instabile Segmentierung nicht verlässlich ausgleichen.
Primärquellen
- OpenCV 4.13: Structural Analysis and Shape Descriptors
- OpenCV 4.13: Contours – Getting Started
- OpenCV 4.13: Contour Features
Quellen geprüft am 29. Oktober 2026. Code, synthetische Gegenbeispiele und Prüfplan sind eigene Lehrbeispiele und technische Empfehlungen.
