Redan på 1980-talet utvecklade Microsoft en enhetsoberoende lösning för bildåtergivning för bitmaps: BMP-filformatet.¹ De som använde Microsoft Paint tidigare kunde njuta av den gigantiska filstorlek som producerades av enkla streck och färgfyllningar.
Tanken bakom BMP-filformatet är att varje pixel tilldelas ett färgvärde. Så om jag har en bitmapp på 480×360 som stöder 16 miljoner färger (24 bitar), skulle bitmappen bli någonstans norr om 4 MB stor.
Det här är förstås inte idealiskt om man vill återge flera bilder av hög kvalitet. Därför måste man ställa sig frågan. ”Finns det ett sätt att optimera bitmappresentationen så att man fortfarande kan bevara bildens visuella integritet men med mindre resurser att använda?”
Svaret är ja. Det visar sig att användarna för det mesta är mer intresserade av bilder som visuella hjälpmedel än av noggrannhet. Anta att jag till exempel får en bild av Golden Gate Bridge som visas nedan:
Som jag vet att den verkliga bron när den ses i verkligheten är mycket mer detaljerad, är det som jag ser här tillräckligt bra för ändamålet. Så de flesta människor är faktiskt villiga att byta ut visuell integritet mot snabbhet så länge som kompromissen är acceptabel. Om t.ex. försämringen av den subjektiva visuella kvaliteten är 1 %, men användaren får njuta av en utrymmesbesparing på 90 %, är det för det mesta ett välkommet byte.
En av de viktigaste övervägandena vid komprimering av bitmaps är därför att optimera för visuell oskiljbarhet. Det vill säga att ta bort vissa element i en bild där det blotta ögat inte kan identifiera skillnaden. Detta kallas förlustkomprimering och utgör de flesta typer av komprimering som man ser vid videoströmning av bilder på nätet. Det är så här som H.264, HEVC, HEIF och JPEG codecs fungerar.
Andra typer av bilder, till exempel PNG, komprimeras förlustfritt. Tanken är att man bevarar den ursprungliga bildens fulla visuella integritet men förbrukar färre bytes för att representera samma sak. Det finns dock andra filformat som WebP som stöder både förlustkomprimering och förlustfri komprimering. Varför vill vi komprimera saker förlustfritt? Precis som ovan är det baserat på vad vi vill uppnå med bilden. Till exempel är ikoner i appar vanligtvis i PNG (och nyligen i vektorgrafikformat).
Förlustfri bildkomprimering består av större filstorlek till skillnad från förlustfylld komprimering. Anledningen är främst att det finns färre möjligheter att komprimera den förstnämnda än den sistnämnda. I den här bloggen kommer vi att tala om förlustkomprimering.
De generella stegen som togs vid JPEG-komprimering görs än i dag vid videokomprimering. Under årens lopp har algoritmen förbättrats, men de allmänna begreppen förblir desamma.
STEG 1. Färgrymdskonvertering
Bildkonverteringen börjar med att konvertera det råa RGB-bildformatet till dess kromatiska (r och b) och luminans (Y) värden. Tanken är att våra ögon är mer känsliga för förändringar i luminans än för färg. Därför kan vi faktiskt minska färgskalan i bilden utan att märkbart påverka bildens visuella kvalitet. Detta görs genom Chroma Subsampling som förklaras nedan.
STEG 2. Chroma Subsampling
Många spelare minns kanske att subsampling är en av de möjliga rattar de kan ställa in för att optimera sin spelupplevelse. Huvudtanken är att ju mer subsampling man gör, desto snabbare blir spelprestandan. Detta beror på att spelet kräver mindre antal färger att rendera.
Chroma subsampling betecknas med J:a:b där J är antalet pixlar som ska subsamplas, a representerar pixlarna i den övre raden och b representerar pixlarna i den nedre raden.
I fallet 4:4:4 betyder det att i en 4×2 pixlar måste den första raden (a) ha 4 färger och så även den andra raden. I fallet 4:2:2 betyder det att i en 4×2 pixel ska den första raden ha två färger och den andra raden likaså. I fallet 4:2:0 betyder det att i en 4×2 pixel ska den första raden representeras av två färger och den andra raden kopierar över det som finns på den första raden.
Som du kan se kan man genom chroma subsampling reducera färgskalan med så mycket som 75 %.
STEG 3. Diskret kosintransformator
JPEG-komprimering görs genom att den ursprungliga bilden skärs upp i bitar av 8×8 pixlar. I detta steg tilldelar vi koefficienter för 8×8 bitarna baserat på de signaler som visas nedan.
Tanken här är att ju mer det mänskliga ögat rör sig från den övre vänstra delen av DCT-referensen till den nedre högra delen, desto svårare är det att uppfatta. Så vanligtvis är det så att vid tilldelningen av koefficienter får den övre vänstra koefficienten ett mycket högt värde och det sjunker när man rör sig diagonalt nedåt.
Så här kan det se ut i numeriskt format:
STEG 4. Kvantisering
När DCT har tillämpats kallas nästa steg för kvantisering. Här tillämpas en kvantiseringstabell på de resulterande DCT-värdena. Tabellen skiljer sig åt mellan olika komprimeringsalgoritmer och i vissa programvaror kan användaren själv ställa in hur mycket kvantisering han/hon vill använda. Nedan följer en standardtabell:
Bemärk att siffrorna blir högre när man rör sig från övre vänster till nedre höger. Detta är avsiktligt. Tanken med kvantisering är att de resulterande data från DCT delas med kvantiseringstabellen. Det är här som den komprimerade bilden förlorar mycket av sina data. Eftersom de nedre högra siffrorna är höga kommer de flesta av dess värden så småningom att bli noll efter divisionen. Så här kan det se ut:
STEG 5. Entropikodning med hjälp av Huffman-kodning
Huffman-kodning är det sista steget i komprimeringen. Så här fungerar den.
Antag att jag vill representera ett antal siffror med hjälp av bitar. Dessutom vill jag representera dem på ett sådant sätt att jag förbrukar minst antal bitar för representationen. Hur det kan göras är att de högt upprepade talen får lägre bitar. Om t.ex. noll representeras mycket, skulle jag i allmänhet tilldela det lägre bitar. En mer ingående förklaring av Huffman-kodningen finns här.
Tanken här är att man använder färre bitar för att representera en längre uppsättning värden. Huffman-kodning är en förlustfri komprimeringsalgoritm som också används för att komprimera textfiler. Genom att göra detta är det möjligt att spara så mycket som 50 % av den ursprungliga storleken.
Vad händer härnäst?
Komprimering är bara en del av ekvationen. När man ska återge bilden måste man vända komprimeringsprocessen innan man kan återge bilden på skärmen.
JPEGs är ungefär 90 % mindre än dess motsvarighet i form av bitmappar. Än idag är det fortfarande det mest populära bildkomprimeringsformatet. Nyare algoritmer som HEIF (2013) och AVIF (2018) ökar antalet pixlar man kan använda för komprimeringsalgoritmen.²
Trots JPEG:s popularitet ger nyare format bättre komprimering. WebP till exempel är i allmänhet cirka 70 % av storleken på JPEG och kan ändå bibehålla bildens visuella integritet. Därför har Google (företaget som utvecklat WebP) uppmanat utvecklare att omkoda sina bilder från JPEG till WebP. Stödet för WebP är dock fortfarande mindre än för JPEG. Därför är det nödvändigt att stödja båda formaten som ett resultat.
¹ ”The BMP File Format”. Prepressure. Tillgänglig den 19 april 2019. https://www.prepressure.com/library/file-formats/bmp.
² Netflix publicerade den första uppsättningen AVIF-bilder 2018. I och med det här inlägget är bilderna fortfarande tillgängliga här. Företag som Firefox och Microsoft kommer snart att stödja den här bilden i sina programvaruerbjudanden.