5.28. QR-коди та AprilTags

Детектори, розглянуті раніше – плями, лінії, кола, прямокутники – знаходять геометричні ознаки: позиції та контури, які наступний етап обробки інтерпретує. Решта детекторів знаходять символьні ознаки: друковані патерни, візуальна структура яких створена спеціально для кодування корисних даних. Камера їх виявляє, декодер зчитує біти, і у відповідь повертається не позиція, а рядок (або ідентифікатор), свідомо обраний тим, хто надрукував символ.

Дві такі сім’ї домінують у застосунках з малими камерами. QR-коди містять довільний текст, URL, контактні картки або двійкові дані – це 2D-коди для споживачів, що з’являються на плакатах, пакуванні та посадкових талонах. AprilTags містять єдиний числовий ідентифікатор з невеликого фіксованого набору, швидко декодуються навіть з великої відстані, а (якщо надано внутрішні параметри об’єктива) повертають позу з 6 ступенями свободи у системі координат камери – це 2D-коди для робототехніки, що позначають дрони, цілі калібрування та реперні точки. Обидва детектори повертають об’єкти результатів з тим же словниковим запасом обмежувальних прямокутників, що й детектори плям і прямокутників, однак корисне навантаження робить їх принципово відмінними від усього, розглянутого раніше.

5.28.1. QR-коди

find_qrcodes() сканує кадр у пошуку QR-кодів і повертає список об’єктів результатів 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)

Детектор приймає один необов’язковий параметр roi для обмеження зони пошуку. Він потребує вхідних даних у відтінках сірого – кольоровий кадр конвертується внутрішньо перед декодуванням.

Кожне виявлення містить обмежувальний прямокутник (x, y, w, h, rect), чотири виявлені кути (corners – проєктивний чотирикутник, що утворюється пошуковими патернами QR-коду) і декодовані дані у вигляді рядка. Кути є правильним елементом для малювання при анотуванні виявлення – QR-код, знятий під кутом, не вирівняний по осях, а обмежувальний прямокутник дає лише приблизний контур.

Метадані декодера охоплюють усе, що дізнався QR-декодер у процесі роботи. version – це версія QR-коду від 1 до 40, яка визначає розмір сітки модулів (код версії 1 має ширину 21 модуль, версії 40 – 177). ecc_level – рівень виправлення помилок (від 0 до 3 для L / M / Q / H); вищі рівні резервують більше кодових слів для виправлення помилок і витримують більше пошкоджень ціною зменшення обсягу корисних даних. mask – це маскувальний патерн (від 0 до 7), обраний кодером для мінімізації помилок декодера. data_type – це кодування, яке повідомив декодер (числове, буквено-цифрове, двійкове або Kanji), а прапорці is_numeric / is_alphanumeric / is_binary / is_kanji представляють те саме значення у зручнішому булевому вигляді.

eci – це значення Extended Channel Interpretation, яке визначає текстове кодування байтів (UTF-8, ISO-8859-1 тощо). QR-код із довільного друкованого матеріалу може не гарантувати UTF-8; застосунок, якому потрібно правильно декодувати байти, перевіряє eci і декодує відповідно. Особливий випадок – Kanji: MicroPython не розбирає кодування Kanji, тому дані is_kanji слід обробляти як масив байтів і декодувати засобами застосунку.

Типовий сценарій використання: камера зчитує QR-коди з конвеєра і передає декодовані дані на хост. Камера виконує find_qrcodes() один раз за кадр, ітерує повернений список, відбирає коди, чий data_type відповідає очікуванням застосунку, і передає c.payload через UART або USB. Дані обмежувального прямокутника і кутів корисні для попереднього перегляду в IDE, але не є тим, що цікавить хост.

5.28.2. AprilTags

find_apriltags() сканує кадр у пошуку AprilTags і повертає список об’єктів результатів 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 відрізняються від QR-кодів своїми цілями проєктування. QR-код призначений для кодування довільних даних в одному щільному символі, який користувач зчитує один раз зблизька. AprilTag призначений для кодування малого ідентифікатора у розрідженому символі, який камера зчитує безперервно з відстані, з таким рівнем стійкості до помилок, який дозволяє код Геммінга його сімейства. Компроміс проявляється з обох боків: QR-код може містити сотні байтів, але потребує зчитування зблизька; AprilTag містить лише кілька сотень унікальних ідентифікаторів, але надійно зчитується з відстані в метри.

