Hoe maak je QR-codes met foutdiffusie

QR-codes: de basis

Hoewel de exacte werking niet cruciaal is voor dit artikel, kunnen we een QR-code voor dit doel definiëren als een raster van vierkanten dat is onderverdeeld in twee delen: de functiepatronen (de prominente vormen) en de datamodules (alles wat overblijft). De functiemodules worden hoofdzakelijk gebruikt om de scanner te helpen de QR-code gemakkelijk te vinden, waardoor ze zeer helder en duidelijk moeten zijn. In de datamodules wordt de eigenlijke data opgeslagen, samen met enkele extra headergegevens. Omdat deze modules pas worden uitgelezen nadat de scanner via de functiemodules heeft vastgesteld waar de QR-code zich precies bevindt, kunnen ze iets meer worden aangepast. Merken gebruiken dit vaak om QR-codes te maken die er kenmerkend uitzien. Hoewel dit soort aanpassingen de scanbaarheid enigszins vermindert, kan men over het algemeen vrij ver gaan voordat de codes onleesbaar worden.

Afbeeldingen in QR-codes plaatsen

Een van de aanpassingen die je kunt doen met de datamodules is het verkleinen ervan. De scanner kijkt namelijk naar waar de finder-patronen aangeven dat de centra van de pixels zouden moeten zitten; zolang de code niet vervormd is tijdens het scannen, blijft dit werken. Dit betekent dat de resterende ruimte vrij beschikbaar is.

Een methode hierbij is om elke pixel te verdelen in een raster van drie bij drie, waarbij het middelste vierkant wordt gebruikt om de data op te slaan en de overige vierkanten voor een foto. Het resultaat is een foto met een lage resolutie en één-bit kleurdiepte, met enige 'salt-and-pepper'-ruis.

Dithering

Wanneer we een afbeelding reduceren naar een lage kleurdiepte, passen we normaal gesproken geen eenvoudige drempelwaarde (thresholding) toe — waarbij donkere pixels zwart worden en lichte pixels wit. In plaats daarvan gebruiken we meestal een soort schaakbordeffect om ook middentonen te creëren. Een Bayer-filter kan worden gebruikt om dit idee toe te passen op een hele afbeelding zonder te veel fijne details te verliezen.

Foutdiffusie (Error Diffusion)

Een poging om deze methode te verbeteren was de Floyd-Steinberg dithering.

Bij deze methode begin je linksboven en pas je normaal drempelwaarde-behandeling toe: als een pixel meer dan 50% helderheid heeft, maak je hem wit; anders maak je hem zwart. Stel dat een pixel een helderheid van 70% had — we maken hem wit (100% helderheid), wat betekent dat we 30% te veel helderheid hebben toegevoegd. Om dit tegen te gaan, 'diffunderen' (verspreiden) we die fout naar andere pixels: alle naburige pixels die nog niet zijn behandeld, worden een stukje donkerder gemaakt, tot in totaal 30% van een pixel. Wanneer we deze pixels vervolgens behandelen, houden we daar rekening mee.

Het idee is dat zodra de hele afbeelding is verwerkt, elk deel van de afbeelding gemiddeld dichter bij de correcte helderheid ligt dan bij reguliere dithering. Bovendien zijn de onregelmatige patronen minder storend.

QR-codes met foutdiffusie-dithering

Een ander voordeel van deze onregelmatige dithering is dat de 'salt-and-pepper'-ruis, veroorzaakt door de datamodules van de QR-code, veel moeilijker op te merken is. De ruis is echter nog steeds aanwezig, wat verklaart waarom de afbeelding er korrelig uitziet. Dit komt enerzijds doordat het een één-bit afbeelding van 147×147 pixels is, maar anderzijds omdat één op de negen pixels effectief willekeurige kleuren heeft.

Dit kan worden opgelost door méér foutdiffusie toe te passen.

De datamodules met foutdiffusie bewerken

In dit geval wordt de foutdiffusie in twee fasen uitgevoerd. De tweede fase is hetzelfde als normaal, maar de eerste fase is specifiek bedoeld om de datamodules te maskeren. Omdat we al weten welke kleur al deze pixels moeten hebben, geven we ze die kleuren en diffunderen we die fout naar de omliggende acht pixels.

De fout kan in dit geval vrij groot zijn. Normaal gesproken kunnen we de kleur kiezen waardoor de fout nooit meer dan 50% bedraagt, maar hier moeten we misschien een pixel in een donker gebied puur wit maken, wat resulteert in een fout van 95%. Dat klinkt slecht, maar dat is precies waarom het zo belangrijk is om deze fout te diffunderen in plaats van deze simpelweg te accepteren. Dit resulteert in een veel schonere afbeelding.

Geavanceerde opties

Met behulp van generatietools kunnen er extra trucs worden toegepast:

  • De QR-code kan worden gedraaid voordat de afbeelding wordt toegevoegd.
  • Er kan geëxperimenteerd worden met de instellingen van de QR-code om te zien of alternatieve coderingen er mooier uitzien.

Daarnaast is het mogelijk om de generator toe te staan een paar van die pixels met een foutmarge van 95% aan te passen. QR-codes bevatten voldoende foutcorrectie waardoor je een aantal pixels kunt wijzigen zonder dat dit de scanbaarheid beïnvloedt (dit is ook hoe QR-codes met logo's in het midden werken). In de praktijk heeft dit echter weinig invloed op de beeldkwaliteit als de fouten van de datamodules al worden gediffundeerd, terwijl het wel een serieuze impact kan hebben op hoe goed de code scant.

Praktisch gebruik

Deze methode werkt goed zolang je niet te ver gaat en de code wordt getoond op een groot scherm of een poster. Als de code echter op bijvoorbeeld een papieren flyer komt die kreukels kan krijgen, heb je meer van de redundantie, robuustheid en foutcorrectie nodig die we hebben opgeofferd om de QR-code esthetisch aantrekkelijker te maken.

Uiteindelijk is het een afweging tussen esthetiek en scanbaarheid. Houd er rekening mee dat wanneer een code scant op jouw telefoon vanaf een laptopscherm, dit niet betekent dat hij ook scant op de eenvoudige telefoon van een vreemde vanaf een printout met slechte belichting.

Ten slotte is het belangrijk om te onthouden dat generatietools vaak kleine afbeeldingen maken zonder marge. Er is echter een marge (stiltezone) nodig om een QR-code betrouwbaar te kunnen scannen. Bovendien zullen browsers afbeeldingen normaal gesproken vervagen bij het opschalen, tenzij dit met CSS wordt uitgeschakeld. De marge moet de tegenovergestelde kleur hebben van het midden van de drie grote 'finder'-patroonvierkanten — normaal gesproken is dat wit, maar bij geïnverteerde QR-codes is een zwarte achtergrond nodig.