Komprese obrazového signálu

V tomto notebooku si demonstrujeme myšlenku komprese obrazového signálu pomocí harmonických funkcí. Použijeme k tomu upravený původní notebook, ve kterém jsme demonstrovali převod do Fourierových řad. 

V praxi se pro kompresi používá povětšinou Diskrétní kosinová tranformace (DCT), ta je ale příbuzná s demonstrovaným převodem. Rovněž se v praxi zpravidla komprimují čtvercové plochy 8x8 pixelů (zde budeme komprimovat proužek 1x20 pixelů).

ClearAll["Global`*"];
$HistoryLength=2;
Off[NMaximize::cvmit,NIntegrate::"slwcon",NIntegrate::"ncvb"]

Vytvořme si 2 sady vzorků. Sada vzorky1 představuje proužek pixelů z fotografie - přechody jasu nejsou příliš ostré. Sada vzorky2 představuje proužek pixelů z nějaké čárové grafiky - uprostřed bílého pruhu (hodnota jasu 10) jsou 4 pixely černé (hodnota jasu 0), pravděpodobně tento proužek přeťala svislá černá čára o tloušťce 4 pixelů.

perioda=20;
vzorky1={6,5,4,3,3,5,7,8,8,9,7,6,4,3,1,0,2,4,6,8};
vzorky2={10,10,10,10,10,10,10,10,0,0,0,0,10,10,10,10,10,10,10,10};

Pro další práci vyberme nejprve sadu vzorky1 ("fotografie").

vzorky=vzorky1;

Proveďme přípravné práce :

f[t_]:=vzorky[[(IntegerPart[t+1])]]/;0.0≤t<perioda;
f[t_]:=f[t-perioda]/;t≥perioda;
f[t_]:=f[t+perioda]/;t<0;
pl1=Plot[f[t],{t,0,perioda},PlotStyle->{Thick,Hue[0.63]},AxesLabel->{"pixel","jas pixelu"}];
nb=500;
pl2=ListPlot[{#,f[#]}&/@((perioda/nb)*(Range[nb]-1)),PlotStyle->{Hue[0.63],PointSize[0.007]},AxesLabel->{"pixel","jas pixelu"}];
gr1=Graphics[Table[{GrayLevel[f[k+0.5]/10],Rectangle[{k,-2},{k+1,-1}]},{k,0,19}]];

Proužek pixelů vypadá takto :

gr1

Vykresleme si proužek pixelů (pod osou x) společně s hodnotami jasu každého pixelu (nad osou x) :

Show[{pl2,gr1},PlotRange->{{0,20},{-2,10}}]

Nyní spočítáme koeficienty an a bn pro prvních 50 harmonických funkcí. V podstatě podvádíme - oněch 20 pixelů jsme prohlásili za periodu a tváříme se, že se těchto 20 pixelů periodicky opakuje. Pak nám nic nebrání, abychom na takto definovanou "periodickou" funkci aplikovali známý postup.

nHarm=50;
rn=Range[nHarm];
siny=Sin[((2Pi)/perioda)*t*#]&/@rn;
cosiny=Cos[((2Pi)/perioda)*t*#]&/@rn;
a0=(1/perioda)*NIntegrate[f[t],{t,0,perioda}];
an:=(2/perioda)*NIntegrate[f[t]*cosiny[[#]],{t,0,perioda}]&;
aenka=an/@rn;
bn:=(2/perioda)*NIntegrate[f[t]*siny[[#]],{t,0,perioda}]&;
beenka=bn/@rn;
nahrada:=a0+Plus@@Take[aenka*cosiny+beenka*siny,#]&;

Provedeme přípravy na zobrazení :

pln:=Plot[{nahrada[#]},{t,0,perioda},PlotStyle->{Thick,GrayLevel[0]},AxesLabel->{"t","f[t]"}]&;
bodyn:=ListPlot[
Table[{k+0.5,(nahrada[#]/.t->(k+0.5))},{k,0,19}],PlotStyle->{Orange,PointSize[0.015]}]&
grn:=Graphics[
Table[{GrayLevel[(nahrada[#]/.t->(k+0.5))/10],Rectangle[{k,-3.1},{k+1,-2.1}]},{k,0,19}]]&;
vys:=Show[pl2,pln[#],gr1,grn[#],PlotRange->{{0,20},{-4,12}},AxesOrigin->{0,0}]&;
vys2:=Show[pl2,pln[#],bodyn[#],gr1,grn[#],PlotRange->{{0,20},{-4,12}},AxesOrigin->{0,0}]&;

Zobrazme výsledky. Nad osou x  je jas každého vzorku modře a aproximace tohoto průběhu pomocí součtu harmonických funkcí je černě. Pod osou x jsou dva proužky pixelů - horní proužek je originál a spodní proužek je jeho aproximace (která odpovídá černé čáře nad osou).

Manipulate[vys[n],{n,1,nHarm,1}]

U sady pixelů vzorky1 si povšimněme, že již pouhé první dvě harmonické funkce začínají uspokojivě aproximovat originál. V tomto případě by nám stačilo uložit pouhých 5 hodnot koeficientů a0, a1, b1, a2 a b2. Šest harmonických aproximuje průběh dobře a deset harmonických velmi dobře (pouhým okem prakticky nerozeznatelně).

Jako aproximační hodnotu jsme brali pokaždé hodnotu aproximační funkce "uprostřed pixelu", tedy pracovali jsme s oranžově zvýrazněnými hodnotami na následujícím grafu:

Manipulate[vys2[n],{n,1,nHarm,1}]

Nyní si vše znova vyzkoušejte pro sadu pixelů vzorky2 (stačí upravit přiřazení vzorky = vzorky2;)