FastAntialiasing - 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

FastAntialiasing

antialias

16. srpna 2002, 00.00 | Pokračování tématu práce s grafikou a speciálně antialiasingu. V dnešním díle se budeme zabývat kritickou otázkou celé problematiky, a tou je rychlost zpracování. Zrychlení si pak můžete otestovat i na přiložené ukázkové aplikaci.

Všichni z Vás co četli první část tohoto článku a to článek Aliasing a Antialiasing již určitě vědí, o co půjde v příštích pár odstavcích. Dokonce se mezi čtenáři našel člověk, který na velký nedostatek Antialiasingu presentovaném v minulém díle upozornil a také již naznačil možnost jeho řešení. Tímto zmiňovaným nedostatkem je samozřejmě rychlost. A protože je antialiasing velmi častá věc v počítačové grafice, tak není možné, abychom na jeho provedení čekali v případě mého PC (750MHz) 5-6s.
Uvědomme si nejprve, čím je ono zpoždění způsobeno. Vždyť algoritmus jen přečte barvu a pak jednoduchou aritmetickou operací vypočítá barvu druhou,kterou zase zapíše. Právě zde je ale zakopán pes. Naši barvu totiž čteme a zapisujeme vlastností objektu TCanvas Pixels.
Tato vlastnost požívá pro čtení funkci GetPixel a pro zápis proceduru SetPixel definované:

function GetPixel(X, Y: Integer): TColor;
procedure SetPixel(X, Y: Integer; Value: TColor);

Obě metody musejí spolupracovat s pamětí grafické karty (číst, zapisovat) a tato operace je obzvláště pomalá a během antialiasingu se provádí výška x šířka –krát. Můsíme tedy vymyslet způsob jak všechny nebo alespoň většinu údajů z grafické paměti přečíst (zapsat) najednou. K tomu nám pomůže vlastnost objektu TBitmap ScanLine. Metoda Scan line je definovaná:
ScanLine[Row: Integer]: Pointer;
a bude zřejmě třeba použití této metody lehce objasnit. Vstup metody je snad jasný. Row nám označuje řádek bitmapy, který chceme číst (zapisovat). Zajímavější je výstup. Metoda vrací ukazatel na adresovaný řádek (Row), který je již ale uložen v operační paměti. Je dobré vědět, že řádek bitmapy uložený v grafické paměti není pouze pole barev. Grafická karta pracuje přímo se složkami RBG a proto má každý pixel uložený jako strukturu RGB typu TRGBTriple. Nyní již víme dost na to abychom mohli s metodou ScanLine pracovat. Pro usnadnění si zavedeme nový typ.

type
  pRGBArray  =  ^TRGBArray;
  TRGBArray  =  ARRAY[0..high(smallint)] OF TRGBTriple;

PRGBArray je ukazatel na řádek bitmapy, který nám vrátí metoda ScanLine. A high(smallint) nám vrátí maximální velikost typu smallint. Je to proto, že na starších počítačích a hlavně ve starších verzích Delphi je max. počet prvků pole omezen velikostí integru a ta je na 16.bit Delphi právě smallint. K samotnému algoritmu budeme potřebovat tyto proměnné: Row1, Row2, Row3, DestRow: pRGBArray; Row1-3 jsou řádky bitmapy která je kreslená v 3-násobném rozlišení a DesRow je potom výsledný řádek. Bude také nutné si vytvořit nové 2 bitmapy protože je nutné aby byly v 24-bit formátu, jinak metoda ScanLine nefunguje. Pokud by bitmapa měla nastavenou více jak 24-bit paletu, došlo by při zpracování k chybě. Já jsem nové bitmapy nazval big_bmp a out_bmp. Názvy jsou snad jasné. Důležité je jejich správné vytvoření a zinicializování.

  // vytvoreni pomocne bitmapy k presamplovani do vyssiho rozliseni
  big_bmp := TBitmap.Create;
  big_bmp.Width := sirka*z;
  big_bmp.Height := vyska*z;
  big_bmp.PixelFormat := pf24bit; //velice důležitý řádek
  big_bmp.Canvas.Draw(0,0,form1.image3.Picture.Bitmap);

Podobně vytvoříme i ostatní bitmapy. Metoda Draw nám kopíruje bitmapu z komponenty Image do pomocné proměnné. Teď jen pepíšeme náši proceduru antialias z předchozího článku, tak aby fungovala s metodou ScanLine. Je to v podstatě úplně to samé. Některé nejasnosti jsou popsány v komentáři.

// pro všechny řadky
  for y := 0 to vyska - 1 do
  begin
    // načtu si data do proměnných 
    cy := y*z;
    // Vezmu body od aktuálního, následujícího 
    // a ještě následujícího sloupce v přesamplované bitmapě
    Row1 := big_bmp.ScanLine[cy];
    Row2 := big_bmp.ScanLine[cy+1];
    Row3 := big_bmp.ScanLine[cy+2];

    // Vezmu ukazatel na sloupec y
    DestRow := out_bmp.ScanLine[y];

    //pro vsechny radky
        for x := 0 to sirka - 1 do
    begin
      // zpracuju vzorky z 3 x 3 pixelu
      cx := x*z;

      // icializace vysledne barvy
      totr := 0;
      totg := 0;
      totb := 0;

      // Pro vsechny pxely ve vzorku
      for i:=0 to 2 do
      begin
        // nova hodnota cervene
        totr := totr + Row1[cx + i].rgbtRed
             + Row2[cx + i].rgbtRed
             + Row3[cx + i].rgbtRed;
        // nova hodnota zelene
        totg := totg + Row1[cx + i].rgbtGreen
             + Row2[cx + i].rgbtGreen
             + Row3[cx + i].rgbtGreen;
        // nova hodnota modre
        totb := totb + Row1[cx + i].rgbtBlue
             + Row2[cx + i].rgbtBlue
             + Row3[cx + i].rgbtBlue;
      end;

      // nastaveni vyslednych pixelu
      DestRow[x].rgbtRed := totr div 9;
      DestRow[x].rgbtGreen := totg div 9;
      DestRow[x].rgbtBlue := totb div 9;
    end;
  end;

form1.Image2.canvas.Draw(0,0,out_bmp);
//zkopirovani vysledne bitmapy do Image2

Nakonec se nesmí zapomenout uvolnit pomocné proměnné. Výsledný obraz je naprosto totožný i při použití metody Pixels, ale výrazně se celý algoritmus urychlil a to u mě přibližně o 5-6 násobek předchozího času tzn asi na 0,8-1s. Pokud si někteří čtenáři pamatují, že v minulém článku šlo změnou konstanty z dosáhnout efektu Motion Blur, tak je musím upozornit, že v tomto případě je tato možnost možná až po malé úpravě.

Ukázka (190kb)

Tématické zařazení:

 » Rubriky  » Delphi  

 » Rubriky  » Windows  

 

 

 

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

 

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

Uživatelské jméno:

Heslo: