5.28. QR-koder och AprilTags

Detektorerna hittills – blobbar, linjer, cirklar, rektanglar – hittar geometriska särdrag: positioner och konturer som ett efterföljande steg tolkar. De återstående detektorerna hittar symboliska särdrag: tryckta mönster vars visuella struktur finns specifikt för att koda en nyttolast. Kameran lokaliserar dem, avkodaren läser bitarna, och det som kommer tillbaka är inte en position utan en sträng (eller ett ID) som den som tryckte symbolen medvetet valde.

Två sådana familjer dominerar tillämpningar med små kameror. QR-koder bär godtycklig text, URL:er, kontaktkort eller binära nyttolaster – de konsumentinriktade 2D-koderna som dyker upp på affischer, förpackningar och boardingkort. AprilTags bär ett enda numeriskt ID från en liten fast uppsättning, avkodas snabbt även på långt avstånd, och rapporterar (när linsens inre parametrar tillhandahålls) en pose med 6 frihetsgrader i kamerans bildruta – de robotikinriktade 2D-koderna som markerar drönare, kalibreringsmål och fiducialer. Båda detektorerna returnerar resultatobjekt med samma vokabulär för begränsningsrutor som blob- och rektangeldetektorerna använder, men nyttolasten gör dem genuint annorlunda än något som hittills behandlats.

5.28.1. QR-koder

find_qrcodes() skannar bildrutan efter QR-koder och returnerar en lista med resultatobjekt av typen QRCode:

codes = img.find_qrcodes()

for c in codes:
    img.draw_rectangle(c.rect, color=(0, 255, 0))
    for corner in c.corners:
        img.draw_circle((corner[0], corner[1], 4),
                        color=(0, 255, 0))
    print(c.payload)

Detektorn tar ett enda valfritt roi för att begränsa sökningen. Den behöver gråskaleindata – en färgbildruta konverteras internt före avkodning.

Varje detektering bär begränsningsrutan (x, y, w, h, rect), de fyra detekterade hörnen (corners, den projektiva fyrhörningen som QR-kodens sökmönster ritar upp), och den avkodade nyttolasten som en sträng. Hörnen är det rätta att rita när man annoterar detekteringen – en QR-kod som ses snett är inte axelinriktad och begränsningsrutan ger bara en lös kontur.

Avkodarens metadata täcker allt QR-avkodaren lärde sig på vägen. version är QR-kodens version, 1 – 40, vilket bestämmer modulrutnätets storlek (en version-1-kod är 21 moduler bred, en version-40-kod är 177). ecc_level är felkorrigeringsnivån (0 – 3 för L / M / Q / H); högre nivåer reserverar fler kodord för felkorrigering och överlever mer skada till priset av mindre utrymme för nyttolast. mask är maskmönstret (0 – 7) som kodaren valde för att minimera förvirring hos avkodaren. data_type är kodningen som avkodaren rapporterade – numerisk, alfanumerisk, binär eller Kanji – och flaggorna is_numeric / is_alphanumeric / is_binary / is_kanji exponerar samma värde som mer lättanvända booleska värden.

eci är värdet för Extended Channel Interpretation, som identifierar vilken textkodning byten är i (UTF-8, ISO-8859-1, och så vidare). En QR-kod från godtyckligt tryckt material är inte garanterat UTF-8; en tillämpning som behöver avkoda byten korrekt kontrollerar eci och avkodar därefter. Särskilt Kanji-fallet: MicroPython tolkar inte Kanji-kodning, så en is_kanji-nyttolast måste behandlas som en byte-array och avkodas av tillämpningen.

Ett typiskt användningsfall: en kamera läser QR-koder från ett transportband och rapporterar den avkodade nyttolasten till en värd. Kameran kör find_qrcodes() en gång per bildruta, itererar över den returnerade listan, väljer de koder vars data_type matchar vad tillämpningen förväntar sig, och vidarebefordrar c.payload över UART eller USB. Data för begränsningsruta och hörn är användbara för förhandsvisningen i IDE:n men är inte vad värden bryr sig om.

5.28.2. AprilTags

find_apriltags() skannar bildrutan efter AprilTags och returnerar en lista med resultatobjekt av typen AprilTag:

tags = img.find_apriltags(families=image.TAG36H11)

for t in tags:
    img.draw_rectangle(t.rect, color=(0, 255, 0))
    img.draw_cross(t.cx, t.cy, color=(0, 255, 0))
    print(t.id, t.decision_margin)

AprilTags skiljer sig från QR-koder i sina designmål. En QR-kod är byggd för att koda godtycklig data i en enda tät symbol som användaren läser en gång på nära håll. En AprilTag är byggd för att koda ett litet ID i en gles symbol som kameran läser kontinuerligt på avstånd, med så mycket feltolerans som Hamming-koden i dess familj tillåter. Avvägningen visar sig i båda riktningarna: en QR-kod kan bära hundratals byte men måste läsas på nära håll; en AprilTag bär bara några hundra unika ID:n men läses tillförlitligt på flera meters avstånd.