Ключове слово families приймає бітову маску сімейств міток для декодування. Доступні сімейства: image.TAG16H5, image.TAG25H9, image.TAG36H10, image.TAG36H11, image.TAGCIRCLE21H7, image.TAGCIRCLE49H12, image.TAGCUSTOM48H12, image.TAGSTANDARD41H12 та image.TAGSTANDARD52H13. Кожне сімейство балансує між кількістю ідентифікаторів і надійністю. Число після H у назві – це мінімальна відстань Геммінга між будь-якими двома кодами в сімействі – скільки бітів має перекинутися, щоб один дійсний код перетворився на інший: TAG16H5 має 30 ідентифікаторів при відстані 5, TAG25H9 – 35 ідентифікаторів при відстані 9, а TAG36H11 (типовий та найпоширеніший) – 587 ідентифікаторів при відстані 11. Детектор виправляє до двох бітових помилок незалежно від сімейства, тому відстань визначає ступінь ризику такого виправлення: випадковий патерн у шумному кадрі повинен лише опинитися в межах двох бітів від дійсного коду, щоб декодуватися як хибне виявлення, а сімейства з більшою відстанню розміщують свої коди настільки рідше, що такі збіги стають рідкісними – саме тому TAG36H11 є рекомендованим вибором. Час виявлення масштабується з кількістю увімкнених сімейств, тому застосунок вмикає лише ті, що він реально друкує. Коли в одному виклику потрібно кілька сімейств, бітова маска є побітовим АБО констант сімейств.

Кожне виявлення містить словник обмежувального прямокутника – x, y, w, h, rect, area, цілочисельні та субпіксельні центроїди (cx, cy, cxf, cyf) – а також чотири виявлені кути (corners). Далі йдуть поля ідентифікації: id – числовий ідентифікатор у межах сімейства (від 0 до 586 для TAG36H11), family – числова константа сімейства, name – назва сімейства у вигляді рядка.

Поля якості розпізнавання використовуються застосунком для фільтрації виявлень. decision_margin – це оцінка впевненості від 0.0 до 1.0; чим вища – тим краще, і відфільтрування виявлень нижче decision_margin > 0.1 усуває більшість хибних спрацювань без витрат. hamming підраховує кількість бітових помилок, прийнятих декодером для даної мітки – чим менше, тим краще; 0 означає ідеальне декодування. goodness – застарілий показник якості зображення, який поточний декодер більше не обчислює; він завжди дорівнює 0.0 і може ігноруватися.

5.28.3. Поза з внутрішніх параметрів

Визначальна ознака find_apriltags(), яка виправдовує AprilTags як реперну точку для робототехніки, полягає в тому, що метод може відновити позу мітки з 6 ступенями свободи у системі координат камери безпосередньо з виявлених кутів і невеликого набору калібрувальних внутрішніх параметрів. Внутрішні параметри – це фокусні відстані камери по осях X і Y у пікселях (fx, fy) та оптичний центр у пікселях (cx, cy), всі чотири з яких застосунок вимірює один раз у процесі калібрування і після цього жорстко кодує.

Коли внутрішні параметри вказано, повернутий AprilTag заповнює поля x_translation, y_translation, z_translation позицією мітки відносно камери, а поля x_rotation, y_rotation, z_rotation (і дублікат rotation для симетрії) – орієнтацією мітки. Без внутрішніх параметрів всі шість полів дорівнюють 0.0, і застосунок відповідає за будь-яку потрібну йому оцінку пози.

Поля трансляції вказуються в ширинах мітки: декодер вважає мітку шириною 1 одиниця, тому застосунок множить кожну трансляцію на фізичну ширину надрукованої мітки, щоб отримати метричні відстані. Мітка, надрукована шириною 100 мм і яка повідомляє z_translation = 8.3, знаходиться на відстані 830 мм від камери; та сама мітка, надрукована шириною 50 мм на тій самій відстані, повідомить z_translation = 16.6. Поля обертання вказуються в радіанах і не потребують масштабування.

Оцінка пози є основою для широкого спектра застосунків робототехніки: стикування робота із зарядною станцією, позначеною міткою, проходження надрукованого маршруту, відновлення власної пози камери з кількох відомих міток у середовищі. Камера, яка знає внутрішні параметри, бачить мітку і має реальне положення мітки у просторі, тими ж обчисленнями знає й власне реальне положення у просторі.

5.28.4. Коли що обирати

QR-коди та AprilTags вирішують різні задачі. Вибір між ними залежить від того, що несе надрукований символ.

Коли застосунку потрібно передати довільні дані через надрукований символ – URL, рядок серійного номера, контактний запис – правильний вибір – QR-код. Сотні байтів вміщуються в код помірного розміру, кодування є загальнодоступним і підтримується на кожному смартфоні, а декодер справляється з поворотом, помірними пошкодженнями та косими кутами.

Коли застосунку потрібен малий ідентифікатор, що безперервно зчитується з відстані з можливою оцінкою пози – реперна точка на рухомому роботі, ціль калібрування у приміщенні, стикувальний маркер на зарядній станції – правильний вибір – AprilTag. Сотень ідентифікаторів цілком достатньо для таких сценаріїв, код Геммінга відновлює бітові помилки, що подолали б QR-код, а оцінка пози є безкоштовною, якщо внутрішні параметри відкалібровано.

Деякі застосунки використовують обидва: AprilTag позначає відоме місце, а пов’язаний QR-код (надрукований поряд) несе метадані про те, що це місце означає. Обидва детектори працюють незалежно на одному кадрі, і застосунок зіставляє їхні обмежувальні прямокутники, щоб зв’язати кожну мітку з її кодом-супутником.