Mijn compressieregel leek aanvankelijk eenvoudig: encodeer AVIF met de laagste kwaliteit die nog een SSIMULACRA2-target van 60 haalt. Bij grotere beeldverzamelingen mocht één representatieve sample tot 58 zakken, terwijl alle andere samples minimaal 60 moesten halen.
Voor PNG en normale bronbestanden werkte dat prima. Daarna kreeg ik WebP-bestanden die al lossy waren gecomprimeerd vanuit originelen van hogere kwaliteit voordat ik ze ontving.
origineel van hogere kwaliteit: ~2 MB
↓
lossy WebP: ~100 KB
↓
AVIF
Mocht die tweede conversie nog steeds slagen met 60 ten opzichte van de WebP? Eerst dacht ik van wel. Een score van 60 blijft 60. Maar wat werkelijk veranderd was, was de referentie.
De metric was niet fout. De referentie was veranderd.
SSIMULACRA2 vergelijkt een referentiebeeld met een vervormd beeld en scoort het perceptuele verschil tussen precies die twee inputs. De metric reageert op compressieschade zoals blur, ringing en kunstmatig geïntroduceerde randen; de gepubliceerde evaluatiematerialen bevatten vervormingen van JPEG, WebP, AVIF en andere codecs. De SSIMULACRA2-documentatie](https://github.com/cloudinary/ssimulacra2/blob/main/README.md%22>SSIMULACRA2-documentatie) beschrijft de metric en de globale kwaliteitsankers.
Als ik AVIF rechtstreeks encodeer vanuit een goede bron, is de vergelijking praktisch source → AVIF. Een score van 60 beschrijft dan de schade die door die conversie is toegevoegd.
Bij een WebP die al lossy is, ziet de echte geschiedenis er anders uit:
original
↓ first lossy encode
WebP
↓ second lossy encode
AVIF
SSIMULACRA2 ziet alleen WebP → AVIF. De metric weet niets van het originele beeld dat vóór de WebP bestond. Artefacten die al in de WebP zitten, worden onderdeel van de referentie.
Een score van 60 kan dus zeggen dat de AVIF niet te ver van de WebP is afgeweken. Hij kan niet zeggen hoe ver de uiteindelijke AVIF van de verloren master staat.
Lossy transcoding creëert een tweede kwaliteitsbudget
Stel dat het origineel een vloeiende gradient bevat. De eerste encoder voegt een beetje banding toe, maar de WebP ziet er nog acceptabel uit. Daarna encodeer ik die WebP naar AVIF. SSIMULACRA2 kan extra degradatie door de AVIF-encoder bestraffen, maar niet de schade die al onderdeel is van de referentie.
Daarom is encoden vanuit een reeds lossy beeld niet hetzelfde als rechtstreeks encoden vanuit de beste beschikbare bron. Een discussie in het libavif-project](https://github.com/AOMediaCodec/libavif/discussions/2640%22>libavif-project) beschrijft hetzelfde algemene principe: bestaande compressieartefacten kunnen worden meegenomen naar een nieuwe AVIF wanneer de input al gecomprimeerd is.
Dat betekent niet dat AVIF automatisch elk WebP-artefact verergert, en ook niet dat transcoding altijd verkeerd is. Het betekent dat de tweede encoder begint nadat een deel van het oorspronkelijke kwaliteitsbudget al is opgebruikt.
De policy waar ik uiteindelijk op uitkwam
- Canonieke of hoogwaardige bron: target 60, floor 58 voor één sample.
- Lossless WebP: target 60, floor 58.
- Bekend lossy derivaat: target 65, floor 63.
Het belangrijke onderscheid is niet JPEG tegenover WebP, maar canonieke bron tegenover bekend lossy derivaat.
WebP kan lossless zijn. De WebP](https://developers.google.com/speed/webp/docs/webp_lossless_bitstream_specification%22>WebP) lossless-specificatie beschrijft een modus die pixelwaarden exact reconstrueert. Dan is er geen eerdere lossy generatie. Omgekeerd verdient een JPEG waarvan ik weet dat hij al meerdere lossy transformaties heeft doorlopen dezelfde voorzichtigheid als een eerder gecomprimeerde WebP.
Waarom 65?
Er bestaat geen SSIMULACRA2-regel die zegt dat een tweede lossy generatie precies vijf extra punten nodig heeft. Ik heb zo'n regel niet gevonden omdat die niet bestaat. 65 is een engineering policy, geen eigenschap van de metric.
De gepubliceerde kwaliteitsankers geven context. Grofweg staat 50 voor medium of fair quality en 70 voor high of good quality. Daarmee ligt 60 in een vrij agressieve webcompressiezone, niet in de visually lossless-zone.
Bij een rechtstreekse conversie vanuit een goede bron accepteer ik dat perceptuele budget in ruil voor kleinere bestanden. Voor een tweede lossy generatie wilde ik minder extra vervorming toestaan.
Ik heb 70 overwogen, maar dan zouden alle getranscodeerde afbeeldingen naar een aanzienlijk strengere kwaliteitszone verschuiven. Op pagina's met veel afbeeldingen, zeker via mobiele verbindingen, tellen extra bytes. Ik had geen bewijs dat het afdwingen van 70 voor alle reeds gecomprimeerde afbeeldingen die kosten rechtvaardigde. Daarom koos ik 65 als conservatieve middenweg.
Waarom 65/63 en niet 65/62?
Mijn oorspronkelijke policy was 60/58: één representatieve outlier mocht twee punten onder het hoofdtarget zakken. Als ik het target naar 65 verhoog en dezelfde policy behoud, kom ik vanzelf uit op 65/63.
60 - 58 = 2
65 - 63 = 2
Met 62 wordt de uitzondering drie punten. Normale samples worden strenger, terwijl juist de slechtste sample meer ruimte krijgt. Ik vond geen technische reden om die uitzondering specifiek voor reeds lossy gecomprimeerde inputs te vergroten.
Noch 63 noch 65 is een magisch getal. Het nuttige is dat de policy intern consistent blijft.
Van 2 MB naar 100 KB zegt niets betrouwbaars over visuele kwaliteit
Ik leid SSIMULACRA2-drempels bewust niet af uit de compressieverhouding. Een daling van 2 MB naar 100 KB klinkt spectaculair, maar bestandsgrootte alleen zegt verrassend weinig over perceptuele degradatie.
Resolutie, beeldentropie, ruis, vlakke gebieden, line art, chroma subsampling en het eerdere formaat beïnvloeden de compressie-efficiëntie sterk. De WebP-compressiestudie](https://developers.google.com/speed/webp/docs/webp_study%22>WebP-compressiestudie) van Google vergelijkt codecs bij ongeveer gelijkwaardige kwaliteit in plaats van te veronderstellen dat gelijke bestandsgrootte gelijke visuele kwaliteit betekent.
Ik gebruik dus geen regels zoals 20× kleiner → target 65. Voor mijn policy is van belang of het huidige bestand een bekend lossy derivaat is, niet hoe indrukwekkend de verkleining eruitziet.
Als ik het origineel nog heb, transcodeer ik de WebP niet
Als zowel het hoogwaardige origineel als de kleine lossy WebP beschikbaar zijn, encodeer ik AVIF rechtstreeks vanuit het origineel en gebruik ik de normale 60/58-policy.
preferred:
original → AVIF
avoid when possible:
original → lossy WebP → AVIF
Een strenger target voor de tweede generatie kan informatie die tijdens de eerste encode verloren is gegaan niet herstellen. 65 houdt de AVIF alleen dichter bij de WebP; 70 zou hem nog dichter houden. Geen van beide reconstrueert het verloren origineel.
De implementatiebug was belangrijker dan 62 versus 63
Tijdens het herzien van de policy vond ik een gevaarlijker probleem in de encoderlogica. De code had al formatspecifieke targets en een helper die voor WebP een ander target kon teruggeven. Daardoor leek de stap van 60 naar 65 triviaal.
Dat was niet zo. De adaptive quality decision gebruikte nog steeds het globale target en de globale worst-score-threshold. Het formatspecifieke target werd later gebruikt om individuele resultaten als pass of below-target te labelen, maar stuurde niet noodzakelijk de beslissing die de uiteindelijke AVIF-quality selecteerde.
Daarmee ontstaat een subtiele fout: een WebP-sample kan correct als onder target 65 worden gemarkeerd, terwijl de adaptive search dezelfde quality toch accepteert omdat de globale passvoorwaarde nog steeds 60 is.
intended WebP target: 65
actual score: 61.2
format-aware label: below target
global search rule: pass if target is still 60
Een threshold is betekenisloos als hij niet deelneemt aan de beslissing die de werkelijk encoded output kiest.
Veiliger is om thresholds onderdeel van de sample-policy te maken
Ik behandel thresholds nu liever als eigenschappen van de bron in plaats van decoratieve formatconstanten. In vereenvoudigde pseudocode:
if sample is a known lossy derivative:
target = 65
floor = 63
else:
target = 60
floor = 58
reject if any sample is below its floor
allow at most one sample below its target
Het belangrijke is dat dezelfde thresholds waarmee een resultaat wordt beschreven ook bepalen of dat resultaat wordt geaccepteerd.
De sampling-policy telt ook mee
Ik hoef niet elke afbeelding op elke mogelijke AVIF-quality te testen. De pipeline kiest maximaal tien representatieve JPEG-, PNG- of WebP-samples over de bytes-per-pixelverdeling.
Bij collecties van tien afbeeldingen of minder moet elk sample het normale target halen. Bij grotere collecties mag één sample de lagere floor gebruiken, terwijl de overige samples het hoofdtarget moeten halen.
Sampling maakt de zoektocht praktisch, maar is ook een reden om de outlierregel niet onnodig soepel te maken. De gekozen samples zijn representatief; ze bewijzen niet dat elke niet-gesamplede afbeelding identiek reageert.
Het experiment dat de heuristiek kan vervangen
Het sterkste antwoord zou komen van het bewaren van echte originelen voor een representatieve corpus en het testen van volledige ketens:
A: original → AVIF, target 60
B: original → lossy WebP → AVIF, target 60
C: original → lossy WebP → AVIF, target 63
D: original → lossy WebP → AVIF, target 65
E: original → lossy WebP → AVIF, target 70
Voor elke variant zou ik de uiteindelijke bestandsgrootte, SSIMULACRA2 ten opzichte van het echte origineel, SSIMULACRA2 ten opzichte van de WebP-intermediate en de gekozen encoder-quality vastleggen. Moeilijke afbeeldingen zou ik ook handmatig inspecteren.
Ik heb die gecontroleerde test nog niet uitgevoerd op een voldoende representatieve set bewaarde originelen. Daarom kan ik niet beweren dat 65 universeel optimaal is. Die beperking is belangrijk.
AVIF rechtvaardigt niet automatisch nog een encode
Als de enige resterende bron een WebP van 100 KB is en de AVIF die 65/63 haalt 96 KB groot is, zou ik de conversie ter discussie stellen. Vier kilobyte besparen rechtvaardigt misschien geen extra lossy generatie en extra verwerkingscomplexiteit.
Wordt dezelfde WebP van 100 KB een AVIF van 65 KB terwijl de quality policy nog steeds wordt gehaald, dan wordt de trade-off veel aantrekkelijker op beeldrijke pagina's.
Een codecconversie moet twee afzonderlijke vragen beantwoorden: is de extra vervorming acceptabel, en is de bestandsgroottereductie groot genoeg om relevant te zijn? De eerste halen garandeert de tweede niet.
De regel die ik nu gebruik
Heb ik het beste origineel, dan encodeer ik daar rechtstreeks vanuit en gebruik ik 60/58 voor deze webworkload. Is de WebP lossless, dan gebruik ik eveneens 60/58. Is het enige resterende bestand een bekend lossy derivaat, dan gebruik ik een strenger budget voor de tweede generatie, momenteel 65/63. Als AVIF nauwelijks kleiner wordt, overweeg ik de bestaande WebP te behouden.
De diepere les is niet dat WebP een speciaal SSIMULACRA2-getal nodig heeft. Een full-reference quality metric beantwoordt alleen de vraag die door zijn referentiebeeld wordt vertegenwoordigd.
Als de referentie al informatie heeft verloren, betekent een hoge score “dicht bij deze referentie”, niet “dicht bij het beeld dat ervoor bestond”. Toen ik de herkomst van een afbeelding onderdeel maakte van de compressie-policy, zagen thresholds er niet langer uit als willekeurige codecinstellingen. Het werden budgetten voor verschillende generaties verlies.