Alpha Blending - Czyli półprzezroczysty obrazek

Bru2s

Co to jest alpha blending? Więc według encyklopedii jest to obliczeniowa technika obróbki grafiki służąca do obliczania przejrzystości elementów obrazu. Pewnie, nie wiele wam to mówi więc postaram się wam to wytłumaczyć na przykładzie. Załóżmy że mamy w 1 komponencie TImage jakąś graficzkę a w drugim mamy jakąś mniejszą. Naszym zadaniem jest nałożenie jednej na drugą ale tak aby ta ze spodu "prześwitywała" przez tą na wierzchu i tu z pomocą przychodzi nam alpha blending. Oto prosty kod w BCB który spełnię to zadanie:

Na formularz wstaw 2 komponenty TImage, 1 TEdit i 1 TButton.

W pierwszym TImage będzie "podkład" czyli grafika która będzie znajdywała się pod spodem. W drugim będzie grafika która znajdzie się na górze.

W zdarzeniu OnClick dla Button1 wstaw taki kod:

int alfa=StrToInt(Edit1->Text); //poziom przezroczystości od 0-255
int r1,g1,b1,r2,g2,b2,rk,gk,bk;  //deklaracja zmiennych
for(int y=0;y<Image2->Height;y++)
for(int x=0;x<Image2->Width;x++)
{
r1=GetRValue(Image1->Canvas->Pixels[x][y]);  //pobieranie czerwonego koloru do zmiennej
g1=GetGValue(Image1->Canvas->Pixels[x][y]); //pobieranie zielonego koloru do zmiennej
b1=GetBValue(Image1->Canvas->Pixels[x][y]); //pobieranie niebieskiego koloru do zmiennej

r2=GetRValue(Image2->Canvas->Pixels[x][y]); //pobieranie czerwonego koloru do zmiennej
g2=GetGValue(Image2->Canvas->Pixels[x][y]); //pobieranie zielonego koloru do zmiennej
b2=GetBValue(Image2->Canvas->Pixels[x][y]); //pobieranie niebieskiego koloru do zmiennej

//obliczanie średniego koloru pixela
rk=(alfa*((r2+64)-r1))/256+r1-(alfa/4); 
gk=(alfa*((g2+64)-g1))/256+g1-(alfa/4);
bk=(alfa*((b2+64)-b1))/256+b1-(alfa/4);

// wyświetlanie wszystkiego w Image1
Image1->Canvas->Pixels[x][y]=RGB(rk,gk,bk);
}

Teraz wystarczy wczytać jakieś obrazki do Image1 i Image2 i skompilować :)

Chodź ten artykuł jest krótki, ale myślę że dość treściwy i komuś się to przyda :) Ponieważ to mój pierwszy artykuł więc nie bądźcie zbyt krytyczni, czekam na wasze komentarze.

10 komentarzy

U mnie kod wygląda tak:

procedure JEDNO_W_DRUGIE(JEDEN,DWA : TBITMAP; var wynik : TBITMAP);
var
  Alfa, x, y : Integer ;
  r1,g1,b1,r2,g2,b2,rk,gk,bk: Integer;
begin

 // Alfa := StrToInt(Edit1.Text); //poziom przezroczystości od 0-255

  for y := 0 to JEDEN.Height do
    for x:= 0 to JEDEN.Width do
    begin
    Alfa := 255*(y div JEDEN.HEIGHT);
      r1:=GetRValue(JEDEN.Canvas.Pixels[x, y]); //pobieranie czerwonego koloru do zmiennej
      g1:=GetGValue(JEDEN.Canvas.Pixels[x, y]); //pobieranie zielonego koloru do zmiennej
      b1:=GetBValue(JEDEN.Canvas.Pixels[x, y]); //pobieranie niebieskiego koloru do zmiennej

      r2:=GetRValue(DWA.Canvas.Pixels[x, y]); //pobieranie czerwonego koloru do zmiennej
      g2:=GetGValue(DWA.Canvas.Pixels[x, y]); //pobieranie zielonego koloru do zmiennej
      b2:=GetBValue(DWA.Canvas.Pixels[x, y]); //pobieranie niebieskiego koloru do zmiennej

      //obliczanie średniego koloru pixela
      rk:=(alfa*((r2+64)-r1)) div 256 + r1 - (alfa div 4);
      gk:=(alfa*((g2+64)-g1)) div 256 + g1 - (alfa div 4);
      bk:=(alfa*((b2+64)-b1)) div 256 + b1 - (alfa div 4);

      // wyświetlanie wszystkiego w Image1
      wynik.Canvas.Pixels[x, y]:=RGB(rk,gk,bk);
    end;
end;

Jak wstawie stałą wartość ALFA to działa a jak nie to nie działa WTF? FFS? :}

CZemu nie ma podanychwartosci jaiie moze przyjac Alfa bo ja dfalem coś takiego 255*(y/wysokosc_obrazka) i wyszlo na tyle ze w ogole nie mam przezroczystosci tylko ten sam obrazek :C

4x dłuższego też;-)

To mam dla Was coś czterdziestokrotnie szybszego (mojej produkcji):

function MonoAlfa(source, dest, fade : word) : byte;
   // result := fade * (dest - source) / 256 + source;
   // zwraca składową koloru z zastosowaniem efektu Alpfa-Blending

asm
    push ebx
    mov ebx, 0
    mov bx, source
    sub dest, source
    mov ax, dest
    mul fade
    shr ax, 8          // ax / 256
    add ax, bx
    pop ebx
end;

procedure rysujAlfa(punkt : TPunkt; fade : real; rysunek : TBitmap; plotno : Tcanvas);
var x, y : integer;
    tempBmp, bmp : TBitmap;
    linia, linia2, linia3 : PByteArray;
    fade256 : integer;

