2017/10/03

JPEG alapok 5 - color subsampling

a 8x8-as tömbösödés mellett egy 16*16-os színtömbösödés is észrevehető helyenként. Ennek a 2:2 subsampling az oka.
Ez a lépés nem kötelezően fordul elő a JPEG kódolása során. Ezért, külön próbálunk kapcsolódni hozzá. Ha valaki tudja a magyar szakkifejezést, ne titkolja. Amúgy meg voltam győződve, hogy nem is nehéz téma, kicsi átlagolás ide-oda. De nem. A bejegyzés végére sem fogunk sokkal közelebb kerülni a megértéshez.

Az RGB - YCbCr átalakítás után következik, még a DCT előtti lépésben, így használható ki legjobban a fileméret csökkentő hatása. Definíció szerint a kroma subsampling alacsonyabb felbontású színcsatorna kódolást jelent (a luminancia csatorna kódolásához képest), egy chrominance pixel 2, 4, 8 szorosa a luminance pixelnek, kihasználja a szem gyengeségét a színek észlelésében. YCbCr színtérben gondolkodva, ez azt jelenti, hogy a luminancia csatorna érintetlen marad, a Cr és a Cb csatornákat pedig lehet rozsolni. Persze vannak olyan esetek, ahol a színinformáció is irtó fontos tud lenni, pl. orvosi, térinformatikai képalkotásban. De a facebookon aztán töknyolc. Mellesleg ott 2x2-es. Kipróbáltam.

RGB és Lab összehasonlítás 2x2-es color (a,b) subsampling
A Lab a,b csatornáin jól látszik, hogy 4 pixel ugyanazt a színt kódolja.



Ha az interneten keresgélni kezdenél ebben a témában, tuttifix, hogy a J:a:b  rendszer lesz amibe leginkább belebotlasz. Ideszúrom azért Douglas A. Kerr munkáját, amiben az elnevezések között vág rendet. Ennyire mélyen most nem megyünk bele, csupán pár szóban, a J a blokk (általában 4x2 pixel) száma vízszintesen , az a a felső vízszintes sorban, a b az alsó sorban található kroma-pixelek száma.  Ezt csak itt megmutatjuk, majd megyünk is tovább...
Forrás
...ugyanis nekünk a JPGsnoop, exiftool meg a társaik teljesen más elnevezést mutatnak, ezért ennek eredünk a nyomába.
A fenti ábra a Nikon D5000 Fine beállítás subsamplingjét mutatja.
Még egy indok, hogy RAW-ba dolgozzunk, a drága cucc simán kidobja az információ 33 százalékát.

Az 1x1 (4:4:4) gyakorlatilag nem is subsampling, minden pixel a maga jogán van elkódolva, ahogy kell.  A luminanciát nem is szokás subsamplingelni, mert minek.
Amennyiben minden csatorna 1x1 lenne, akkor valahogy így történne a kódolás:
YCbCr, YCbCr, YCbCr... stb., azaz pixelenként 3 byte. Így ment a PS 7-es minőségtől felfele.
A két kroma csatornának a fenti példában viszont 2x1-es subsamplingja van (4:2:2), ami azt jelenti, hogy két szomszédos kroma-pixel értéke kiátlagolódva egyetlen egyszer kerül elkódolásra. Így:
YYCbCr, YYCbCr, YYCbCr...  vagyis két pixelenként 4 byteon kódol 6 helyett. Így ment a Nikon D5000 Fine módban.
Van ennél is durvább tömörítése a színeknek, a 2x2 (4:2:0), ami értelemszerűen mindkét irányba két pixelt, vagyis négyet átlagol ki.
YYYYCbCr, YYYYCbCr...  négy pixelen 6 byte, 12 helyett. Ilyen az Assus Fine beállítása (!), a Photoshop JPEG mentése 6-os szint alatt, facebook stb.
Van még olyan is, hogy 4x4, de ezt pl. a PS nem alkalmazza, ilyenkor aztán 16 kroma pixel kerül kiátlagolásra, ami már azért a színlátásban bénácska látást sem tudja kicselezni.
YYYYYYYYYYYYYYYYCbCr - viszont csökkenti a fileméretet rendesen, 16 pixel csak 18 byte.


