5.12. Binäre Schwellenwertbildung¶
Viele Bildverarbeitungs-Pipelines laufen auf eine Frage zu jedem Pixel hinaus: Liegt diese Helligkeit innerhalb des Bereichs, der „Vordergrund“ bedeutet? Liegt diese Farbe nahe genug an Rot, um die von der Anwendung verfolgte Markierung zu sein? Ist dieses Pixel Teil der Kandidatenmenge, die die nächste Stufe der Pipeline betrachten soll? Schwellenwertbildung ist die Operation, die diese Fragen an jeder Position in eine binäre Antwort verwandelt – an, wenn das Pixel passt, aus, wenn nicht – und das gesamte Bild auf eine Maske reduziert, gegen die der Rest der Pipeline arbeiten kann.
5.12.1. Die binary-Methode¶
Die Methode binary() führt diese Klassifizierung in einem Aufruf über jedes Pixel hinweg aus. Sie nimmt eine Liste von Schwellenwertbereichen entgegen – die Bedingungen, die ein Pixel erfüllen kann, um als „an“ zu zählen – und schreibt das Bild so um, dass jedes Pixel, das mindestens einen der Bereiche erfüllt hat, auf den Maximalwert des Formats gesetzt wird und jedes Pixel, das dies nicht tat, auf null gesetzt wird. Das Ergebnis ist die binäre Maske, die der Rest der Pipeline direkt verwenden kann.
In der einfachsten Form hat die Schwellenwertliste einen Bereich und der Aufruf gibt eine Maske der Pixel in diesem Bereich zurück:
img.binary([(120, 255)])
Die Listenform macht binary leistungsfähig. Eine Pipeline, die zwei farbige Markierungen verfolgen möchte, oder einen Helligkeitsbereich plus eine isolierte Sättigungsspitze, übergibt beide Bereiche in derselben Liste und erhält eine einzige Ausgabemaske, die alle Treffer abdeckt.
Die Schwellenwertbildung verwandelt ein Bild mit kontinuierlichen Werten in eine binäre Maske: jedes Pixel innerhalb des Schwellenwertbereichs wird zum Maximalwert des Formats, jedes Pixel außerhalb wird zu null.¶
5.12.2. Das Graustufen-Tupel¶
Für ein Graustufenbild ist jeder Eintrag in der Schwellenwertliste ein zweielementiges Tupel (lo, hi), das einen inklusiven Helligkeitsbereich beschreibt. Pixel mit Werten zwischen lo und hi (inklusive) passen; alles außerhalb dieses Bereichs nicht. Die natürlichen Muster sind unkompliziert:
(0, 60)passt zu dunklen Pixeln – alles von Schwarz bis hin zu tiefem Grau.(180, 255)passt zu hellen Pixeln – alles von hellem Grau bis hin zu Weiß.(100, 160)passt zu mittelgrauen Pixeln – ein Band in der Mitte des Helligkeitsbereichs.
Die Reihenfolge der beiden Werte innerhalb eines Tupels spielt keine Rolle; die Methode vertauscht sie intern, wenn lo größer als hi ist, sodass (60, 0) genauso funktioniert wie (0, 60).
5.12.3. Das LAB-Tupel für Farbe¶
Für ein RGB565-Bild ist jeder Eintrag ein sechselementiges Tupel (l_lo, l_hi, a_lo, a_hi, b_lo, b_hi), das einen inklusiven Bereich im LAB-Farbraum beschreibt, anstatt direkt in Rot, Grün und Blau. Die Schwellenwerte sind L (Helligkeit), A (chromatische Achse von Grün nach Rot) und B (chromatische Achse von Blau nach Gelb), jeweils verglichen mit dem Wert des Pixels in diesem Kanal.
Der Grund, den Umweg über LAB zu nehmen, anstatt RGB direkt mit Schwellenwerten zu bearbeiten, ist die Eigenschaft, um die herum der LAB-Farbraum entworfen wurde: LAB trennt die Helligkeit von der Chroma. Zwei Pixel, die dieselbe Farbe, aber bei unterschiedlichen Helligkeiten zeigen, landen bei unterschiedlichen L-Werten, aber bei ungefähr gleichen A- und B-Werten. Diese Trennung erlaubt es den Schwellenwertbereichen, eine Farbe durch ihre Position auf den A- und B-Achsen zu beschreiben und den L-Bereich weit offen zu lassen, um diese Farbe bei jeder Helligkeit von Schatten bis Glanzlicht zu akzeptieren. Ein RGB-basierter Schwellenwert kann das nicht – jede Änderung der Beleuchtung verschiebt alle drei R-, G-, B-Werte gleichzeitig, und ein auf RGB-Schwellenwerten aufgebauter Tracker bricht zusammen, sobald zum ersten Mal eine Wolke vor die Sonne zieht.
Das praktische Muster: wähle die A- und B-Bereiche, die die von der Anwendung verfolgte Farbe beschreiben, und lasse den L-Bereich weit – oft (0, 100), um jede Helligkeit zu akzeptieren – es sei denn, die Anwendung möchte gezielt sowohl nach Helligkeit als auch nach Farbe einen Schwellenwert anwenden.
Für Tupel mit weniger als sechs Werten nehmen die fehlenden Komponenten standardmäßig den maximalen Bereich an (keine Einschränkung für diese Achse). Ein zweielementiges Tupel (l_lo, l_hi) in einer RGB565-Schwellenwertliste wendet daher nur auf die Helligkeit einen Schwellenwert an und passt zu jeder Farbe.
Bemerkung
Ein wirklich weit offener L-Bereich hat am unteren Ende einen Haken. Wenn die Helligkeit gegen null fällt, konvergieren alle Farben gegen Schwarz, wobei die A- und B-Werte gegen null zusammenfallen und vom Rauschen dominiert werden – sodass dunkle Pixel in die A- und B-Bereiche driften und als die Zielfarbe verfolgt werden können. Wenn schwarze Bereiche der Szene als Treffer aufleuchten, erhöhe l_lo, bis sie herausfallen.
5.12.4. Flags¶
Drei Schlüsselwortargumente steuern die Ausgabe:
invert=Truekehrt das Ergebnis um. Jedes Pixel, das gepasst hätte, wird zu null, und jedes Pixel, das null gewesen wäre, wird zum Maximalwert. Nützlich, wenn die natürliche Art, den Vordergrund zu beschreiben, darin besteht, zu sagen, was er nicht ist.zero=Trueändert den Arbeitsmodus: passende Pixel werden auf null gesetzt und nicht passende Pixel behalten ihre ursprünglichen Werte. Verwende dies, wenn das Ziel darin besteht, die passenden Pixel aus dem Bild zu löschen, anstatt das Bild auf eine binäre Maske davon zu reduzieren.to_bitmap=Truegibt das Ergebnis alsBINARY-Bild zurück, anstatt das bestehende Format der Quelle zu überschreiben. Das Ergebnis mit einem Bit pro Pixel ist das, was spätere Maskenargumente direkt akzeptieren, und die Umwandlung spart oft den Speicherdruck, der entsteht, wenn eine Maske im vollen Format mitgeführt wird.
Maske und ROI folgen derselben Konvention wie der Rest der Oberfläche: ein roi-Rechteck beschränkt die Operation auf einen Teilbereich, ein mask-Bild beschränkt sie auf ein beliebiges Muster von Positionen.
5.12.5. Standardmäßig an Ort und Stelle¶
Wie die arithmetischen Operationen läuft binary standardmäßig an Ort und Stelle: die Pixel des Quellbildes werden mit der binären Ausgabe überschrieben, und die ursprünglichen Werte sind nach dem Aufruf verschwunden. Die Form to_bitmap=True ist die Alternative, wenn die Quelle erhalten bleiben muss und die Ausgabe ein frisch reserviertes BINARY-Bild sein soll. Die Form copy=True wird ebenfalls für ein Ergebnis im selben Format auf einem neuen Puffer akzeptiert.