5.28. QR-codes en AprilTags¶
De detectoren tot nu toe – blobs, lijnen, cirkels, rechthoeken – vinden geometrische kenmerken: posities en omtrekken die een vervolgstap interpreteert. De overige detectoren vinden symbolische kenmerken: gedrukte patronen waarvan de visuele structuur specifiek bestaat om een payload te coderen. De camera lokaliseert ze, de decoder leest de bits, en wat terugkomt is geen positie maar een string (of een ID) die degene die het symbool drukte bewust koos.
Twee van zulke families domineren toepassingen met kleine camera’s. QR-codes dragen willekeurige tekst, URL’s, contactkaarten of binaire payloads – de consumentgerichte 2D-codes die op posters, verpakkingen en instapkaarten verschijnen. AprilTags dragen een enkele numerieke ID uit een kleine vaste verzameling, decoderen snel zelfs van grote afstand, en (wanneer de lensintrinsieken worden meegegeven) rapporteren een 6-DoF pose in het cameraframe – de roboticagerichte 2D-codes die drones, kalibratiedoelen en fiducials markeren. Beide detectoren geven resultaatobjecten terug met dezelfde begrenzingsvak-woordenschat die de blob- en rect-detectoren gebruiken, maar de payload maakt ze werkelijk anders dan alles wat tot nu toe is behandeld.
5.28.1. QR-codes¶
find_qrcodes() scant het frame op QR-codes en geeft een lijst van QRCode-resultaatobjecten terug:
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)
De detector neemt een enkele optionele roi om de zoekopdracht te beperken. Hij heeft grijswaarden-invoer nodig – een kleurframe wordt intern geconverteerd voordat het wordt gedecodeerd.
Elke detectie draagt het begrenzingsvak (x, y, w, h, rect), de vier gedetecteerde hoeken (corners, de projectieve vierhoek die de zoekpatronen van de QR-code beschrijven) en de gedecodeerde payload als een string. De hoeken zijn het juiste om te tekenen bij het annoteren van de detectie – een QR-code die schuin wordt bekeken is niet asgericht en het begrenzingsvak geeft slechts een losse omtrek.
De decoder-metadata dekt alles wat de QR-decoder onderweg heeft geleerd. version is de QR-codeversie, 1 – 40, die de modulerastergrootte bepaalt (een versie-1-code is 21 modules breed, een versie-40-code is 177). ecc_level is het foutcorrectieniveau (0 – 3 voor L / M / Q / H); hogere niveaus reserveren meer codewoorden voor foutcorrectie en overleven meer schade ten koste van minder payloadruimte. mask is het maskerpatroon (0 – 7) dat de encoder koos om decoderverwarring te minimaliseren. data_type is de codering die de decoder rapporteerde – numeriek, alfanumeriek, binair of Kanji – en de vlaggen is_numeric / is_alphanumeric / is_binary / is_kanji stellen dezelfde waarde bloot als vriendelijkere booleans.
eci is de Extended Channel Interpretation-waarde, die de tekstcodering identificeert waarin de bytes staan (UTF-8, ISO-8859-1, enzovoort). Een QR-code van willekeurig gedrukt materiaal is mogelijk niet gegarandeerd UTF-8; een toepassing die de bytes correct moet decoderen controleert eci en decodeert dienovereenkomstig. In het bijzonder het Kanji-geval: MicroPython parseert geen Kanji-codering, dus een is_kanji-payload moet worden behandeld als een byte-array en door de toepassing worden gedecodeerd.
Een typisch gebruik: een camera leest QR-codes van een transportband en rapporteert de gedecodeerde payload aan een host. De cam draait find_qrcodes() eenmaal per frame, doorloopt de teruggegeven lijst, kiest de codes waarvan het data_type overeenkomt met wat de toepassing verwacht, en stuurt c.payload door via UART of USB. De begrenzingsvak- en hoekgegevens zijn nuttig voor de IDE-preview maar zijn niet waar de host om geeft.
5.28.2. AprilTags¶
find_apriltags() scant het frame op AprilTags en geeft een lijst van AprilTag-resultaatobjecten terug:
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 verschillen van QR-codes in hun ontwerpdoelen. Een QR-code is gebouwd om willekeurige gegevens te coderen in een enkel dicht symbool dat de gebruiker eenmaal van dichtbij leest. Een AprilTag is gebouwd om een kleine ID te coderen in een schaars symbool dat de camera continu van een afstand leest, met zoveel fouttolerantie als de Hamming-code van zijn familie toestaat. De afweging komt in beide richtingen tot uiting: een QR-code kan honderden bytes dragen maar moet van dichtbij worden gelezen; een AprilTag draagt slechts een paar honderd unieke ID’s maar leest betrouwbaar vanaf meters afstand.
Het sleutelwoord families neemt een bitmasker van de tagfamilies om te decoderen. De beschikbare families zijn image.TAG16H5, image.TAG25H9, image.TAG36H10, image.TAG36H11, image.TAGCIRCLE21H7, image.TAGCIRCLE49H12, image.TAGCUSTOM48H12, image.TAGSTANDARD41H12 en image.TAGSTANDARD52H13. Elke familie weegt het aantal ID’s af tegen robuustheid. Het H-getal in de naam is de minimale Hamming-afstand tussen twee codes in de familie – hoeveel bits moeten omkeren voordat één geldige code in een andere verandert – TAG16H5 heeft 30 ID’s op afstand 5, TAG25H9 heeft 35 ID’s op afstand 9, en TAG36H11 (de standaard en de meest voorkomende) heeft 587 ID’s op afstand 11. De detector corrigeert tot twee bitfouten ongeacht de familie, dus de afstand bepaalt hoe riskant die correctie is: een willekeurig patroon in een ruisrijk frame hoeft alleen binnen twee bits van een geldige code te landen om als een valse detectie te decoderen, en de families met grotere afstand spreiden hun codes zoveel schaarser dat zulke botsingen zeldzaam worden – de reden waarom TAG36H11 de aanbevolen keuze is. De detectietijd schaalt met het aantal ingeschakelde families, dus een toepassing schakelt alleen in wat ze daadwerkelijk afdrukt. Het bitmasker is de bitsgewijze OR van de familieconstanten wanneer meerdere families in één aanroep nodig zijn.
Elke detectie draagt de begrenzingsvak-woordenschat – x, y, w, h, rect, area, gehele en sub-pixel-zwaartepunten (cx, cy, cxf, cyf) – en de vier gedetecteerde hoeken (corners). De identificatievelden volgen: id is de numerieke ID binnen de familie (0 – 586 voor TAG36H11), family is de numerieke familieconstante, en name is de familienaam als een string.
De velden voor match-kwaliteit zijn wat een toepassing gebruikt om detecties te filteren. decision_margin is een betrouwbaarheidsscore van 0.0 – 1.0; hoger is beter, en het uitfilteren van detecties onder decision_margin > 0.1 ruimt de meeste valse treffers kosteloos op. hamming telt de bitfouten die de decoder voor deze tag accepteerde – lager is beter, waarbij 0 een perfecte decodering betekent. goodness is een historische beeldkwaliteitsmetriek die de huidige decoder niet langer berekent; het is altijd 0.0 en kan worden genegeerd.
5.28.3. Pose uit intrinsieken¶
Het transformatieve kenmerk van find_apriltags(), het kenmerk dat AprilTags rechtvaardigt als de fiducial bij uitstek voor robotica, is dat de methode de 6-DoF pose van de tag in het cameraframe rechtstreeks kan herstellen uit de gedetecteerde hoeken en een kleine set kalibratie-intrinsieken. De intrinsieken zijn de X- en Y-brandpuntsafstanden van de camera in pixels (fx, fy) en het optische middelpunt in pixels (cx, cy), die alle vier de toepassing eenmaal meet met een kalibratieprocedure en daarna hardcodeert.
Wanneer de intrinsieken worden meegegeven, vult de teruggegeven AprilTag zijn velden x_translation, y_translation, z_translation met de positie van de tag ten opzichte van de camera, en x_rotation, y_rotation, z_rotation (en het duplicaat rotation voor symmetrie) met de oriëntatie van de tag. Zonder intrinsieken zijn alle zes velden 0.0 en is de toepassing verantwoordelijk voor elke pose-schatting die ze nodig heeft.
De translatievelden worden gerapporteerd in tagbreedtes: de decoder behandelt de tag als 1 eenheid breed, dus de toepassing vermenigvuldigt elke translatie met de fysieke breedte van de gedrukte tag om metrische afstanden te verkrijgen. Een tag afgedrukt op 100 mm breed die z_translation = 8.3 rapporteert is 830 mm van de camera verwijderd; dezelfde tag afgedrukt op 50 mm breed op dezelfde afstand zou z_translation = 16.6 rapporteren. De rotatievelden zijn in radialen en hebben geen schaling nodig.
De pose-schatting is de basis voor een breed scala aan roboticatoepassingen: een robot laten aanmeren bij een oplaadstation gemarkeerd met een tag, een gedrukt routepad volgen, de eigen pose van de camera herstellen uit meerdere bekende tags in de omgeving. Een camera die de intrinsieken kent, een tag ziet en een positie in de echte wereld voor de tag heeft, heeft door dezelfde rekenkunde ook een positie in de echte wereld voor zichzelf.
5.28.4. Wanneer welke te kiezen¶
QR-codes en AprilTags lossen verschillende problemen op. De keuze tussen beide komt neer op wat het gedrukte symbool draagt.
Wanneer de toepassing willekeurige gegevens door het gedrukte symbool moet dragen – een URL, een serienummerstring, een contactrecord – is de QR-code de juiste keuze. Honderden bytes passen in een bescheiden code, de codering is openbaar en wordt op elke smartphone ondersteund, en de decoder gaat om met rotatie, matige schade en schuine hoeken.
Wanneer de toepassing een kleine ID continu van een afstand gelezen met optionele pose nodig heeft – een fiducial op een bewegende robot, een kalibratiedoel in een ruimte, een aanmeermarkering op een oplaadstation – is de AprilTag de juiste keuze. Honderden ID’s zijn ruim voldoende voor het gebruik, de Hamming-code herstelt van bitfouten die een QR-code zouden verslaan, en de pose-schatting is gratis zodra de intrinsieken zijn gekalibreerd.
Sommige toepassingen gebruiken beide: een AprilTag markeert een bekende locatie en een bijbehorende QR-code (ernaast afgedrukt) draagt de metadata over wat die locatie betekent. De twee detectoren draaien onafhankelijk op hetzelfde frame en de toepassing correleert hun begrenzingsvakken om elke tag aan zijn bijbehorende code te koppelen.