A fenti ábra jól mutatja mivel jár a color subsampling pixeles szinten. A PS 12-7-es JPEG minőségnél 1X1-es chroma subsamplinget használ. 6-0 között viszont 2x2-est.  Erről majd lesz szó. Persze egy 2x2-es beállítás nem fog jelentős colorshiftet eredményezni >4 pixeles színfoltok esetén, de viszont előfordulhatnak olyan helyzetek a képen, finom textúrák, pl. színes tarka ruhadarab, amin a csíkok nagyságrendje a subsampling zónába esik, és emiatt teljesen más színt fogunk kapni a JPEG kódolása után.
De azért nem egy rossz technika, mert bár teljesen más színek keletkeznek (jobb és baloldal)...

... viszont a mindennapi fotográfiában. 1:1 méretben, azért elég jól eltalálja a tónusokat:


Másik érdekesség a PS 00 értákre tömörített képen, hogy YCbCr módban ugyan látszik a két chroma csatornán a 2x2-es tömbösítés, de valamiféle turpisságot használ visszakonvertáláskor. Gyanítjuk, hogy valamilyen antialiase lehet. 

2017/09/29

Valóban jobban látunk kontrasztot, mint színeket?

A cím meglehetősen pongyola (fényesség vs színesség a téma), de mindjárt kiderül miről van szó. Már egy jó csomószor meghivatkoztam, hogy az emberi látás, meg a luma, meg a chroma, de semmit se nem hiszünk el senkinek, ezért legyen itt egy félperces, elég butácska, de szerintem meglehetősen szemléletes példa. Persze a PS nem tud direkt módon YCbCr-be konvertálni, tehát trükközünk picit. Nem én találtam ki, a netről nyaltam nektek.
Originál
A kiindulási képből Desaturate paranccsal létrehozzuk a Luminancia réteget, majd a kiindulási képet 25%-ra csökkentjük (Best for reduction). majd 400%-ra növeljük kétféleképpen. Egyik a Smooth (jobboldali), másik a Hard (baloldali) interpoláció. Ezeket visszahelyezzük a deszaturált rétegre, Color Blending mode beállítással. 
 Az előbbi módszer fordítottját végezzük el, az alapréteg most a színes eredeti lesz, a deszaturált réteg kap most 2x2-es subsamplinget, majd visszahelyezve a színes rétegre, Luminosity blending módot állítunk.  
A képeket 100%-ban nézzétek, ofkorsz, a jobb sarokban egy 200% nagyítást is kaptok. Asszem magukért beszélnek. Innentől nem kérdés, hogy van létjogosultsága a color subsamplingnek. 

Találtam egy ilyet is valami powerpointban (sajni nem tudom belinkelni, keressétek meg, mert jó):

Azért is sznájpoltam ide, mert nemcsak a luma-chroma kérdést világítja meg, hanem visszacsatolhatunk a Diszkrét koszinusz transzformációhoz is. Jól megfigyelhető, miért állították azt, és a nyomukban én is szajkóztam, hogy a látás a nagyfrekvenciás jelekre kevésbé érzékeny, mint az alacsonyabbakra. Na ezér. 

2017/09/28

JPEG alapok 4 - Futamidő- és Huffman-kódolás

Előzménye a DCT kvantálása. Na, ebben a részben történik meg a tömörítés, ami önmagában veszteségmentes folyamat (a veszteség már a kvantálás során keletkezett).


