Aliasing a antialiasing - Builder.cz - Informacni server o programovani

Odběr fotomagazínu

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:



Delphi

Aliasing a antialiasing

antialias

22. července 2002, 00.00 | Dnešním článkem načneme téma zpracování grafiky v programování. Ukážeme si, jak vyhladit obrázek pomocí techniky antialiasingu. Což si budete moci sami zkusit v přiloženém programu či zapracovat do vlastního díla díky přístupným zdrojovým kodům..

{Úvod, seznámení}

Na začátku bude nutné se alespoň malou chvíli zaobírat teorií vzorkování, přesněji teorií vzorkování obrazu v počítači. Určitě většina z Vás ví, že obraz je v PC reprezentován diskrétně, tzn. Není spojitý a tudíž se nedá vyjádřit pomocí jakékoliv spojité funkce. A tudíž je vždy omezen určitými parametry. Pro nás je to nejčastěji rozlišení monitoru, které způsobuje, že výsledný obraz je tvořen malinkými čtverci neboli vzorky obrazu. Nyní se již vrátím k pojmům aliasing a antialiasing. Pro ty co neví co si pod těmito pojmy představit, můžu jedině poradit, aby si vzpomněli na legendární hru Quake 3 aréna, kde antialiasing hrál nemalou část výpočtu celkového obrazu a při jeho vypnutí hra běhala sic svižněji, ale zato vypadala jako kdyby byla vytvořena kdysi dávno v časech 486-tek. Ti z Vás co ani teď ještě netuší co výše zmiňované pojmy znamenají budou muset číst dál. Alias je jedním z největších problémů v počítačové grafice a já se nyní pokusím ukázat Vám postup jakým ho alespoň trochu potlačit a minimalizovat. Antialias je potom postup, pomocí kterého se alias snažíme eliminovat. Alias vzniká 2 způsoby, ale bavit se budeme jen o jednom, protože s tím druhým stejně moc dělat nejde.

Příčiny vzniku:

  • původní funkce obrazu je frekvenčně neomezená, proto není možné najít takovou vzorkovací frekvenci aby byly vzorky možné zobrazit v diskrétní mřížce rastru tvořené obrazem monitoru
  • původní funkce obrazu je frekvenčně omezená, ale my ji vzorkujeme s frekvenci nižší, než je dvojnásobek maximální frekvence funkce obrazu (viz. Shannonův vzorkovací theorém)

poznámka. : pod funkcí obrazu je možné si představit třeba funkci sin (x), kterou se snažíte zobrazit na monitoru.

Teď by jsme si mohli rozebrat každý z případů. Začnu druhým. Vezměme si funkci sin(x) a tu budeme chtít nakreslit. Pro kreslení v počítači ale musíme znát hodnotu funkce v každém bodě. Proto pustíme časovou osu a budeme odebírat vzorky (vzorkovat). Pokud bude sin(x) probíhat s malým kmitočtem, tak se nám podaří zobrazit funkci téměř správně, ale pokud by kmitočet vzrostl tak, ze stihneme vzít jen 2 vzorky, tak podle toho kdy vzorky uděláme můžeme dostat např. : dva trojúhelníky nebo jen rovnou čáru. Tento jev znají snad všichni, ale většina neví, že je způsoben právě aliasingem. Vzpomeňte si na pohyb kol u rozjíždějícího se auta v televizi. Ze začátku se kola točí normálně pak chvíli stojí a pak se dokonce točí naopak. To vše jsou příčiny tohoto druhu aliasingu.

Na obrázcích jsou červeně označeny místa odebrání vzorku.


Při správném vzorkování.


Při dvou vzorcích -vhodné umístění (je vidět velké zkreslení)


Při dou vzorcích - špatné umístění (obraz již nelze rekostruovat)

A nyní se vrhneme na to co všechny zajímá. Na odstranění Aliasu prvního druhu můžeme použít dvě metody. První z nich spočívá v posunutí aliasu k vyšším frekvencím a druhá převádí alias na šum. (lidské oko reaguje na šum daleko méně, než na nekorektnost obrazu)

Vzorkování s vyšší frekvencí:

Budeme potřebovat 3 bitmapy. První z nich reprezentuje samotný obraz, druhá je stená jako první, ale obraz je nakreslen v k-krát větším rozlišení a třetí bude samozřejmě obsahovat výsledek. Třetí bitmapa je nezbytná, jelikož není možné výsledek zapisovat do původní bitmapy, protože se v průběhu výpočtu pracuje s okolními pixely a ty se nesmí měnit. Vložíme proto do formuláře 3 komponenty typu TImage, které nám budou zmiňované bitmapy reprezentovat. Na začátku všechny tři vymažeme a tím zinicializujeme.

