5.29. Coduri de bare și coduri Data Matrix

Încă două familii de coduri completează decodoarele camerei. Codurile de bare unidimensionale – dungile de pe partea laterală a unei cutii de cereale, o brățară de identificare de spital, o etichetă de expediere – sunt cele mai vechi simboluri citibile de mașini aflate încă în uz zilnic. Codurile Data Matrix sunt bidimensionale, ca și codurile QR, dar mai dense la aceeași dimensiune a încărcăturii utile și destinate marcajului industrial – marca producătorului gravată cu laser pe o placă de circuit, mai degrabă decât posterul de pe perete. Modulul image are un decodor dedicat pentru fiecare, acoperind aplicațiile industriale, de comerț și de inventar pe care codurile 2D destinate consumatorilor nu le-au atins niciodată cu adevărat.

5.29.1. Coduri de bare 1D

Un cod de bare unidimensional își codifică încărcătura utilă ca o secvență de bare verticale de lățimi variate, citită de la stânga la dreapta (sau de sus în jos pentru codurile orientate vertical). Lățimile se cuantizează la una dintr-un set mic de valori, iar secvența de lățimi formează caractere în orice simbologie a ales imprimanta: numerică pentru un cod de produs UPC, alfanumerică pentru un număr de piesă de depozit sau text arbitrar pentru o etichetă Code 128.

find_barcodes() scanează cadrul după coduri de bare 1D în oricare dintre simbologiile acceptate și returnează o listă de obiecte rezultat BarCode:

codes = img.find_barcodes()

for c in codes:
    img.draw_rectangle(c.rect, color=(0, 255, 0))
    print(c.payload, c.type, c.quality)

Decodorul scanează cadrul atât orizontal cât și vertical într-un singur apel, astfel încât un cod de bare imprimat la orice unghi este găsit într-o singură trecere fără ca aplicația să fie nevoită să rotească intrarea. roi restrânge căutarea; nu există alți parametri de reglaj – decodorul este de sine stătător.

Simbologiile acceptate acoperă familiile comune de consum și industriale. Setul de comerț este image.EAN2, image.EAN5, image.EAN8, image.UPCE, image.UPCA, image.EAN13 (codurile numerice de lungime fixă de pe majoritatea ambalajelor de consum), image.ISBN10 și image.ISBN13 (aceleași familii reutilizate pentru cărți). Setul de uz general este image.I25 (Interleaved 2 of 5, comun pe etichetele de expediere), image.CODABAR (folosit în biblioteci și bănci de sânge), image.CODE39, image.CODE93 și image.CODE128 (simbologii alfanumerice de lungime variabilă pentru text arbitrar). Familia de pe marginea raftului image.DATABAR (RSS-14) și image.DATABAR_EXP (RSS-Expanded) completează lista.

Fiecare detectare poartă vocabularul casetei de încadrare – x, y, w, h, rect, corners – și payload-ul decodat sub formă de șir de caractere. type este constanta de simbologie din lista de mai sus, pe care o aplicație o verifică atunci când îi pasă în mod specific de familia care a fost decodată (de exemplu, acceptând doar EAN13 pentru o aplicație de scanner de magazin alimentar).

Cele două câmpuri care contează pentru filtrare sunt rotation și quality. rotation este unghiul codului de bare în planul imaginii, în radiani: decodorul face față rotațiilor arbitrare, dar codul din aval care dorește să afișeze detectarea în mod curat ar putea dori să filtreze codurile care revin înclinate peste un anumit prag.

quality este numărul de decodări: numărul de linii de scanare care au decodat cu succes aceeași încărcătură utilă. Decodorul rulează peste fiecare rând (și coloană) al cadrului care intersectează codul de bare și incrementează contorul de fiecare dată când decodarea reușește. Un cod de bare imprimat, cu focalizare clară și iluminare bună, produce o quality de ordinul zecilor; un cod de bare parțial ocluzat sau pătat ar putea decoda pe doar una sau două linii de scanare și raporta o quality de 1 – 2. Filtrarea detectărilor sub quality > 5 elimină decodările eronate tranzitorii de o singură linie de scanare fără niciun cost pentru detectările autentice.

O aplicație de coduri de bare 1D este mică. Captează un cadru, apelează find_barcodes(), iterează lista returnată, filtrează după c.type și c.quality și transmite c.payload prin UART sau USB către orice etapă din aval care înregistrează sau totalizează scanarea.

5.29.2. Data Matrix

Un cod Data Matrix este un simbol 2D care își codifică încărcătura utilă ca o grilă de celule albe și negre, la fel cum face un cod QR. Diferă de un cod QR în două aspecte practice: este mai mic la aceeași dimensiune a încărcăturii utile (codificarea este mai densă) și este destinat utilizării industriale mai degrabă decât celei de consum (unde domină codurile QR). Modelele gravate cu laser în piese metalice pe podeaua unei fabrici, etichetele imprimate pe pachetele de circuite integrate, marcajele plasate pe seringile medicale – toate acestea sunt de obicei coduri Data Matrix, nu coduri QR.

find_datamatrices() scanează cadrul după coduri Data Matrix și returnează o listă de obiecte rezultat DataMatrix:

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 restrânge căutarea în modul obișnuit. Singurul buton de reglaj specific decodorului este effort, un întreg care controlează cât de intens lucrează decodorul pentru a găsi o potrivire. Valorile mai mari îmbunătățesc detectarea codurilor estompate, deteriorate sau oblice cu prețul ratei de cadre; valorile mai mici rulează mai rapid, dar pot rata coduri pe care efortul mai mare le-ar fi găsit. Valorile sub aproximativ 160 efectiv nu reușesc detectarea; valorile peste aproximativ 240 oferă randamente în scădere. Valoarea implicită de 200 este un echilibru rezonabil pentru o imagine clară, iar punctul de plecare potrivit pentru o aplicație nouă este valoarea implicită plus sau minus 20, în funcție de faptul dacă țintele sunt curate (mai mic) sau deteriorate (mai mare).

Fiecare detectare poartă vocabularul casetei de încadrare și cele patru colțuri detectate, payload-ul decodat și rotation-ul în planul imaginii, în radiani. Metadatele de aranjament descriu dimensiunea și densitatea simbolului pe care l-a citit decodorul: rows și columns sunt numărul de celule al grilei de date; capacity este numărul maxim de caractere de încărcătură utilă pe care le-ar putea purta simbolul la acea dimensiune; padding este câte dintre acele poziții au rămas neutilizate (capacity - len(payload)).

Câmpurile de aranjament sunt utile pentru aplicațiile care trebuie să valideze formatul unui marcaj gravat, mai degrabă decât conținutul acestuia. Un sistem de urmărire a pieselor ar putea cere ca toate marcajele să fie coduri de 12 pe 12 cu cel mult două caractere de padding; o detectare care a revenit la 8 pe 8 (un simbol mai mic decât prevede specificația) sau cu 10 caractere de padding (în mare parte gol) este semnalată pentru re-marcare.

5.29.3. Când să alegi care

Acolo unde QR versus AprilTag se reducea la tipul de încărcătură utilă (date arbitrare versus ID mic), codurile de bare versus codurile Data Matrix se reduc la densitatea fizică și industrie.

Când aplicația este orientată spre consumator, iar codurile există deja pe teren – alimente, cărți, etichete de expediere, cărți de bibliotecă – detectorul potrivit este find_barcodes(). Codurile pe care le citește aplicația au fost imprimate pentru a fi citite de un alt sistem, iar simbologiile de comerț standardizate sunt ceea ce se aștepta acel sistem.

Când aplicația este industrială, iar codurile sunt imprimate pentru aplicație – urmărirea inventarului pe podeaua unei fabrici, coduri de lot gravate pe piese, marcaje de trasabilitate pe dispozitive medicale – detectorul potrivit este find_datamatrices() sau find_qrcodes(), în funcție de faptul dacă aplicația are nevoie de densitatea mai mare a Data Matrix sau de suportul de instrumente mai larg al QR.

O mână de aplicații amestecă toate cele patru detectoare într-un singur flux. O cameră de inspecție a coletelor ar putea rula o trecere find_barcodes() pentru UPC-ul imprimat, o trecere find_qrcodes() pentru un cod QR de expediere de pe aceeași cutie și o trecere find_datamatrices() pentru un cod de piesă gravat, toate pe același cadru capturat; cele trei liste de rezultate sunt corelate prin poziția casetei de încadrare și raportate ca o singură înregistrare de detectare. Costul fiecărui detector se adună, așa că aplicațiile care fac asta restrâng de obicei fiecare trecere cu un roi adecvat, în loc să caute în întregul cadru pentru fiecare tip de cod.