5.30. Template Matching¶
Die bisher behandelten Detektoren beantworten Fragen zum Inhalt eines einzelnen Einzelbildes: wo sich die Blobs befinden, wohin die Linien verlaufen, was ein gedruckter Code aussagt. Eine andere Klasse von Fragen vergleicht ein Bild mit einem anderen. Sieht dieser Bereich des aufgenommenen Einzelbildes so aus wie der Referenz-Patch, den ich zur Kalibrierungszeit gespeichert habe? Die Matching-Methoden beantworten diese Frage.
Die tonale und statistische Analyse führte get_similarity() für die verwandte Frage ein – wie ähnlich sind sich diese beiden gleich großen Bilder insgesamt? – mit SSIM als zugrunde liegender Metrik. Die verbleibende Matching-Frage ist die der Lokalisierung: nicht „wie ähnlich sind sich diese beiden Bilder“, sondern „wo innerhalb dieses größeren Bildes erscheint jener kleinere Patch?“ Das richtige Werkzeug für die Lokalisierungsfrage ist das Template Matching.
5.30.1. Der grundlegende Aufruf¶
find_template() sucht die erste Stelle, an der ein kleines Template-Bild innerhalb des aufgenommenen Einzelbildes erscheint. Die Implementierung verwendet normalisierte Kreuzkorrelation (NCC): Das Template wird über das Einzelbild geschoben, der Übereinstimmungswert pro Position wird aus der Korrelation zwischen den Template-Pixeln und den darunterliegenden Pixeln des Einzelbildes berechnet (normalisiert gegen die lokalen Mittelwerte und Varianzen, sodass Änderungen der Verstärkung den Abgleich nicht täuschen), und die erste Position, deren Wert threshold überschreitet, wird als Begrenzungsrahmen zurückgegeben:
template = image.Image("/sdcard/template.bmp", copy_to_fb=False)
template.to_grayscale()
match = img.find_template(template, threshold=0.7,
search=image.SEARCH_DS)
if match is not None:
img.draw_rectangle(match, color=(255, 0, 0))
Die Methode funktioniert nur mit Graustufenbildern. Nehmen Sie in Graustufen auf (die natürliche Wahl für jede Kamera ohne Farbsensor), oder konvertieren Sie vor dem Aufruf mit to_grayscale() an Ort und Stelle. Dasselbe gilt für das von der Festplatte geladene Template: Ein Farb-Template wird mit derselben Methode konvertiert, und das Ergebnis ist das, was der Matcher erwartet.
threshold ist ein Float von 0.0 bis 1.0. Ein Wert von 1.0 verlangt eine perfekte Pixel-für-Pixel-Übereinstimmung (die bei echten aufgenommenen Bildern nie vorkommt), 0.0 akzeptiert alles, und Werte zwischen 0.6 und 0.8 decken den häufigen Fall ab, in dem das Template unter ähnlicher Beleuchtung aufgenommen wurde und sich die Szene nicht dramatisch verändert hat. Erhöhen Sie den Schwellenwert, um Fehlalarme zu unterdrücken; senken Sie ihn, um verrauschtere Übereinstimmungen zu akzeptieren, auf Kosten von mehr falschen Treffern.
5.30.2. Suchstrategie¶
search wählt zwischen zwei Strategien. image.SEARCH_EX ist die erschöpfende Suche: Das Template wird durch jede step-Pixel-Position im Einzelbild geschoben und gibt den ersten Treffer über dem Schwellenwert zurück. image.SEARCH_DS ist die Diamantsuche: Der Matcher tastet zunächst grob ab und verfeinert dann um den besten Wert herum, was dramatisch schneller ist, aber eine echte Übereinstimmung verpassen kann, wenn der grobe Durchlauf zufällig in der Nähe eines lokalen Maximums landet, das das globale übertrifft. Für eine Echtzeit-Pipeline, in der das Template gut definiert und unwahrscheinlich zu verwechseln ist, ist SEARCH_DS der richtige Standard; für eine einmalige Kalibrierung, bei der die Kosten eines Fehlschlags höher sind als die Kosten eines langsameren Scans, ist SEARCH_EX sicherer.
step steuert das Überspringen von Pixeln während des erschöpfenden Durchlaufs (die Diamantsuche verwaltet ihren eigenen Schritt). Größere step-Werte beschleunigen den Scan auf Kosten der Subpixel-Genauigkeit. roi beschränkt die Suche auf einen Bereich des Einzelbildes, was sowohl eingrenzt, was der Matcher berücksichtigt, als auch den Aufwand reduziert.
Der zurückgegebene Wert ist ein (x, y, w, h)-Begrenzungsrahmen-Tupel, das die beste Übereinstimmung identifiziert, oder None, falls keine Position den Schwellenwert überschritten hat. Der Begrenzungsrahmen lässt sich direkt in draw_rectangle() oder crop() für die nächste Verarbeitungsstufe einsetzen.
5.30.3. Die Skalierungs- und Rotationsfalle¶
Die klassische Fallgrube beim Template Matching ist die Empfindlichkeit gegenüber Skalierung und Rotation. Der Matcher vergleicht das Template Pixel für Pixel mit dem Einzelbild; ein in einer Entfernung aufgenommenes Template passt nicht zu demselben Objekt, das in einer anderen Entfernung aufgenommen wurde, und ein frontal aufgenommenes Template passt nicht zu demselben Objekt, das aus einem anderen Winkel betrachtet wird. Der Wert fällt unbemerkt unter das Übereinstimmungsniveau, selbst wenn das Objekt für ein menschliches Auge deutlich sichtbar ist, und die Methode gibt None zurück.
Für die einfachen Fälle gibt es einige Behelfslösungen. Die Anwendung kann mehrere Templates in verschiedenen Maßstäben aufnehmen und find_template() für jedes nacheinander ausführen, wobei das erste akzeptiert wird, das den Schwellenwert überschreitet; der Aufwand skaliert mit der Anzahl der Templates. Die Anwendung kann das Einzelbild mit rotation_corr() oder der Polartransformation (Geometrische Transformationen) vorverarbeiten, um die störende Rotation vor dem Abgleich zu entfernen; das gefundene Template muss dann immer noch zur korrigierten Geometrie passen.
Ein nützliches Idiom für QA-Inspektions-Pipelines kombiniert den Template-Matcher mit dem Ähnlichkeitsbewerter, den die tonale und statistische Analyse einführte: find_template() lokalisiert das Teil im aufgenommenen Einzelbild, und der zurückgegebene Begrenzungsrahmen wird ausgeschnitten und mittels get_similarity() gegen den Referenz-Patch übergeben. Der Template-Matching-Schritt entscheidet, wo sich das Teil befindet; der Ähnlichkeitsbewertungs-Schritt entscheidet, ob das Teil akzeptabel ist. Die beiden Schritte laufen bei jedem Einzelbild, der Schwellenwert auf mean ist das Bestanden/Durchgefallen-Tor, und der in das Einzelbild zurückgezeichnete gefundene Begrenzungsrahmen ist die IDE-Vorschau, die der Bediener beobachtet.