A kvantált DCT
5. A kvantálás utáni mátrixból egymás után rendezzük frekvencia szerint az AC értékeket, aminek hatására a DC után először az alacsony, majd a magas frekvenciák lesznek egymás után fűzve. Gyakorlatilag egy kétdimenziós táblából egydimenziósat csinálunk. Ennek az a célja, hogy többnyire hasonló elemek (főleg a zérósok) nagy számban rendeződjenek egymás mellé. Emlékszünk, ezért nyírtuk ki a nagyfrekvenciás jeleket a tömbünk jobb alsó régiójában, hogy ez megtörténjen. Első érték tehát a DC (0,0 pozíció), jelen esetben a -26, ami a teljes blokk átlaga is egyben, azután az alacsony frekvenciák felől haladunk a magas frekvenciák felé, vagyis a jobb alsó sarok irányába. Így:
-26 -3 0 -3 -3 -6 2 4 1 -4 1 1 5 1 2 -1 1 -1 2 0 0 0 0 0 -1 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
A DC értéket amúgy az előző blokkhoz viszonyítva bonyolultabbul menthetik, arra alapozva, hogy a szomszédos blokkok átlagai közel esnek egymáshoz, inkább a kis méreten kódolható eltérést kódolják, mint a nagydinamikájú adatot, ebbe most nem megyünk bele.

Na innen kezdve aztán elég sokféleképpen magyaráz az internet. A futamhossz-kódolást (run-lenght-encode) többnyire szöveggel és karaktereinek kódolásával mutatják be, de volt aki nem átallotta almákkal és banánokkal. Na midegy, mi képpel dolgozunk. Azt a módszert vesszük át, amit a leghitelesebbnek ítéltünk meg (8 perc környékén tér rá erre Amir úr).

