5.29. Barcodes und Data-Matrix-Codes¶
Zwei weitere Code-Familien runden die Decoder der Kamera ab. Eindimensionale Barcodes – die Streifen an der Seite einer Müslischachtel, ein Krankenhaus-Armband, ein Versandetikett – sind die ältesten maschinenlesbaren Symbole, die noch täglich im Einsatz sind. Data-Matrix-Codes sind wie QR-Codes zweidimensional, aber bei gleicher Nutzdatengröße dichter und auf industrielle Kennzeichnung ausgerichtet – die Herstellermarkierung, die per Laser in eine Leiterplatte geätzt wird, statt des Posters an der Wand. Das image-Modul verfügt für jeden einen eigenen Decoder, der die industriellen, Einzelhandels- und Inventaranwendungen abdeckt, die die 2D-Codes für Verbraucher nie ganz erreicht haben.
5.29.1. 1D-Barcodes¶
Ein eindimensionaler Barcode kodiert seine Nutzdaten als eine Folge vertikaler Balken unterschiedlicher Breite, die von links nach rechts gelesen werden (oder von oben nach unten bei vertikal ausgerichteten Codes). Die Breiten werden auf einen kleinen Satz von Werten quantisiert, und die Folge der Breiten ergibt Zeichen in der jeweiligen Symbologie, die der Drucker gewählt hat: numerisch für einen UPC-Produktcode, alphanumerisch für eine Lager-Teilenummer oder beliebiger Text für ein Code-128-Etikett.
find_barcodes() durchsucht das Einzelbild nach 1D-Barcodes in jeder der unterstützten Symbologien und gibt eine Liste von BarCode-Ergebnisobjekten zurück:
codes = img.find_barcodes()
for c in codes:
img.draw_rectangle(c.rect, color=(0, 255, 0))
print(c.payload, c.type, c.quality)
Der Decoder durchsucht das Einzelbild in einem einzigen Aufruf sowohl horizontal als auch vertikal, sodass ein in einem beliebigen Winkel gedruckter Barcode in einem Durchlauf gefunden wird, ohne dass die Anwendung die Eingabe drehen muss. roi schränkt die Suche ein; weitere Einstellungsparameter gibt es nicht – der Decoder ist in sich abgeschlossen.
Die unterstützten Symbologien decken die gängigen Verbraucher- und Industriefamilien ab. Der Einzelhandelssatz umfasst image.EAN2, image.EAN5, image.EAN8, image.UPCE, image.UPCA, image.EAN13 (die numerischen Codes fester Länge auf den meisten Verbraucherverpackungen), image.ISBN10 und image.ISBN13 (dieselben Familien für Bücher umgewidmet). Der Allzwecksatz umfasst image.I25 (Interleaved 2 of 5, häufig auf Versandetiketten), image.CODABAR (verwendet in Bibliotheken und Blutbanken), image.CODE39, image.CODE93 und image.CODE128 (alphanumerische Symbologien variabler Länge für beliebigen Text). Die Regalkanten-Familie image.DATABAR (RSS-14) und image.DATABAR_EXP (RSS-Expanded) vervollständigt die Liste.
Jede Erkennung trägt das Begrenzungsrahmen-Vokabular – x, y, w, h, rect, corners – und die dekodierten payload als Zeichenkette. type ist die Symbologiekonstante aus der obigen Liste, die eine Anwendung prüft, wenn ihr speziell wichtig ist, welche Familie dekodiert wurde (z. B. nur EAN13 für eine Lebensmittelscanner-Anwendung zu akzeptieren).
Die beiden für die Filterung wichtigen Felder sind rotation und quality. rotation ist der Winkel des Barcodes in der Bildebene im Bogenmaß: Der Decoder kommt mit beliebigen Drehungen zurecht, aber nachgelagerter Code, der die Erkennung sauber anzeigen möchte, möchte möglicherweise Codes herausfiltern, die über einen bestimmten Schwellenwert hinaus geneigt zurückkommen.
quality ist die Dekodierungsanzahl: die Anzahl der Scanlinien, die dieselben Nutzdaten erfolgreich dekodiert haben. Der Decoder läuft über jede Zeile (und Spalte) des Einzelbilds, die den Barcode schneidet, und erhöht den Zähler bei jeder erfolgreichen Dekodierung. Ein gedruckter Barcode bei scharfer Fokussierung und guter Beleuchtung liefert eine quality im Bereich von mehreren Dutzend; ein teilweise verdeckter oder verschmierter Barcode wird möglicherweise nur auf ein oder zwei Scanlinien dekodiert und meldet eine quality von 1 bis 2. Das Herausfiltern von Erkennungen unterhalb von quality > 5 verwirft vorübergehende Fehldekodierungen einzelner Scanlinien, ohne die echten Erkennungen zu beeinträchtigen.
Eine 1D-Barcode-Anwendung ist klein. Nehmen Sie ein Einzelbild auf, rufen Sie find_barcodes() auf, iterieren Sie über die zurückgegebene Liste, filtern Sie nach c.type und c.quality und leiten Sie c.payload über UART oder USB an die nachgelagerte Stufe weiter, die den Scan protokolliert oder abkassiert.
5.29.2. Data Matrix¶
Ein Data-Matrix-Code ist ein 2D-Symbol, das seine Nutzdaten als Raster aus schwarzen und weißen Zellen kodiert, so wie es ein QR-Code tut. Er unterscheidet sich in zweierlei praktischer Hinsicht von einem QR-Code: Er ist bei gleicher Nutzdatengröße kleiner (die Kodierung ist dichter) und er ist auf den industriellen Einsatz statt auf den Verbrauchereinsatz (wo QR-Codes dominieren) ausgerichtet. Die in Metallteile auf einem Fabrikboden lasergeätzten Muster, die auf Gehäuse integrierter Schaltkreise gedruckten Etiketten, die auf medizinischen Spritzen angebrachten Markierungen – all das sind typischerweise Data Matrices, keine QR-Codes.
find_datamatrices() durchsucht das Einzelbild nach Data-Matrix-Codes und gibt eine Liste von DataMatrix-Ergebnisobjekten zurück:
codes = img.find_datamatrices()
for c in codes:
img.draw_rectangle(c.rect, color=(0, 255, 0))
print(c.payload, c.rows, c.columns)
roi schränkt die Suche auf die übliche Weise ein. Der eine decoderspezifische Einstellungsregler ist effort, eine Ganzzahl, die steuert, wie hart der Decoder arbeitet, um eine Übereinstimmung zu finden. Höhere Werte verbessern die Erkennung schwacher, beschädigter oder schräger Codes auf Kosten der Bildrate; niedrigere Werte laufen schneller, übersehen aber möglicherweise Codes, die der höhere Aufwand gefunden hätte. Werte unter etwa 160 erkennen praktisch nichts; Werte über etwa 240 bringen abnehmenden Nutzen. Der Standardwert von 200 ist ein vernünftiger Kompromiss für ein klares Bild, und der richtige Ausgangspunkt für eine neue Anwendung ist der Standardwert plus oder minus 20, je nachdem, ob die Ziele sauber (niedriger) oder beschädigt (höher) sind.
Jede Erkennung trägt das Begrenzungsrahmen-Vokabular und die vier erkannten Ecken, die dekodierten payload und die rotation in der Bildebene im Bogenmaß. Die Layout-Metadaten beschreiben die Größe und Dichte des vom Decoder gelesenen Symbols: rows und columns sind die Zellenzahlen des Datenrasters; capacity ist die maximale Anzahl von Nutzdatenzeichen, die das Symbol bei dieser Größe tragen könnte; padding gibt an, wie viele dieser Plätze ungenutzt blieben (capacity - len(payload)).
Die Layout-Felder sind nützlich für Anwendungen, die das Format einer geätzten Markierung statt ihres Inhalts validieren müssen. Ein Teile-Tracking-System könnte verlangen, dass alle Markierungen 12-mal-12-Codes mit höchstens zwei Padding-Zeichen sind; eine Erkennung, die mit 8-mal-8 (ein kleineres Symbol, als die Spezifikation vorschreibt) oder mit 10 Padding-Zeichen (überwiegend leer) zurückkam, wird zur Neukennzeichnung markiert.
5.29.3. Wann was wählen¶
Während es bei QR gegenüber AprilTag auf die Art der Nutzdaten ankam (beliebige Daten gegenüber kleiner ID), kommt es bei Barcodes gegenüber Data-Matrix-Codes auf die physische Dichte und die Branche an.
Wenn die Anwendung verbraucherorientiert ist und die Codes bereits im Feld existieren – Lebensmittel, Bücher, Versandetiketten, Bibliotheksbücher – ist der richtige Detektor find_barcodes(). Die Codes, die die Anwendung liest, wurden für ein anderes System zum Lesen gedruckt, und die standardisierten Einzelhandels-Symbologien sind das, was dieses System erwartete.
Wenn die Anwendung industriell ist und die Codes für die Anwendung gedruckt werden – Inventarverfolgung auf einem Fabrikboden, in Teile geätzte Chargencodes, Rückverfolgbarkeitsmarkierungen auf Medizinprodukten – ist der richtige Detektor find_datamatrices() oder find_qrcodes(), je nachdem, ob die Anwendung die höhere Dichte von Data Matrix oder die breitere Werkzeugunterstützung von QR benötigt.
Eine Handvoll Anwendungen kombiniert alle vier Detektoren in einer Pipeline. Eine Paketinspektions-Kamera könnte einen find_barcodes()-Durchlauf für den gedruckten UPC, einen find_qrcodes()-Durchlauf für einen Versand-QR-Code auf derselben Schachtel und einen find_datamatrices()-Durchlauf für einen geätzten Teilecode ausführen, alles auf demselben aufgenommenen Einzelbild; die drei Ergebnislisten werden anhand der Begrenzungsrahmenposition korreliert und als einzelner Erkennungsdatensatz gemeldet. Die Kosten jedes Detektors addieren sich, sodass Anwendungen, die dies tun, typischerweise jeden Durchlauf mit einem passenden roi eingrenzen, statt das gesamte Einzelbild nach jeder Code-Art zu durchsuchen.