Fotografický magazín "iZIN IDIF" každý týden ve Vašem e-mailu.
Co nového ve světě fotografie!
Zadejte Vaši e-mailovou adresu:
Kamarád fotí rád?
Přihlas ho k odběru fotomagazínu!
Zadejte e-mailovou adresu kamaráda:
C/C++
Z hlubin JPEG
jpeg
6. února 2003, 00.00 | V tomto článku se vrátíme k problematice JPEG komprese a na malém prográmku si ukážeme praktickou funkčnost JPEGu, jeho výhody a nevýhody. Součástí je samozřejmě detailní popis algoritmu, matematické vyjádření a plně funkční ukázkový kod.
V předchozím článku jsme si rozebrali JPEG standard z teoretického hlediska. Jelikož je jméno tohoto serveru builder, tak před tím než se vypravíme do tajů dalších typů grafické komprese, ukážeme si dnes něco víc z praxe a "nabuildujeme" si malý prográmek jenž nám pomůže lépe pochopit výhody nevýhody JPEG komprese.
Kód jsem napsal v Pascalu a měl by být zkompilovatelný pod Delphi5. Základem prográmku je nasledující záznam a z něho pak odvozeno třírozměrné pole:
type TClr=record
red,green,blue:byte;
hue,saturation,brightness:double;
DCTH,
DCTS, DCTB:double;
TCDH, TCDS, TCDB:double;
newred,newgreen,newblue:byte;
end;
var
ClrArray:array[1..1000,1..8,1..8] of
TClr;
Smysl proměnných je asi zřejmý : red, green, blue a newred, newgreen a newblue jsou hodnoty kanálů RGB původního a nového obrázku. Hue,saturation, brigthness a TCDH, TCDS, TCDB jsou hodnoty HSB původního a nového obrázku, ale zřejmě se naskýstá otázka, proč jsou typu double jenž v Delphi zabíra 64 bitů, když se jedná o stupnice s velmi malým rozsahem. Odpověd je jednoduchá, jestli chceme dělat přesnou kompresi je dobré se při výpočtech v co největší míře vyhnout předčasnému zaokrouhlování a zaokrouhlit vše až nakonec.
Další otazník by mohl být nad rozměry pole ClrArray. [1..8,1..8] jsou rozměry matice s níž se v JPEG pracuje a první rozměr 1..1000 slouží jen jako jakýsi index k definici s kterým čtveřečkem [1..8,1..8] zrovna pracujeme.
V samotném kódu se setkáváme více méně jen se dvěma problematickými okamžiky, a to je převod HSB->RGB a zpět a převod HSB na koeficienty DCT a zpět. Převod RGB na HSB je poměrně jednoduchý a je více zpusobů jak jej provést. Tady je jeden z nich:
|
Převod HSB zpátky do RGB je již poněkud zložitější a je vázán na způsob, kterým jsme hodnoty HSB získali.
|
Tak a teď vzhůru do Diskrétní kosinové transformace. Vzoreček jenž jsem uvedl v předchozím díle pochází ze stránek http://www.faqs.org/, ale není tak docela přesný. Úplně správná verze je zde. A jak to vypadá v kódu: (Uvádím zápis jenom pro složku hue ostatní složky jsou identické)
|
Po tomhto kroku máme k dispozici frekvenční matici koeficientů DCT s níž si můžeme dělat co se nám zlíbí. Totiž koeficienty můžeme zaokrouhlovat nebo také rovnou mazat a stejně se nám obrázek podaří znovu získat zpět.
Podívejme se tedy jak vypočítat s frekvenčních koeficientů zpátky hodnoty HSB.V podstatě se jedná o obrácený proces výpočtu DCT jenž se matematicky zapisuje takto. A v kódu pak vypadá následně:
|
Kde je tedy komprese?
Komprese vzniká právě při již zmiňovaném mazání a zaokrouhlování koeficientů. Jestli si zkompilujete přiložený kód, najdete v něm obrázek, při přepočtu kterého jsou odstraněny z frekvenční matice všechny koeficienty [3..8,3..8] resp. jsou nahrazeny nulou. Ukázka zde. Další finta taky je, že i když koeficienty vypočítáváme jako double můžeme je zaokrouhlit a kvalita (mám na mysli lidským okem postřehnutelnou kvalitu) tím neutrpí. Poté je možné koeficienty přenášet jako čísla typu byte. Nebo taky je převést do 7 bitového formátu což si možná příště taky ukážeme. (toto ovšem neplatí pro koeficient [0,0] jehož hodnota je povětšinou větší než 255) Ostatní koeficienty hlavně při zjednodušení škál HSB, viz předchozí díl, by se měly vejít do 7 bitů.Pár slov na závěr.
Kód jenž jsem tady vytvořil není dokonalý a také to není žádný krasopis. To ostatné ani nebylo účelem, snažil jsem se ho spíš napsat tak aby se z něj dalo vyčíst jak dané výpočty zapsat a jak fungují. Použil jsem Pascal ale jestli to bude čtenářům více vyhovovat mohu v příštích dílech pokračovat v C++.zdrojové kody [183 kB]
-
25. listopadu 2012
-
30. srpna 2002
-
10. října 2002
-
4. listopadu 2002
-
12. září 2002
-
25. listopadu 2012
-
28. července 1998
-
31. července 1998
-
28. srpna 1998
-
6. prosince 2000
-
27. prosince 2007
-
4. května 2007