QR Codes und Datamatrix

Bald kommen QR-Codes, die uns einen Impfstatus oder eine Testung bestätigen sollen.

Das ist doch der perfekte Zeitpunkt um diese beiden Bild-Kodierungen ins GATE Projekt aufzunehmen und mit ihnen zu experimentieren.


Neben den alt bekannten Artikel-Barcodes (Strichcodes), sind mir folgende optischen Datencodes in der Öffentlichkeit bekannt:

  • QR-Codes sind diese Punkte-Quadrate, die an 3 Ecken ein umrandetes Quadrat beinhalten.
    Sie sind auf Plakaten und überall dort vertreten, wo man sie mit dem Smartphone abscannen kann und beinhalten häufig URLs für weitere Infos zu einem Produkt.
  • Data-Matrix-Codes sind wie QR-Codes quadratisch und zeichnen sich durch durchgehende Linien an zwei Achsen an den Rändern aus.
    Sie sind als Bar-Code Ersatz gedacht und man findet sie (etwas versteckt) auf Geräten, wo sie häufig Seriennummern oder Adressen kodieren.

Beide Techniken können allerlei mögliche Formen von Bytes kodieren, auch Binärdaten. Und mit folgenden hilfreichen Bibliotheken kann man aus Pixel-Rastergrafiken (z.B. Bitmaps) Codes erkennen lassen:

libdmtx

Mit Data-Matrix-Codes (auch als 2D-Barcodes bekannt), habe ich schon vor ein paar Jahren “experimentiert”. Die Bibliothek libdmtx soll mir daher auch diesmal einen guten Dienst leisten, wenn es um das Auslesen von Datamatrix Codes in Bildern geht.

Die Bibliothek ist für den Anwender recht einfach gestrickt und kann mit jedem möglichen Rasterbild-Format (RGB, RGBA, usw.) gefüttert werden.

  • DmtxImage* dmtx_image = dmtx_image = dmtxImageCreate(pixelptr, width, height, DmtxPack32bppRGBX);
    Erzeugt ein Bildobjekt basierend auf den Eingabedaten, wobei es ein paar Optionen für Formate gibt.
  • DmtxDecode* decoder = dmtxDecodeCreate(dmtx_image, 1);
    Dann wird die Dekodierung für das Bild eingeleitet.
  • DmtxRegion* region = dmtxRegionFindNext(decoder, NULL);
    Nun sucht man eine gefundene Datamatrix-Region.
  • DmtxMessage* message = dmtxDecodeMatrixRegion(decoder, region, DmtxUndefined);
    Und dann liest man die Nachricht aus der Region heraus.
  • message->output, message->outputSize
    Auf die dekodierten Daten zeigt dann der output Pointer und die Größe. steht in outputSize
  • dmtxMessageDestroy(&message);
    Freigeben des Message Objektes.
  • dmtxRegionDestroy(&region);
    Freigeben des Region Objektes.
  • dmtxDecodeDestroy(&decoder);
    Freigeben des Dekoders.
  • dmtxImageDestroy(&dmtx_image);
    Freigeben der Bilddaten.

Viel einfacher geht es ja kaum und libdmtx kann auch verdrehte Bilder so lange herumtransformieren, bis eine Matrix entdeckt wurde. Man kann auch ein Timeout angeben um zu lange Suchoperationen dann abbrechen zu lassen.

libquirc

Mit der quirc Lib haben wir eine C Bibliothek mit BSD Lizenz, die QR Codes dekodieren kann und keine zusätzlichen Abhängigkeiten hat.

Bilddaten muss man für quirc als Graustufen-Bytes übergeben.

  • struct quirc* qr = quirc_new();
    Eine neue Dekoder-Sitzung wird gestartet.
  • quirc_resize(qr, width, height);
    Die Dimensionen des zu ladenden Bildes werden übergeben.
  • gray_image = quirc_begin(qr, &width, &height);
    Wir erhalten einen Pointer auf die internen Bild-Pixel.
  • for(pixel : pixels) gray_image[offset] = gray(pixel);
    Nun müssen alle Bild-Pixel befüllt werden.
  • quirc_end(qr);
    Das Aufnehmen der Bilddaten ist fertig und die Dekodierung startet.
  • int num_codes = quirc_count(qr);
    Die Anzahl der gefundenen QR-Codes wird abgefragt.
  • for(int index = 0; index < num_codes; index++)
    Wir gehen nun durch alle gefundenen QR-Bereiche durch:
    • struct quirc_code code;
    • quirc_extract(qr, index, &code);
      Es wird versucht einen QR-Code zu extrahieren.
    • struct quirc_data data;
    • quirc_decode(&code, &data);
      Die extrahierten Daten werden in Bytes dekodiert.
    • data.payload, data.payload_len
      Und durch einen Pointer zu den Daten und die Anzahl der Bytes kann der QR-Code Inhalt weiterverarbeitet werden
  • quirc_destroy(qr);
    Am Ende wird die quirc-Sitzung beendet und alle Ressourcen werden freigegeben.

Auch hier ist das Ergebnis mit nur wenigen Zeilen Code zu erhalten. Und es sind nur ein paar if Statements erforderlich um nicht-erkennbare Codes zu überspringen.

Fazit

Also ich bin echt beeindruckt.

Die Komplexität der Bildverarbeitung ist in einer Hand voll von Funktionen abgebildet, die nahezu selbstbeschreibend sind.

Mein Respekt geht an die Macher und ich habe die beiden Bibliotheken mit Freude ins GATE Projekt aufgenommen.

Nun kann ich in Verbindung mit meinen Video-Source-Routinen Bilder auf Webcams und anderen Kameras auf QR- und Datamatrix-Codes durchsuchen lassen. Und das klappt wirklich gut.

Das schwierigste ist meist, die Schärfeeinstellung der Webcams so hinzubekommen, dass ein gut lesbares Bild dabei herauskommt.

Daumen hoch für diese geniale Codebase.