begin
      fade256 := trunc((1-fade)*256);

      tempBmp := TBitmap.Create;
      bmp := TBitmap.Create;
      tempBmp.Width := rysunek.Width;
      bmp.Width := rysunek.Width;
      tempBmp.Height := rysunek.Height;
      bmp.Height := rysunek.Height;
      bmp.Canvas.CopyRect(rect(0, 0, rysunek.width, rysunek.height), plotno, rect(round(punkt.x), round(punkt.y), round(punkt.x)+rysunek.width, round(punkt.y)+rysunek.height));

      if fade = 1 then plotno.Draw(round(punkt.x), round(punkt.y), rysunek) else
      try
        tempBmp.PixelFormat:=pf24Bit;
        Bmp.PixelFormat:=pf24Bit;
        rysunek.PixelFormat:=pf24Bit;
        for y := 0 to rysunek.height - 1 do
                begin
                  linia  := bmp.ScanLine[y];
                  linia2 := rysunek.ScanLine[y];
                  linia3 := tempBmp.ScanLine[y];
                  x := 0;
                  repeat
                       linia3[x]   := MonoAlfa(linia2[x],linia[x],fade256);
                       linia3[x+1] := MonoAlfa(linia2[x+1],linia[x+1],fade256);
                       linia3[x+2] := MonoAlfa(linia2[x+2],linia[x+2],fade256);
                       x := x + 3;
                  until x > (rysunek.Width-1)*3;
                end;
        plotno.Draw(round(punkt.x),round(punkt.y),tempBmp);
        except
          on E: Exception do obslugaWiadomosci('Nie mogę narysować bitmapki alfa z powodu : '+E.Message);
        end;
        bmp.free;
        tempBmp.free;
end;

U mnie działa nawet jeśli mapy są o różnych ilościach kolorów ;) Jedyny warunek to to że muszą to być bitmapy

Robilem juz blending, ale w delphi i obliczanie przejscia w asemblerze. Powinienes dodac jeszcze, ze obie mapy musza miec jednakowa ilosc kolorow. Ciezko jest blending robic dla map <= 255 kolorow.

No i wszystko jasne :)

var
  alpha, r1, b1, g1, r2, g2, b2, rk, gk, bk:extended;
  x, y: integer;
begin
image1:= TBitmap.Create;
bcg:= TBitmap.Create;
bcg.LoadFromFile('cos');
image1.LoadFromFile('cos');
alpha:= tb.Position; //trackbar
for y:= 0 to image1.Height do
begin
  for x:= 0 to image1.Width do
  begin
    r1:=GetRValue(bcg.Canvas.Pixels[x, y]); //pobieranie czerwonego koloru do zmiennej
    g1:=GetGValue(bcg.Canvas.Pixels[x, y]); //pobieranie zielonego koloru do zmiennej
    b1:=GetBValue(bcg.Canvas.Pixels[x, y]); //pobieranie niebieskiego koloru do zmiennej

    r2:=GetRValue(Image1.Canvas.Pixels[x - yt.Position, y - xt.Position]); //pobieranie czerwonego koloru do zmiennej
    g2:=GetGValue(Image1.Canvas.Pixels[x - yt.Position, y - xt.Position]); //pobieranie zielonego koloru do zmiennej
    b2:=GetBValue(Image1.Canvas.Pixels[x - yt.Position, y - xt.Position]); //pobieranie niebieskiego koloru do zmiennej

    // obliczanie średniego koloru
    rk:=(alpha*((r2+64)-r1))/256+r1-(alpha/4);
    gk:=(alpha*((g2+64)-g1))/256+g1-(alpha/4);
    bk:=(alpha*((b2+64)-b1))/256+b1-(alpha/4);

    bcg.Canvas.Pixels[x, y]:=RGB(floor(rk),floor(gk),floor(bk));
  end;
end;
   img.Picture.Bitmap:= bcg;
   image1.Free;
   bcg.Free;
var
  Alfa, x, y : Integer ;
  r1,g1,b1,r2,g2,b2,rk,gk,bk: Integer;
begin

  Alfa := StrToInt(Edit1.Text); //poziom przezroczystości od 0-255

  for y := 0 to Image1.Height do
    for x:= 0 to Image1.Width do
    begin
      r1:=GetRValue(Image1.Canvas.Pixels[x, y]); //pobieranie czerwonego koloru do zmiennej
      g1:=GetGValue(Image1.Canvas.Pixels[x, y]); //pobieranie zielonego koloru do zmiennej
      b1:=GetBValue(Image1.Canvas.Pixels[x, y]); //pobieranie niebieskiego koloru do zmiennej

      r2:=GetRValue(Image2.Canvas.Pixels[x, y]); //pobieranie czerwonego koloru do zmiennej
      g2:=GetGValue(Image2.Canvas.Pixels[x, y]); //pobieranie zielonego koloru do zmiennej
      b2:=GetBValue(Image2.Canvas.Pixels[x, y]); //pobieranie niebieskiego koloru do zmiennej

      //obliczanie średniego koloru pixela
      rk:=(alfa*((r2+64)-r1)) div 256 + r1 - (alfa div 4);
      gk:=(alfa*((g2+64)-g1)) div 256 + g1 - (alfa div 4);
      bk:=(alfa*((b2+64)-b1)) div 256 + b1 - (alfa div 4);

      // wyświetlanie wszystkiego w Image1
      Image1.Canvas.Pixels[x, y]:=RGB(rk,gk,bk);
    end;
end;

Heh :) Tylko jak to przetlumaczyc na Delphi :D