Что, если бы сканируемый код не был обязан выглядеть как набор квадратов и полосок? Что, если он выглядел бы как залитый дождём ночной город — и при этом всё равно безошибочно считывался?

Это NoiR Code. Он кодирует текст в изображение, которое читается как чёрно-белый нуар-кадр: полутоновый силуэт города, луна, штрихованные тени. Наводишь камеру в специальном приложении или веб-сервисе, созданном для поддержки этого формата, и получаешь своё сообщение обратно. Попробовать можно здесь: noir-code.suncake.xyz

Панель NoiR Code: полутоновый нуар-город с луной, собранный из ячеек данных
Панель NoiR Code: полутоновый нуар-город с луной, собранный из ячеек данных

Картинка выше — это не изображение, в котором спрятан код. Картинка и есть код. Точнее, данные несут центры ячеек сетки; город, луна и тени полезной нагрузки не содержат — это искусство, выросшее поверх той же сетки.

Почему

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

Зачем

Мне было интересно. Часто бывает, что я чрезмерно увлекаюсь какими-то занятиями и идеями. Это происходит внезапно, и так же внезапно я теряю интерес к этим вещам. Видеоигры, книги, разработка, мысли. Сейчас благодаря нейросетям я могу реализовать эти проекты раньше, чем потеряю к ним интерес.

Как он остаётся и искусством, и сканируемым

QR‑код тратит всю свою площадь на машиночитаемые квадраты. NoiR Code делит каждую ячейку на две части:

  • Центр каждой ячейки несёт одно тоновое значение — чёрный, тёмно‑серый, светло‑серый или белый. Только это и считывает декодер. Маленький, чёткий, устойчивый.

  • Кольцо вокруг центра — пространство для творчества. Штриховка, перекрёстная штриховка, кромки зданий, градиент неба — ничто из этого не несёт данных.

Декодер видит чистую сетку тоновых точек, а глаз — низкодетальную гравюру города. Рисунок генерируется процедурно из самого сообщения: каждый текст получает свой силуэт города и положение луны, детерминированно, — так что одно и то же сообщение всегда даёт одну и ту же панель.

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

Панель поменьше, кодирующая URL, отрисованная штриховкой
Панель поменьше, кодирующая URL, отрисованная штриховкой

Выживание в реальном мире

Код полезен, только если его легко отсканировать с телефона. NoiR Code для стабильности сканирования использует три вещи:

  • Чёрная рамка по периметру — единственный опорный элемент. Декодер находит это кольцо, считает гомографию и распрямляет панель обратно в квадратную сетку так, что наклонный снимок под углом всё равно выправляется.

  • Коды Рида‑Соломона означают, что часть панели может быть смазана, засвечена бликом или порвана, а сообщение всё равно восстановится. Дополнительная тоновая полоса снизу дублирует байты заголовка, поэтому восстанавливается даже стёртый верхний край.

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

В итоге считываются и чистые рендеры, и скриншоты с оконными рамками вокруг, и фото с монитора, и снимки с рук при неровном свете.

Сетка растёт вместе с сообщением

Короткому тексту не нужен билборд. NoiR Code выбирает наименьшую подходящую сетку — от 16×16 до 40×40 — так что короткий URL умещается в компактную панель 578px, а абзац разрастается на больший холст. Какой размер перед ним, декодер выясняет перебором кандидатов, а контрольная сумма подтверждает победителя. Никаких маркеров версии, никакого лишнего обвеса.

Сетка

Ёмкость

Панель

16×16

~22 байта

578px

24×24

~58 байт

770px

32×32

~109 байт

962px

40×40

~173 байта

1154px

Работает в браузере

Веб‑приложение целиком делает кодирование и декодирование через небольшой публичный API. Вводишь сообщение — получаешь панель. Или переключаешься в декодер: загружаешь изображение либо жмёшь Сканировать и используешь камеру — она снимает кадры несколько раз в секунду и останавливается в тот миг, когда получает чистое считывание.

Аккуратный небольшой стек завёрнут в докер, как горькая сигарета:

  • Ядро на Python делает всю настоящую работу — конвейер кодирования/декодирования, Рида-Соломона, машинное зрение на OpenCV — и выставлено как внутренний сервис на FastAPI.

  • Шлюз на Go стоит впереди как публичный API без состояния и проксирует запросы к Python-сайдкару.

  • SPA на React — это интерфейс, с переключателем EN/RU и нуар-темой: очень тёмной, с острыми углами и красными акцентами.

Всё развёрнуто на небольшом кластере k3s за Traefik с автоматическим TLS, собирается и публикуется по CI на каждый мёрдж.

Исходный код можно посмотреть в репозитории на Гитхабе.

Сравнение с QR

И давайте честно: для любой практической задачи QR лучше:

  • Ёмкость. NoiR Code вмещает максимум ~173 байта. QR — до нескольких килобайт. Короткая ссылка влезет, абзац текста — уже нет.

  • Размер. Ради этих 173 байт панель раздувается до 1154px. QR той же ёмкости заметно компактнее и плотнее.

  • Совместимость. Ни одна камера и ни один телефон не прочитают NoiR Code из коробки — нужен специально созданный веб-сервис или отдельное приложение. QR читает буквально всё. Это перечёркивает большую часть практического смысла.

  • Устойчивость. QR бинарный — чёрное или белое, его трудно сломать. NoiR использует чёрный, белый и две градации серого, поэтому он чувствительнее к освещению, JPEG-сжатию и дешёвой чёрно-белой печати или копиру.

  • Цена декодирования. Чтобы прочитать панель, нужны OpenCV, гомография, перебор версий, поворотов и рамок плюс коррекция Рида-Соломона. QR декодируется мгновенно и где угодно.

  • Стандарт. QR — это ISO и огромная экосистема. NoiR Code — самоделка без всякой совместимости. И стиль ровно один — нуар, на любителя.

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

Закодировать текст и посмотреть, как он растворяется в тенях дождливого ночного города. Исходный код в репозитории.

Комментарии (6)


  1. sanchas
    07.06.2026 13:25

    Как-то раз я экспериментировал с QR-кодами. Я взял QR-код и нарисовал поверх него второй QR-код, но не просто перекрасил квадраты, а нарисовал внутри квадратов кружки занимающие по площади примерно 25% от площади квадрата. Получилось два QR-кода в одном. Если сканировать его с близкого расстояния, то он читается по кружкам, а если с большого то по квадратам. Но наигравшись не нашел как применить эту идею...


    1. Staster
      07.06.2026 13:25

      Интересно было бы посмотреть, можете прислать пример такого куар кода. По поводу NoiR Code прикольная идея, но все портит необходимость в стороннем ПО, вся универсальность куаров в том что программы для его чтения есть везде.


      1. sanchas
        07.06.2026 13:25

        Старые исходники к сожалению пролюбил, поэтому на скорую руку написал заново. Примерно так. Тут квадратиками зашифровано "https://google.com", а кружочками "https://github.com". При некоторой сноровке и игре с масштабом можно поймать оба варианта.


        1. AlexKniga
          07.06.2026 13:25

          Интересно. При расстоянии до qr более ≈1.5 метра "https://google.com", ближе "https://github.com".


          1. sanchas
            07.06.2026 13:25

            На самом деле всё довольно просто. При распознавании учитывается середина квадратика. И если QR-код большой и виден четко, сканер срабатывает на кружочки. А если изображение нечеткое или маленькое, то берется усреднённый естественным образом цвет, который ближе к цвету квадратика.


  1. Politura
    07.06.2026 13:25

    У большинства точек контраст по отношению к фону слишком маленький. QR работает где угодно, на слабом освещении и смазанный, этот только когда света много и картинка не шевелится. Если попытаться засунуть его туда, где используются обычные штрихкоды, или QR, пользователи будут злиться и ругаться, и вся очередь за ними, когда каждый второй не может распознать и должен вбивать цифры и буквы руками.