QR-коды со скрытым фото: техника дизеринга и генератор

QR-коды со скрытым фото: техника дизеринга и генератор

Технический блог andrewt.net разбирает приём, который позволяет спрятать чёрно-белую фотографию прямо внутри QR-кода, так, чтобы код при этом продолжал сканироваться. Автор увидел такой QR-код в соцсети Mastodon: его сделал человек по имени Дэйв, который делит каждый пиксель QR-кода на сетку три на три, отдаёт центральную ячейку под обязательные данные, а остальные восемь, под пиксели фотографии. В результате получается низкодетализированное чёрно-белое изображение с характерным зернистым шумом типа «соль и перец».

Чтобы объяснить, откуда берётся этот шум и как его убрать, автор напоминает механику дизеринга, способа передать полутона на изображении с малой цветовой глубиной. Простое пороговое разбиение (тёмный пиксель делают чёрным, светлый, белым) даёт грубую картинку; фильтр Байера имитирует полутона шахматным узором по всему изображению. Более совершенный метод, дизеринг Флойда, Стейнберга: каждый пиксель обрабатывается слева направо и сверху вниз, а разница между его реальной яркостью и итоговым чёрно-белым значением («ошибка») рассеивается на ещё не обработанные соседние пиксели, которые из-за этого получаются чуть темнее или светлее. За счёт этого итоговое изображение в среднем оказывается ближе к оригиналу, а сам узор дизеринга выглядит менее навязчиво, чем регулярная сетка фильтра Байера.

Обязательные пиксели данных QR-кода (один из каждых девяти в примере автора) имеют случайный цвет и портят вид фотографии зерном. Автор решает эту проблему двухпроходным дизерингом: на первом проходе цвет каждого пикселя данных фиксируется заранее (он известен из содержимого кода), а ошибка от подгонки этого пикселя под нужный цвет рассеивается по восьми соседям, иногда она доходит до 95% яркости, если пиксель на тёмном участке фото приходится сделать чисто белым (при обычном дизеринге ошибка не превышает 50%, потому что там цвет пикселя выбирают свободно). На втором проходе так же дизерингом обрабатывается всё остальное изображение, уже с учётом ошибок первого прохода. В качестве примера в статье фигурирует изображение 147×147 пикселей.

Приложенный к статье инструмент-генератор позволяет вращать QR-код перед наложением фото и перебирать параметры кодирования QR, чтобы найти вариант почище. Генератор также умеет менять цвет части самых «шумных» пикселей данных, это работает благодаря встроенной в QR-коды избыточности (коррекции ошибок), которая позволяет исказить часть пикселей и всё равно успешно отсканировать код: именно так делают QR-коды с логотипом посередине. По наблюдению автора, такая подмена почти не улучшает качество картинки, если ошибка от пикселей данных и так корректно рассеяна дизерингом, зато заметно снижает надёжность сканирования.

Автор описывает результат как компромисс между красотой и сканируемостью: приём хорошо работает для QR-кода на большом экране или постере, но для бумажной листовки, которую могут помять, нужен больший запас избыточности и устойчивости, которым здесь жертвуют ради эстетики. Отдельно отмечается, что генератор делает крошечные изображения без полей, а поля вокруг QR-кода нужны для надёжного сканирования, и при увеличении браузеры обычно размывают такие картинки, если это не отключено через CSS. Цвет поля должен быть противоположен цвету середины трёх больших угловых квадратов-«маячков» QR-кода, обычно это белый, но для инвертированных QR-кодов нужен чёрный фон.

Ключевые факты

  • Каждый пиксель QR-кода делится на сетку три на три: центральная ячейка несёт обязательные данные, остальные восемь, пиксели встроенной фотографии.
  • Двухпроходный дизеринг Флойда, Стейнберга: сначала фиксируются цвета обязательных пикселей данных и их ошибка (до 95% яркости в тёмных участках) рассеивается по соседям, затем обычным дизерингом обрабатывается остальное изображение.
  • В примере из статьи изображение имеет размер 147×147 пикселей, и один из каждых девяти пикселей, обязательный модуль данных со случайным цветом.
  • Генератор умеет вращать QR-код, менять параметры кодирования и подменять часть самых «шумных» пикселей данных за счёт встроенной в QR-коды коррекции ошибок, как в кодах с логотипом посередине, хотя это заметно портит сканируемость почти без выигрыша в качестве картинки.
  • Компромисс между эстетикой и надёжностью: приём годится для больших экранов и постеров, а для листовки, которую могут помять, нужно больше избыточности; кроме того, генератор делает изображения без полей, которые нужны для надёжного сканирования.

Почему это важно

Материал, изящный пример того, как знание внутреннего устройства QR-кода (разделение на обязательные и «свободные» пиксели) и классического алгоритма дизеринга Флойда, Стейнберга позволяет совместить две несовместимые на первый взгляд вещи: машиночитаемый код и узнаваемое изображение. Двухпроходная схема, где первый проход принудительно фиксирует цвет обязательных пикселей и честно рассеивает возникающую от этого ошибку, конкретный технический приём, который можно применить и вне QR-кодов, везде, где требуется совместить произвольные ограничения на часть пикселей с дизерингом остальных.

Кому это важно

Дизайнерам и маркетологам, которые делают брендированные QR-коды для полиграфии и упаковки; разработчикам, интересующимся обработкой изображений и алгоритмами дизеринга; и просто любителям визуальных хаков, которым интересно, как заставить служебный код нести дополнительный смысл.

Как это применить

К статье приложен рабочий генератор: в него загружается фотография, код можно повернуть перед наложением изображения и перебрать варианты кодирования QR, чтобы результат выглядел чище. Отдельная опция позволяет разрешить генератору менять цвет части самых «шумных» пикселей данных за счёт запаса коррекции ошибок в QR-коде, но, по словам автора, эта опция заметно снижает надёжность сканирования при малом выигрыше в качестве изображения, так что использовать её стоит с осторожностью. Итоговый код лучше проверять сканированием с разных устройств и расстояний, особенно если он пойдёт в печать.

Можно ли доверять

Изложенная механика опирается на реальные и хорошо документированные свойства QR-кодов (деление на обязательные и «свободные» модули, встроенная коррекция ошибок) и на классический, десятилетиями используемый алгоритм дизеринга Флойда, Стейнберга, ничего экзотического или непроверяемого здесь нет. К статье приложен работающий генератор, так что любое утверждение из текста можно проверить самостоятельно, сгенерировав свой QR-код. Имя автора статьи, точная дата публикации и то, каким инструментом изначально была сделана QR-фотография Дэйва с Mastodon, в тексте не указаны.

Риски и подводные камни

Приём, прямой компромисс между красотой и надёжностью сканирования: чем сильнее фотография вмешивается в обязательные пиксели данных, тем выше риск, что код не считается с плохого угла, при плохом освещении или на дешёвой камере. Отдельно стоит держать в уме, что генератор выдаёт изображения без полей вокруг кода, хотя поле нужно для устойчивого сканирования, а браузеры при увеличении картинки без поля обычно её размывают, если это явно не отключить через CSS. Для печатной продукции, которая может помяться или испачкаться (листовки, а не постеры за стеклом), автор советует закладывать больше запаса устойчивости, чем даёт эстетичный вариант из генератора.