{ nastavíme velikost na z násobek}
image3.width:=image1.Width*z; 
image3.Height:=image1.Height*z;

{vymaže obsah všech 3 bitmap}
Image1.Canvas.FillRect(Image1.Canvas.ClipRect);
image2.Canvas.FillRect(Image2.Canvas.ClipRect);
image3.Canvas.FillRect(Image3.Canvas.ClipRect);

Do první bitmapy načteme či nakreslíme libovolný obrázek a do 3 vytvoříme stejný, ale v z násobně větším rozlišení. Já jsem pro názornost použil kružnici a rovné čáry tvořící úhlopříčky bitmapy. Na těchto objektech se aliasing nejvíce projevuje. Zdrojový kód kreslení je zde zbytečné uvádět. Je možné si jej stáhnout na konci článku.

Nyní ještě budeme potřebovat jednu pomocnou funkci, která nám vrátí zvlášť hodnoty RGB určitého pixelu.

procedure SeparateColor(color : TColor;  var r, g, b : Integer);
begin
  r := Byte(color);
  g := Byte(color shr 8);
  b := Byte(color shr 16);
end;
[-more-]{Samotný algoritmus, ukázka}

Samotný algoritmus

procedure AntiAliasing;
var
  x, y: integer; 
  totr, totg, totb,r,g,b:integer; //totr,g,b jsou hodnoty RGB výsledné bitmapy
  i, j: integer;
begin
  //pro všechny řádky
  for y := 0 to form1.image1.Height - 1 do
  begin
  Application.ProcessMessages; // vykreslí již hotový řádek
    //pro všechny sloupce
    for x := 0 to form1.image1.Width - 1 do
    begin
      totr := 0; //inicializuj barvu
      totg := 0;
      totb := 0;

      // přečti barvu ze všech okolních pixelů
      for i := 0 to 2 do
      begin
        for j := 0 to 2 do
        begin
         {oddělíme barevné složky}
          SeparateColor(form1.image3.Canvas.Pixels[(x*z)+j, (y*z)+i], r, g, b); 
          totr := totr + r; //přičti příspěvek u každé složky zvlášť
          totg := totg + g;
          totb := totb + b;
        end;
      end;

      form1.image2.Canvas.Pixels[x,y] := RGB(totr div 9, // nakresli výslednou
                                                         // barvu podělenou 9
                                        totg div 9,
                                        totb div 9);
    end; //konec cyklu pro všechny sloupce
  end; // konec cyklu pro všechny řádky
end;


Zpracování jednoho superpixelu. (vlevo: 9 pixelů před zpracováním; vpravo: 1 pixel ve výsledné bitmapě)

Některé věci budou možná potřeba trochu vysvětlit. Funkce vlastně prochází všechny pixely v bitmapě a pří každém projetí jednoho řádku zavolá metodu ProcessMessages, která nechá okenní aplikaci zpracovat čekající zprávy windows a zajistí nám to, aby okno během výpočtu nezatuhlo a aby šel vidět ihned výsledek. Dál funkce vezme hodnoty barev všech 8 okolních pixelů i s aktuálním 9 pixelem a ty po složkách sečte. Tyto hodnoty RGB se ale potom musí vydělit 9 abychom získali výslednou barvu, kterou přímo uložíme do třetí bitmapy. Připomínám, že se pracuje s bitmapou o 3-násobném rozlišení a proto z 9 pixelů dostaneme pouze 1. Pokud by tomu tak nebylo a bitmapa by byla stejná jako požadovaný obraz dostali bychom logicky 3x menší obraz, jehož zvětšení by vedlo ke ztrátě kvality.


Výsledný obraz po provedení antialiasingu

Na podobném principu, ale v podstatě úplně jinak pracuje známá grafická operace a to Motion Blur . Proto doporučuji zvídavějším čtenářům změnit konstantu z na hodnotu 1 místo 3 a dostanete právě zmiňovanou operaci Motion Blur. K té se ale ještě dostaneme v příštím díle, který bude věnován značnému urychlení a vylepšení antialiasingu.


Výsledný obraz po provedeni Motion Blur

Ukázkový program (včetně zdrojových souborů) [185 kB]

Tématické zařazení:

 » Rubriky  » Delphi  

 » Rubriky  » Windows  

Diskuse k článku

 

Vložit nový příspěvek   Sbalit příspěvky

 

Zatím nebyl uložen žádný příspěvek, buďte první.

 

 

Vložit nový příspěvek

Jméno:

Pohlaví:

,

E-mail:

Předmět:

Příspěvek:

 

Kontrola:

Do spodního pole opište z obrázku 5 znaků:

Kód pro ověření

 

 

 

 

Nejčtenější články
Nejlépe hodnocené články

 

Přihlášení k mému účtu

Uživatelské jméno:

Heslo: