MostlyQR

Skenují se fotografické QR kódy doopravdy? Výsledky našich testů

Fotografický QR kód by měl skenovat hůř. Změřili jsme ten náš skutečným dekodérem — rozmazaný, zmenšený a čtený tak, jak ho čte čtečka.

Max Čelar··Tisk a skenování

Co je tu nového: Výsledky dekódovacích testů našeho vlastního fotografického QR kódu, změřené pomocí jsQR proti obyčejnému kontrolnímu kódu: žádný z 4,225 modulů se nenačetl chybně při všech velikostech čtecí clony od 0.10 do 0.45 modulu, stejná tolerance vůči třinásobnému zmenšení a tolerance rozostření 4–5 pixelů oproti 6 pixelům u obyčejného kódu. Je to konkrétní, malá cena za to, že z kódu uděláš obrázek.

QR kód, který je fotografií, vypadá jako kompromis: je hezký, ale část skenů ztratíš. Ten dojem je správný u většiny implementací a špatný v tom, jak to musí fungovat — a „část skenů“ není číslo, které by kdokoli zveřejnil.

Tady jsou naše čísla z testovací sady, která musela projít, než jsme funkci vůbec vydali.

# Co je fotografický QR kód a co není

Dvě velmi různé věci se nazývají stejně.

AI QR art — ten s difuzními modely — vygeneruje obrázek podmíněný QR kódem a pak doufá, že výsledek jde ještě dekódovat. Někdy ano. Selhání je neviditelné, dokud někdo v tmavém baru nenamíří na kód telefon starý tři roky.

Ditherovaný fotografický kód je druhý přístup a ten zde měříme. Obrázek se redukuje na jeden bit — černou nebo bílou na každém subpixelu — pomocí difuze chyby, s jedním zásadním omezením: v každém středu modulu je dither vynucen na hodnotu, kterou vyžaduje enkodér, a chyba, kterou toto vynucení vytvoří (až zhruba 95 % hodnoty jednoho pixelu, u bílého modulu v tmavé oblasti), se přenese do sousedních subpixelů, které ještě nebyly prahovány. Obrázek se skládá z prostoru mezi středy modulů.

Právě v tom je celý rozdíl. Znamená to, že kód nevynakládá svou opravnou schopnost na dekoraci: každý modul stále nese hodnotu enkodéru, takže plná redundance zůstává zachována pro záhyby, odlesky, palec přes jeden roh — přesně to, pro co chyby oprava vlastně existuje.

# Test

Všechno níže lze zreprodukovat z našeho repozitáře, offline:

  • Enkodér: náš vlastní packages/qr, opravná schopnost H, minimální hustota minVersion: 12 → verze symbolu 12, 65 modulů napříč, 10 pixelů na modul, tichá zóna 4 moduly.
  • Styly: halftone (skutečná ditherovaná fotografie) a mozaika (kreslí se jen moduly, velikost podle lokální tmavosti) oproti prostému neditherovanému kódu jako kontrole — stejný obsah, stejná verze, stejné měřítko.
  • Obrázky: procedurální testovací obrázky, včetně diagonálního přechodu (objeví se každý tón) a rovnoměrné středně šedé, což je nejhorší případ, protože každá vynucená tečka se liší od svého okolí.
  • Dekodér: jsQR 1.4.0, skutečný QR dekodér, dostane skutečné pixely.
  • Degradace: downscale metodou nejbližšího souseda, rozostření boxem s následným novým prahováním (rozostřený fotoaparát) a čtení přes clonu.

Sada, na které to stojí, je packages/qr/test/dither.test.js. Prošla 39/39 dne 31. srpna 2026, a kód, který nejde dekódovat, je neúspěšný test, a ne varování — právě to pravidlo je důvodem, proč funkce existuje v tomto tvaru. Tabulky níže vypisuje draft/mostlyqr/seo/benchmarks/photo.js, který spouští tytéž styly přes tytéž degradace; nic zde nebylo přepisováno ručně.

# Nula chybně přečtených modulů při každé cloně

Nejdůležitější měření není „dekódovalo se to“, ale „viděl čtecí zařízení správnou hodnotu v každé buňce“, protože kód, který se dekóduje jen proto, že ho zachránila oprava chyb, je kód, který selže, až se stane něco jiného.

Vyhovující čtečka nevzorkuje jeden pixel na modul. V každém středu modulu zprůměruje malou kruhovou clonu a výsledný průměr prahuje. Udělali jsme totéž, při poloměrech clony 0,10, 0,25, 0,36 a 0,45 modulu (0,5 by bylo celý modul), a spočítali, kolik z 4 225 modulů by bylo přečteno špatně:

Styl Chybně přečtené moduly, clona 0,10 / 0,25 / 0,36 / 0,45
prostý kód (kontrola) 0 / 0 / 0 / 0
mozaikové foto 0 / 0 / 0 / 0
halftone foto (přechod) 0 / 0 / 0 / 0
halftone foto (rovnoměrná středně šedá, nejhorší případ) 0 / 0 / 0 / 0

Ani jeden modul v žádném stylu, při žádné cloně, včetně nejhoršího obrázku. Fotografický a prostý kód předkládají čtečce stejné hodnoty. Oprava chyb je nedotčena a plně dostupná.

# Co to stojí: zhruba jeden krok rozostření

Nedotčená oprava chyb neznamená totožné. Dither skutečně mění, jak pixely mezi středy vypadají, a silně rozostřený fotoaparát je dohromady zprůměruje. Tak jsme každý styl tlačili, dokud se nerozbil:

Styl Maximální zmenšení, které se ještě dekódovalo Maximální poloměr rozostření, který se ještě dekódoval
prostý kód (kontrola) 3× 6 px
mozaikové foto 3× 5 px
halftone foto (rovnoměrná středně šedá) 3× 6 px
halftone foto (přechod) 3× 4 px

Zmenšení — kód vykreslený menší než nativně — je u všech stylů stejné: každý přežil 3× a každý poprvé selhal při 4×. (Zmenšení metodou nejbližšího souseda není monotónní — některé se při 5× znovu dekódovaly, protože mřížka vzorkování padla náhodou příznivěji — takže uvádíme první selhání, a ne poslední úspěch.)

Náklad se projeví při rozostření, a to jen u halftone stylu na nejtěžším obrázku: o třetinu menší rezerva než u prosté kontroly. Halftone rovnoměrného středně šedého pole se prostému kódu přesně vyrovnal, takže jde o náklad závislý na obrázku, a ne o vlastnost techniky. Jednoduše řečeno: fotografický kód potřebuje, aby byl fotoaparát zhruba o jeden krok blíž k zaostření než u prostého kódu. Je to skutečný náklad a je malý, a je to poctivá odpověď na otázku „dá se to naskenovat?“ — ne „ano“ a ne „ne“, ale „ano, s o něco menší tolerancí zaostření, zhruba o jeden krok“.

Mozaikový styl leží mezi oběma, což dává smysl: kreslí jen moduly, takže mezi středy je méně barvy, kterou by rozostření rozmazalo.

# Proč je hustota skutečný požadavek

První verze této funkce byla technicky správná a vypadala špatně, a to z důvodu, který stojí za to znát, pokud používáš jakýkoli nástroj pro fotografické QR kódy:

https://mqr.sh/AB12CD při opravě chyb H — což je to, co fotografický kód vynutí — se zakóduje do mřížky o 29 modulech. To je 841 buněk pro celou fotografii a výsledek působí jako šum, ne jako obrázek: lidé usoudí, že technika nefunguje, když skutečný problém je v tom, že pro obrázek není kde být. Vynucení hustšího symbolu to opraví:

Minimální verze Symbol Moduly napříč Buňky dostupné pro obrázek
žádná (co obsah potřebuje) v3 29 841
8 v8 49 2 401
12 (náš výchozí) v12 65 4 225

Pětinásobek buněk u verze 12. Každý vážný nástroj pro obrazové QR kódy vynucuje tuto hustotu ze stejného důvodu a minimální hodnota nesmí nikdy symbol zmenšit pod to, co obsah skutečně potřebuje — data mají vždy přednost před hustotou.

Důsledek pro tisk je přímý a je to důvod, proč tento článek sedí ve stejném celku jako kolik modulů tvůj obsah potřebuje: Kód o 65 modulech potřebuje 73 šířek modulu papíru včetně tiché zóny. Při modulu 0,5 mm je to 36,5 mm — takže fotografický kód je plakát, jídelní lístek, panel obalu nebo obrazovka. Není to vizitka.

# Co test nepokrývá

Řečeno rovnou, protože měřítko bez uvedených limitů je horší než žádné:

  • Jeden dekodér, syntetické pixely. jsQR je skutečný dekodér, ale není to zásobník fotoaparátu v telefonu a vstup je čistý vykreslený výstup, a ne fotografie vytištěné věci.
  • Žádný tisk, žádné odlesky, žádná perspektiva, žádné pomačkání. Každé z toho stojí rezervu a stojí fotografický a prostý kód různě.
  • Žádná barva. Jde o 1bitové černobílé kódy.
  • Naše vlastní implementace. Nic zde neříká nic o cizích fotografických nebo AI-art QR kódech. Pokud přepisují moduly a spoléhají na opravu chyb, aby škodu napravily, budou se chovat úplně jinak než tohle a férový test je ten výše, spuštěný proti nim.

# Kdy ho použít

  • Ano: plakáty, jídelní lístky pod sklem, panely obalů, obrazovky, výstavní grafika, cokoli tištěného ve velkém.
  • Pravděpodobně: obal alba, obal knihy, velký štítek produktu — vyzkoušej.
  • Ne: vizitky, papírové letáky, které se skládají, cokoli pod zhruba 35 mm, cokoli skenovaného při špatném světle a z dálky.

A pokud nechceš celou fotografii, ale své logo uprostřed jinak obyčejného kódu, je to jiná technika s mnohem menším rozpočtem — i to jsme změřili, jak velké může logo být, a odpověď je menší, než si internet myslí.

Fotografické QR kódy MostlyQR jsou implementace, která se zde měří. Stejné jádro ditheru běží v náhledu v prohlížeči i v PNG renderovaném na serveru, takže to, co vidíš v builderu, je to, co dostane tiskárna. Poznámka v builderu říká „nejlepší na obrazovkách a velkých tiscích — fotografický kód se hůř čte na malém nebo pomačkaném papíru“, což se po těchto číslech zdá být správná věc, kterou tam má.

Často kladené otázky

Spolehlivě se skenují fotografické QR kódy?

Podle našich vlastních testů ano, s jedním měřitelným nákladem. Když čteme naše fotografické kódy tak, jak to dělá vyhovující čtečka, tedy průměrováním kruhové clony ve středu každého modulu, nebyl chybně načten ani jeden z 4,225 modulů při žádné testované cloně. Snesly stejné třinásobné zmenšení jako obyčejný kód. Jediný změřený rozdíl byl rozostření, a to jen u nejtěžšího obrázku: obyčejný kontrolní kód přežil rozmazání o poloměru 6 pixelů, mozaikový styl 5 a půltónový styl 4 na přechodu (6 na rovné šedé). Je to zhruba jeden stupeň zaostření fotoaparátu, nikoli jiná kategorie spolehlivosti.

Spotřebovávají umělecké QR kódy korekci chyb?

Mnohé implementace ano, a proto má tato technika špatnou pověst. Ta naše ne. Místo toho, aby přepisovala celé moduly obrazovými daty a spoléhala na Reed-Solomona, že rozdíl opraví, vynutí tečku ve středu každého modulu na hodnotu, kterou kodér vyžaduje, a výslednou chybu rozptýlí do okolních subpixelů. Obrázek se platí z prostoru mezi středy modulů, takže celý rozpočet na korekci chyb zůstává k dispozici pro reálný svět: pro přehnuté rohy, odlesky a palec přes okraj.

Mohu vytisknout fotografický QR kód na leták?

Nedoporučujeme to. Náš vlastní tvůrce píše „nejlepší na obrazovkách a velkých tiscích“ a myslíme to vážně: fotografický kód potřebuje hustý symbol (65 modulů na šířku v níže uvedeném testu oproti 29 u stejného krátkého odkazu bez úprav), takže na velikosti letáku je každý modul velmi rychle malý. Ideální místa jsou plakáty, jídelní lístky pod sklem, panely na obalech a obrazovky. Papírový leták, který se ohýbá v kapse, ne.

Proč můj fotografický QR kód vypadá spíš jako šum než jako obrázek?

Téměř vždy proto, že symbol je příliš hrubý. Krátký odkaz s korekcí chyb H se zakóduje do mřížky 29 modulů, tedy 841 buněk, což je příliš málo na to, aby unesly rozpoznatelný obrázek, takže obrázek nemá kde být. Pomůže hustší symbol: verze 8 dává 49 modulů a verze 12 dává 65 (4,225 buněk, pětkrát tolik). Náš tvůrce proto u fotografických kódů ve výchozím nastavení používá verzi 12. Data mají vždy přednost, takže delší obsah dostane větší symbol.

Zdroje
  1. jsQR — the decoder used in the test
  2. The published description of the dithered-QR technique this implementation was built from
  3. QR Code standardization (ISO/IEC 18004) — Denso Wave
Další v tomto tématu