Nyckelordet families tar en bitmask av de tagg-familjer som ska avkodas. De tillgängliga familjerna är image.TAG16H5, image.TAG25H9, image.TAG36H10, image.TAG36H11, image.TAGCIRCLE21H7, image.TAGCIRCLE49H12, image.TAGCUSTOM48H12, image.TAGSTANDARD41H12, och image.TAGSTANDARD52H13. Varje familj gör en avvägning mellan antalet ID:n och robusthet. H-numret i namnet är det minsta Hamming-avståndet mellan två koder i familjen – hur många bitar som måste vändas innan en giltig kod blir en annan – TAG16H5 har 30 ID:n på avstånd 5, TAG25H9 har 35 ID:n på avstånd 9, och TAG36H11 (standardvärdet och det vanligaste) har 587 ID:n på avstånd 11. Detektorn korrigerar upp till två bitfel oavsett familj, så avståndet avgör hur riskabel den korrigeringen är: ett slumpmässigt mönster i en brusig bildruta behöver bara hamna inom två bitar från en giltig kod för att avkodas som en falsk detektering, och familjerna med högre avstånd sprider sina koder så mycket glesare att sådana kollisioner blir sällsynta – anledningen till att TAG36H11 är det rekommenderade valet. Detekteringstiden skalar med antalet aktiverade familjer, så en tillämpning aktiverar bara det den faktiskt trycker. Bitmasken är den bitvisa OR av familjekonstanterna när flera familjer behövs i ett anrop.

Varje detektering bär vokabulären för begränsningsrutan – x, y, w, h, rect, area, heltals- och subpixel-centroider (cx, cy, cxf, cyf) – och de fyra detekterade hörnen (corners). Identifieringsfälten följer: id är det numeriska ID:t inom familjen (0 – 586 för TAG36H11), family är den numeriska familjekonstanten, och name är familjenamnet som en sträng.

Fälten för matchningskvalitet är vad en tillämpning använder för att filtrera detekteringar. decision_margin är ett konfidenspoäng från 0,0 – 1,0; högre är bättre, och att filtrera bort detekteringar under decision_margin > 0.1 rensar bort de flesta falska träffar utan kostnad. hamming räknar de bitfel som avkodaren accepterade för denna tagg – lägre är bättre, 0 betyder en perfekt avkodning. goodness är ett historiskt bildkvalitetsmått som den nuvarande avkodaren inte längre beräknar; det är alltid 0,0 och kan ignoreras.

5.28.3. Pose från inre parametrar

Den omvälvande egenskapen hos find_apriltags(), den som motiverar AprilTags som den föredragna robotikfiducialen, är att metoden kan återställa taggens pose med 6 frihetsgrader i kamerans bildruta direkt från de detekterade hörnen och en liten uppsättning kalibreringsparametrar. De inre parametrarna är kamerans fokallängder i X och Y i pixlar (fx, fy) och det optiska centrumet i pixlar (cx, cy), alla fyra mäter tillämpningen en gång med en kalibreringsprocedur och hårdkodar därefter.

När de inre parametrarna tillhandahålls fyller den returnerade AprilTag sina fält x_translation, y_translation, z_translation med taggens position relativt kameran, och x_rotation, y_rotation, z_rotation (och dubbletten rotation för symmetrins skull) med taggens orientering. Utan inre parametrar är alla sex fälten 0,0 och tillämpningen ansvarar för all poseskattning den behöver.

Translationsfälten rapporteras i taggbredder: avkodaren behandlar taggen som 1 enhet bred, så tillämpningen multiplicerar varje translation med den fysiska bredden på den tryckta taggen för att få metriska avstånd. En tagg tryckt 100 mm bred som rapporterar z_translation = 8.3 är 830 mm från kameran; samma tagg tryckt 50 mm bred på samma avstånd skulle rapportera z_translation = 16.6. Rotationsfälten är i radianer och behöver ingen skalning.

Poseskattningen är grunden för ett brett spektrum av robotiktillämpningar: att docka en robot till en laddningsstation märkt med en tagg, att följa en tryckt slinga av vägpunkter, att återställa kamerans egen pose från flera kända taggar i omgivningen. En kamera som känner till de inre parametrarna, ser en tagg, och har en verklig position för taggen har, genom samma aritmetik, en verklig position för sig själv.

5.28.4. När man väljer vilken

QR-koder och AprilTags löser olika problem. Valet mellan dem handlar om vad den tryckta symbolen bär.

När tillämpningen behöver bära godtycklig data genom den tryckta symbolen – en URL, en serienummersträng, en kontaktpost – är QR-koden det rätta valet. Hundratals byte ryms i en kod av blygsam storlek, kodningen är offentlig och stöds på varje smartphone, och avkodaren klarar rotation, måttlig skada och sneda vinklar.

När tillämpningen behöver ett litet ID läst kontinuerligt på avstånd med valfri pose – en fiducial på en rörlig robot, ett kalibreringsmål i ett rum, en dockningsmarkör på en laddningsstation – är AprilTag det rätta valet. Hundratals ID:n är gott och väl för användningsfallet, Hamming-koden återhämtar sig från bitfel som skulle besegra en QR-kod, och poseskattningen är gratis när de inre parametrarna väl är kalibrerade.

Vissa tillämpningar använder båda: en AprilTag markerar en känd plats och en tillhörande QR-kod (tryckt bredvid) bär metadatan om vad den platsen betyder. De två detektorerna körs oberoende på samma bildruta och tillämpningen korrelerar deras begränsningsrutor för att matcha varje tagg med sin kompanjonkod.