A futáshossz-kódolás (RLE) lényege, hogy az egymást követő azonos értékeket pl. zérósok (más weboldalakon, videókban minden ismétlődő érték), ne fogyasszanak sok tárhelyet. Csökkentjük a redundanciát, de mi most csak a nullásokkal (azér' kvantáltunk, hogy jó sok legyen), olyan formában, hogy megadjuk a zérósok számát (r), majd az azokat követő AC érték tárolására szükséges bitek számát (s) - innen fogja tudni a kiolvasó program, hogy pontosan mit kell kiolvasni, mint AC adatot, majd magát a zérósokat követő AC értéket magát (c).

 [(r,s),c]
Tehát a sorunk elemein végighaladva:
-26 -3-3 -3 -6 2 4 1 -4 1 1 5 1 2 -1 1 -1 2 0 0 0 0 0 -1 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

[(0,5),-26] - mivel a DC az első elem, ezért itt az r=0, és máris belefutottunk Amir Nagah videójában egy érdekességre. Ő azt állítja, hogy -26 elkódolható s=5 biten. Felmerült bennem, hogy a negatív előjellel meg mi van? Írtam is neki kérdés-kommentet, lám mit válaszol.
[(0,2),-3] - a második érték előtt sincs zérós, -3 meg Amir szerint 2 biten tárolható. Egyelőre ezzel tárhelyet pazarlunk, de nézzük a zöld zónát:
[(5,1),-1] - 5 zérós előzi meg a -1-et. Itt már 3 számmal írtunk le ötöt, de az igazán érdekes az a feketével kiemelt sor:
[(0,0)] -  ez az EOB jel, ha az r és az s is nullás, akkor innentől a blokk végéig mind zérós jön. Na itt történik a nagy redundanciacsökkentés és tömörítés. 

Amir a videójában azt állítja, hogy a JPEG-ben minden (r,s) párost egyetlen byte ír le, amiből a felső négy bit az r, az alsó négy bit az s. Amennyiben az r nem elég (a zérósok száma >15), több rövidebb futamhossz-kódolásból oldják meg. Az s értékére max. 11-et ír (15 helyett), ennek köze lehet a fent említett előjel-problémának a megoldásához (lássuk mit válaszol). 11 biten mellesleg 2047-ig kódolhatunk. Gyakorlatilag tehát az történik, hogy 15 nullást egyetlen byte kódolhat el. Az EOB byte meg bármennyi nullást.

Egy valós képen, ahol a 8*8-as blokkok homogének és nagyobb felületeken sem nagyon ütnek el egymástól (pl. a fél képen kék ég húzódik), egyes (r,s) párosok sokkal gyakrabban fognak előfordulni, mint mások. Tehát ha a  [(r,s),c] sorozatokat egymás után fűzzük (binárisan persze), akkor lesznek benne patternek, amelyek gyakran fordulnak elő, mások kevésbé. Ezeket érdemes helyettesíteni, a gyakoriakat rövidebb szimbólummal, a ritkábbakat hosszabbal, így további tárhely spórolható meg. 

Ezt csinálja a Huffman kódolás (ebből is többféle van), bár létezik JPEG-ben aritmetikai kódolás is, ami még nagyobb tömörítést eredményez, viszont macerásabb (talán a JP2000, de arra a körhintára nem kívánunk felülni). Lényege az, hogy az elkódolni kívánt elemeket statisztikai gyakoriságuk szerint rendezi, a kevésbé gyakori elemekhez rendel nagyobb címet, a gyakoriakat pedig kevés biten kódolja. A youtube tele van magyarázatokkal, ne spóroljátok meg. Én sem írnám le jobban. Ezt a tömörítést az interneten általában szövegkódolással illusztrálják, tegyünk így mi is, egy Eminem nótában pl. a fuck szó lenne a legrövidebben megcímezve, a hegeli dialektika pedig a leghosszabban (de lehet, hogy tévedek és ilyet egyszer se mondott ki). Tipikus programozói feladat. Azért egy képernyőképet ideszúrok magamnak emlékeztetőnek. Az a1, a2 stb. a kódolni kívánt elemek, pirossal az előfordulásuk gyakorisága jelenik meg. Sárga mezőben pedig az elkódolásukhoz szükséges bináris cím.
Az így keletkezett címeket egymás után írjuk. A legszebb ebben a trükkben az, hogy míg a szavakat szóközök jelzik, a morzéban meg pl. szünet vezeti be a következő jelet, itt a teljes hosszú bit-kolbászban nincs szükség elválasztó szimbólumokra az egyes jelek között, maga a kiolvasási rendszer garantálja a helyes visszakódolást:
például legyen ez a Huffman-kódolt bitstream: 010110101010011101001011101010110010101010
A fenti bináris fa segítségével sorban kiolvassuk. A színek jelzik, melyik szimbólumot melyik szakaszból vesszük: a1, a2, a3a2, a2, a2, a1, a4, a1, a2, a1, és így tovább, egyszerűen nem lehet másképp kiolvasni.

Minden képnek saját bináris fája van, természetesen a visszafejtéshez a JPEG filenak tartalmaznia kell az adott adathalmaz visszafejtéséhez szükséges információkat. A Huffman-kódot is lehet tweakelni a haladóbbaknak, a jobb eredmény érdekében. Mi azonban csak tátjuk a szánkat, a JPEGsnoppal ilyesmiket találtunk Huffman kulcsszóra a tesztekhez használt képünkben:
Egy random JPEG Huffman eloszlása. A DC tábla nyilván jóval kevesebb információt (12) kódol, az AC meg 256-ot.

A táblázatok statisztikai eloszlásából jól látszik, hogy bár eredetileg minden egyes értékre 8 bit kellene, közel felüket 2 bitből meg lehet címezni. Bár van olyan ritkán előforduló adat, ami akár 16 bitet használ el, azért a nyereség elég látványos. A 0% értékek becsapósak, valamiért a JPEGsnoop nem tud egynél kisebb értékeket itt megjeleníteni. 










Mivel a százalék értékek nem pontosak, csak a nagyságrend számolható ki, a négy tábla összes adata megegyezik a 12 megapixeles kép összes pixeleinek a számával. Eben az esetben a DC táblázatban az látszik, hogy a leggyakoribb adatokat 3 biten kódolja, de találtunk olyan képet is, amiben már 1 biten. Gondolom ez azon múlik, milyen bináris fát sikerül létrehozni (levél-ág, vagy ág-ág szerkezet van a gyökér után).

A tömörítésben még van egy fontos tényező, a subsampling, de mivel azt nem mindig alkalmazzák, külön tárgyaljuk a következő részben. Nagyjából ennyi volt a JPEG elkódolása, megnyitáskor pedig ugyanezek a folyamatok fordítva játszódnak le. Ennyike. 

2017/09/27

JPEG alapok 3 - kvantálás


4. lépés a kvantálás. Itt történik meg a veszteség, a későbbi tömöríthetőséget előkészítendő. De nem maga a veszteség az, ami miatt kisebb lesz a file.

Az előbbi lépésben képzett 8x8-as DCT együtthatók kvantálása következik, a kvantálási mátrix segítségével.  A nagyfrekvenciás részletekből fog kidobni többet az eljárás (a DCT mátrix jobb alsó régiójából), az alacsonyakat (lassabban változó képi információkat) egyre kevésbé bántja (a DCT tábla bal felső régiója).

A kvantálás egy 8x8-as adat-mátrix szerint történik, amelyben minden egyes érték a DCT megfelelő együtthatóját fogja osztani, az eredményt meg felkerekítjük. A tábla (annak értékei) függ a mentés minőségi beállításától (is), ezen keresztül állítható be a veszteség mértéke. Eltérő a luminancia és a krominancia kvantálási mátrixa, hiszen a luminancia jeleit kevésbé tizedeli meg, mivel a szem érzékenyebb a kontrasztra mint a színváltozásokra.
Ezeket a wikiről fogdostuk össze. 











A kvantálási mátrixok létrehozására van ezerféle ajánlás (pl. IJG standard 0-99), abszolút nem mindegy a képek felhasználási területe. A kamerák és szoftverek kvantálási mátrixai finomhangoltak, ezért nehéz megfeleltetni őket egymással. Ebben nem segít a fileméretek összehasonlítása sem (pl. lásd később a PS 6-7-es tömörítési érték körüli érdekességet). A PS saját custom fix táblákat használ, nem az IJG standardot. Ezt csak pár képpel teszteltük és csakis a 12-es értéket - ott igaz a hír - logikus is, a többszöri újramentésnél ennek lehet értelme. Vannak alkalmazások, amelyek a mátrix kialakításakor figyelembe veszik a kép egészét, körülményeket, általában a kamerák saját szoftverei ilyenek (custom adaptive tables - on the fly computing). A Nikon D5000 például két ugyanolyan beállítással (ugyanolyan programautomatika) készített képeken is különféle táblázatokat használt. Pláne nem egységes két különböző típusú gép Fine beállítása. A kvantálási táblák annyira specifikusak is lehetnek, hogy forensic alkalmazások ebből tudják megtippelni, hogy volt e matatva egy kép, és ha igen, milyen szoftverekkel. Erre később visszatérünk.

A fenti ábrán jól látszik, hogy a kis DCT együtthatók, és/vagy nagy kvantálási osztók esetén nagyobb az esély, hogy 0 legyen a kerekítés eredménye. A kerekítés során elveszett információ a veszteség.  Minél jobb minőségű kódolást alkalmazunk (több 1-es áll a kvantálási mátrixban), annál több  DCT együttható értéke marad érintetlen, kevesebb veszteség lesz, viszont a kvantálás során kevesebb lesz a 0, amit tömöríteni lehetne, tehát nagyobb lesz a fileméret.

Leegyszerűsítve, a kvantálási mátrixban a nagyobb szám szarabb képet okoz, de nagyobb tömörítést.

Tehát a példában -415/16= -26, a -33/11= -3 lesz és így tovább. A kerekítésekben elég nagy veszteség tud keletkezni (ez amúgy is egy közepesen durva beállítás), viszont hatalmas 0-val töltött mezők jönnek létre, ami jól tömöríthető később. Visszaalakításnál pl.  a második elem -3*11 pontosan visszaadja a -33-at, de a -6*10 már nem lesz 58 többé. Sokkal durvább a veszteség ott, ahol 0 keletkezik a kvantálás után, hiszen ott az eredeti AC érték már egyáltalán nem állítható vissza. A DC értékét is érintheti a veszteség, ez pl. a 8*8-as blokk tónusában, colorshiftben mutatkozhat meg.
Amennyiben az összes AC értéke 0 lenne a kvantálás után, az egyben azt is jelentené, hogy a 8x8-as blokkunk tónusa (vagy színe, ha a chroma csatornáról beszélünk) kiátlagolódott, hiszen akkor csak a DC érték állítható vissza.

Összefoglalva: a kerekítés során elveszett információ tehát a veszteség. Ha a kvantálási táblában csupa 1-es állna, az azt jelentené, hogy nem történt veszteség (de igen, egy kevés  a lebegőpontosról átalakítás miatt is lenne), viszont a kevés 0 érték miatt tömöríteni se fog túl sokat az eljárás.

A legtöbb veszteség tehát ennél a lépésnél keletkezik a folyamatban, emiatt egy JPEG más eszközön (más kvantálási mátrix) történő egyszerű újramentése is újabb veszteséget fog okozni. Minden JPEG file hordozza magában a kvantálási mátrixot, amivel kvantálták, hiszen csak így lehet visszafejteni amikor megnyitjuk bármiben, ezért a JPEGsnoop-al ki is lehet nyerni belőle, hogy össze-vissza hasonlíthassuk:
A PS kvantálási mátrixai, 12-es és 0-ás tömörítési szintek esetén.  
Érdekes a fenti ábrán, hogy a legdurvább tömörítésnél (0 szint) sokkal nagyobb együtthatókkal operál az alacsonyabb frekvenciák (bal felső) felé, ami ellene mond annak az elvnek, hogy a nagyfrekvenciákat jobban ki lehet gyomlálni, míg a 12-es, jó minőségű kvantálás eredményező táblában pont fordítva, a magasabb frekvenciákra (jobb alsó) ad nagyobb együtthatót. Erről értekezhetnénk, ha lenne bárki, aki eddig elolvasta volna ezt a bejegyzést... Dzsida is ezt érezte.
"Körülnéztem: szerettem volna néhány
szót váltani jó, meghitt emberekkel,
de nyirkos éj volt és hideg sötét volt,
Péter aludt, János aludt, Jakab
aludt, Máté aludt és mind aludtak...
Kövér csöppek indultak homlokomról
s végigcsurogtak gyűrött arcomon."

2017/09/26

JPEG alapok 2 blokkosítás és a diszkrét koszinusz-transzformáció

Előzmények a RGB - YCbCr átalakítás. Ebben a lépésben még sem veszteség, sem tömörítés nem történik. Sőt.

2. Következő lépés a keletkezett három új csatorna (Y/Cb/Cr) 8X8-as blokkokra történő szegmentálása (MCU - minimum coded unit) - ezek határainak elhelyezkedésén sok fog múlni, ideális lenne ha a kép X és Y irányban is osztható lenne 8 pixellel. Mivel a fényképezőgépek mind tudnak JPEG-et menteni, adta magát a kérdés, hamar csekkoltuk is, minden gépünk maximális felbontása felosztható 8x8 egész számú többszöröseire. Gondolom erre a gyártók figyelnek, ha nektek van olyan gépetek, ami nem ilyen, írjátok meg. A wiki szerint a 8x8-as bontás oka történelmi, az IC technológia ezt tette lehetővé, és mivel bevált, azóta is ez maradt. Máshol azzal magyarázzák, hogy a 16x16 túl komplex lenne. Amennyiben a képet már megfaragtuk és már nem osztható maradéktalanul nyolccal, a csonka (<8pixel) blokkokat kiegészíti (padding), hogy a műveleteket el tudja végezni, majd trimmeli, hogy te ne vedd észre a trükköt

3. DCT - diszkrét koszinusz transzformáció, na ez a rész eddig a legdurvább, pedig ha sikerül megérteni, akkor egyszerű. Mindenesetre nem azért diszkrét, mert kevesen értik és azok sem beszélnek róla. Tele van vele az internet.

Lényege, hogy az adatokat különböző frekvenciájú koszinusz hullámokkal írja le. OK, mindjárt találunk rajta fogást. Lássuk mit értünk a képen kis és nagyfrekvencia alatt.

A képen alacsony frekvencia (luminanciában vagy kromában) jellemzi azokat a területeket, ahol a változás lassan (nagyobb felületen) következik be (pl. egy világoskék ég degradéja a sötétebb felé), vagyis itt nagy a hullámhossz. Nagy frekvencia jellemzi viszont a finom részleteket, ahol a változás akár pixelről pixelre történik (pl. apró pixelméretű fűszálak, pixelméretű sakktábla), ez rövid hullámhossz. A nagy frekvenciás komponensek a zaj-szerű képződmények, kis frekvenciásak a blokkon átívelő képződmények.
Más megközelítésben a képi elemek szélei mentén nagyfrekvenciás (pl egy lapi széle), a homogén felületeken alacsony frekvenciás komponensek vannak (a lapi felülete, amennyiben nem durván textúrás, mert az szintén magas frekvencia lenne).

Azt olvastuk, hogy az emberi látás sajátossága, hogy a szélek érzékelése lerontja a veszteségből adódó hibák észlelését, sokkal feltűnőbbek, idegesítőbbek a veszteségek a homogén felületeken. Ezt lehet ha majd később ellenőrizzük, egyelőre elfogadjuk. Ha sikerül szétválogatni a kép (még mindig 8*8 pixelről van szó!) komponenseit frekvenciák szerint, akkor külön lehet kigyomlálni a nagy- és kisfrekvenciás összetevőket, a nagyokat sokkal jobban lehet ritkítani, az alacsonyabbakat kevésbé, az emberi szem érzékenységével és a vállalt veszteséggel összhangban.
Nagyobb és kisebb frekvenciás blokkok a kép különböző részeiről.
Mellesleg a hibrid képek is az emberi látásnak ezen a jellegzetességén alapulnak, egyik képnek az alacsony, másiknak a magas frekvenciájú komponenseit keverik össze, de hibrid képekről majd máskor lesz szó.

Lássuk gyakorlatban a fenti elméletet. A képlettel inkább nem fárasztom magunkat. Inkább sok-sok képernyőképpel fárasztom. Nekünk így sikerült megérteni a dolgot. Egy dimenzió mentén így lehet leírni hullámmal egyetlen pixelsort.
Forrás 

Forrás. Példaként egyetlen dimenzió mentén a képpontok ezzel a hullámmal írhatóak le jó közelítéssel. 
(A mélyebbre hatoló anyagok a neten mind megmagyarázzák, miért is nem Fourier transzformációt használunk, de mivel bennünk fel nem merült volna, hogy magunktól azt használjuk, ezért arra nem térünk ki).
A fenti két példa végtelenül leegyszerűsített, egyetlen pixelsort mutat, olyan szerencsés értékekkel amelyek egyetlen függvénnyel leírhatóak. A valós képeken bonyibb a helyzet, egyetlen függvénnyel általában nem írhatóak le teljesen, de több függvényt kombinálva kialakítható a megfelelő alakzat:
Forrás. Itt két függvénnyel (piros görbék) írja le a komplexebb fehér görbét.
A koszinusz függvény a képekre (és hangokra) nagyon jól alkalmazható, a valós (organikus) képek viszonylag kevés koszinusz függvénnyel leírhatóak. Egy nyolc pixeles sor legfeljebb 8 darab függvény kombinálásával. De nekünk 8*8 pixeles tömbünk van, tehát a transzformáció két dimenzió mentén történik (x és y tengely), tehát 64 lehetséges függvényünk van, ami a blokkot leírhatja.
Tehát 64 darab adat helyett  (amit egyenként 8 biten kódoltunk 0-255 lépésben), most lett 64 másik adatunk, amiket már  jóval több biten tárolunk (-1024-től 1023 szintek). Egyelőre nagyobb lett csak az adathalmaz, de majd később ez is megoldódik.

Az ábra engem sokáig megtévesztett, a 64 különféle függvény patterneit egymáson kell elképzelni, egymás hatását erősíteni illetve lerontani fogják, így jön ki a végleges 8*8 pixeles kép. Természetesen nem minden esetben használjuk az összeset. Amennyiben csak a bal felső pontunkhoz (DC) rendelünk értéket, az összes többi 63 mező (AC értékek) a mátrixban nullás, akkor a 8*8 pixelünk gyakorlatilag olyan tónusú lesz, mint a bal felső érték. Sima homogén tömb. Ha csak a bal felső és jobb szomszédja kap értéket, akkor egy vízszintes átmenet fog megjelenni a blokkunkon és így tovább.

Összegezve, a bal felső pont kitüntetett (DC) ez a tömbünknek az átlaga. A többi érték (AC) azt adja meg, hogy az adott függvény milyen mértékben (egyáltalán, kicsit, nagyon) vesz részt a blokk kialakításában. A wiki példája egy 8*8 pixeles A betűt ír le. Az alábbi táblázat pedig azt mutatja, hogy az A betű formáját melyik függvény milyen arányban írja le.

Forrás. A wiki példája egy DCT mátrixra, ami egy A betűt formáz.
Van ott mozgó-gif is,
nem lopom ide azt is, de nézzétek meg, szemléletes.
Ez azért jó, mert egy 8x8-as blokkban általában nincs nagy szórás, valós esetben a blokkokban egymáshoz elég közeli pixelértékek szoktak lenni (az AC értékek nem lesznek túl nagy számok, ez a későbbiekben jól jön).
Ugyanaz a képrészlet 0 illetve 12-es tömörítéssel.
Ilyen brutális kvantálás mellett az alapfüggvények elég jól kivehetőek annak ellenére, hogy
ez már itt RGB-ben van.
Ha minden forrást végigolvastál és néztél, és még mindig gondot okoz a lényeg megsejtése, akkor van ez a jó kis jávás eszköz, amivel vizualizálni lehet a DCT-t. A DCT -1024..+1023 között vehet fel értéket, a kép meg 0..255 között.

Fehér blokk esetén a DC is maximális, az AC-k viszont zérósok, a képen nincs semmilyen eltérés.


Fekete blokk esetén a DC is mnimális, az AC-k viszont zérósok, a képen nincs semmilyen eltérés.

A blokk egyetlen fekete pixelt tartalmaz, 1x0+63*255/64 = 98%.
A baloldalon tehát megjelent a blokk átlaga (2048-nak a 98%-a) = 984 (-1024-től)
Az alacsony frekvenciás értékek -44-től haladnak  a nagyok felé -2-ig (jobb alsó sarok)
(alig 2-3%változás van a teljes blokkon, a képen szinte egybefüggő szürkének látszik, de nem az). 

A DC a blokk tónusának átlaga, látszik, hogy x tengelyen nincs AC,
y tengelyen is leginkább az alacsony frekvencia  (második sötét pötty) dominál a lassú átmenet miatt

Itt az x tengelyen a nagyfrekvenciák dominánsak (főleg a jobboldali érték miatt), y tengelyen meg semmi történik.


Az előbbi pattern inverze. Itt is a jobboldali magas frekvenciás függvény dominál de ellenkező előjellel (jobboldali fehér) 








































A DCT transzformáció oda-vissza, a leírások szerint nem okoz veszteséget, annyira nem látjuk át, hogy ezt cáfoljuk. Igazán kockáknak az internet tele van programkódokkal, mi ennél jobban nem akarunk belemenni. Különben is 17 éve programoztunk utoljára, miért pont most kezdenénk újra.