SWAPQR← Руководство

Почему художественный QR-код может не прочитаться, если поднести телефон вплотную

Все ожидают, что QR-код откажет, если он слишком мал, слишком далеко или слишком тускло освещён. У фото-кодов есть и обратный отказ: они прекрасно читаются с расстояния и перестают читаться, когда телефон подносят вплотную. Ниже объяснено почему — с цифрами того измерения, которое это обнаружило.

Создать QR-код в браузере →Напечатайте квадрат один раз. Куда он ведёт — решите потом.

Как сканер решает, что считать тёмным

Прежде чем искать модули, читатель обязан превратить фотографию в чёрно-белое. Глобальный порог не выживает в реальном освещении — тень, легшая на один угол, зачернила бы половину кода, — поэтому большинство декодеров вычисляет порог локально. ZXing, открытая библиотека, от которой до сих пор происходит немалая часть сканирования штрихкодов, делит изображение на блоки 8×8 пикселей, считает среднее каждого блока, сглаживает его с соседними блоками и использует результат как порог для этих 64 пикселей. Пиксель темнее порога своего блока считается тёмным, остальные — светлыми. Для обычного QR-кода это почти бесплатно. Каким бы ни был размер блока, модуль сплошной, поэтому среднее блока либо близко к тёмному, либо к светлому, либо лежит между ними, когда блок попал на границу, и решение в любом случае простое. Схема надёжна, дёшева и широко скопирована — именно поэтому она и важна: декодер, с которым встретится ваш напечатанный код в поле, вполне может считать порог именно так.

Что меняется, когда модули состоят из дизеринга

В коде с дизерингом модуль не сплошной. Это небольшое принудительное ядро, окружённое пикселями, которые несут фотографию. Его среднее верно; его текстура неоднородна. Теперь посмотрим на дистанцию сканирования в единственной значимой единице — пикселях камеры на модуль. Отодвиньте телефон настолько, чтобы модуль занимал 5—8 пикселей: блок 8×8 будет перекрывать границы модулей. Локальное среднее — это примерно «данный модуль и его соседи», порог оказывается между тёмным и светлым, и код читается. Поднесите телефон так, чтобы модуль занимал 20 пикселей, и блок 8×8 целиком помещается внутрь одного модуля. Средним блока становится собственная локальная текстура этого модуля. Порог начинает следовать за дизерингом вместо модуля, и декодер восстанавливает крап, а не код. В самом отпечатке ничего не изменилось; изменилось лишь число пикселей матрицы, приходящихся на модуль, а вместе с ним — отношение между блоком декодера и модулем. Поэтому отказ является свойством дистанции, а не размера или освещения.

Цифра

Мы измерили это при разработке фоторежима SWAPQR: три длины полезной нагрузки, шесть типов изображений, обе полярности цвета, три положения баланса, семь смоделированных дистанций сканирования, декодирование двумя независимыми библиотеками. Граница получилась чистой. При примерно 20% принудительной доли модуля — положение с упором на фото — и при примерно 44% коды читались на 5—8 пикселях на модуль, а читатели класса ZXing становились ненадёжны вплотную, на 10—28 пикселях на модуль. При примерно 60% и выше они читались на любой дистанции. Как только более половины площади модуля сплошная, любой блок 8×8, попавший внутрь модуля, ложится в основном на сплошные пиксели, и эффект исчезает. Ниже этой доли — не исчезает, и никакая подстройка тонового крена не помогает, потому что локальный порог всё равно вычитает локальное среднее. В какую бы сторону вы ни кренили тон модуля, блок целиком внутри него измерит этот крен как свою базовую линию и вычтет его. Единственный работающий рычаг — доля модуля, которая сделана сплошной, ради чего регулятор баланса и существует.

Новые декодеры и почему на этом нельзя успокоиться

Новые декодеры справляются лучше. В той же серии измерений jsQR, использующий другую стратегию бинаризации, прочитал все конфигурации на всех дистанциях, а сканеры, встроенные в современные телефоны, ещё сильнее. Но «большинство телефонов справится» — не то же самое, что «справится любой читатель», а напечатанный код встречается с тем читателем, который на него направили: старый телефон, кассовый сканер, киоск, приложение с библиотекой, происходящей от ZXing. Поэтому положение баланса с упором на фото честно сообщает о своём компромиссе — студия отмечает, что современные телефонные сканеры читают его на любой дистанции, тогда как более старые и простые читатели могут спотыкаться вплотную, — и выбор точки на балансе зависит от того, кто и с какого расстояния будет сканировать код. Зависит он и от того, где телефон оказывается естественным образом: никто не держит телефон на вытянутой руке перед афишей, но к визитке его подносят вплотную все, и именно там фото-код и простой читатель могут встретиться.

Что с этим делать

Если код едет туда, где его сканируют с обычной дистанции — афиша, настольная табличка, полочный ценник, — положения с упором на фото годятся: на такой дистанции модуль занимает несколько пикселей камеры, и блоки перекрывают границы, как и должны. Если код едет туда, где телефон приложат вплотную — маленькая наклейка, визитка, экран, — сдвиньте баланс к «Коду», чтобы более половины каждого модуля стало сплошным, и эффект близкого сканирования исчезнет для любого класса читателей. В обоих случаях напечатайте образец и просканируйте его телефоном. Не снимок экрана на мониторе, а настоящий отпечаток, в настоящем размере, с той дистанции, с которой люди будут им пользоваться, и желательно не одним телефоном. SWAPQR показывает это предупреждение в самой студии, а не мелким шрифтом, потому что код, отказавший в поле, хуже обычного кода, который работает, и потому что, если поймать это до тиража, лечится оно движением ползунка, а не перепечаткой.

Принудительная доля модуляДалеко / обычно (5—8 пкс на модуль)Вплотную (10—28 пкс на модуль)
~20% (упор на фото)ЧитаетсяЧитатели класса ZXing ненадёжны
~44% (середина)ЧитаетсяЧитатели класса ZXing ненадёжны
~60% и выше (упор на код)ЧитаетсяЧитается
Любая настройка, класс jsQR и современные телефонные сканерыЧитаетсяЧитается в той же серии измерений

Часто задаваемые вопросы

Мой телефон читает фото-код с любого расстояния. К чему предупреждение?

Современные телефонные сканеры используют более сильную бинаризацию и прочитали все конфигурации в нашей серии. Предупреждение касается более старых и простых читателей, считающих порог блоками 8×8, с которыми напечатанный код всё ещё может встретиться.

Почему помогает отодвинуть телефон?

Дальше от кода на каждый модуль приходится меньше пикселей камеры, поэтому блок 8×8 декодера перекрывает несколько модулей и его среднее оказывается между тёмным и светлым. Вплотную блок попадает внутрь одного модуля и следует за текстурой дизеринга.

Поможет ли усиление тонового крена при съёмке вплотную?

Нет. Локальный порог вычитает локальное среднее, поэтому любой равномерный крен внутри модуля вычитается вместе с ним. Результат меняет только доля модуля, сделанная сплошной.

Какой баланс безопасен для визитки?

Сдвиньте его к «Коду», чтобы сплошным стало больше примерно половины каждого модуля. С этого момента читатели класса ZXing в нашем измерении читали код на всех дистанциях, а картинка остаётся видимой, просто бледнее.

Напечатайте квадрат один раз. Куда он ведёт — решите потом. SWAPQR создаёт статические QR-коды бесплатно, со всеми вариантами оформления, без аккаунта и без водяного знака. Платный план делает код динамическим: напечатанный квадрат остаётся прежним, а вы меняете его адрес назначения и видите, как часто его сканировали, по дням и по устройствам.

Создать QR-код в браузере
Язык: TR EN DE ES FR IT PT AR RU JA KO