Kopírovanie a modifikácia obrázkov. Práca s myšou.

03.11.2009 00:00

Kopírovanie a modifikácia obrázkov

Vytvoríme  nový projekt, v ktorom budú dve grafické plochy: Image1 a Image2. Do prvej načítame z nejakého súboru bitmapu a túto potom prekopírujeme do druhej plochy. Pri kopírovaní ju môžeme rôzne meniť, prípadne meniť spôsoby kopírovania. S obrázkami budeme pracovať ako s dvojrozmerným poľom, pričom prvý index poľa bude vyjadrovať x-ovú súradnicu a druhý index y-ovú súradnicu farebného bodu (voláme ich pixel). Body v grafickej ploche číslujeme od 0 do šírka-1, resp. 0 až výška-1.

  • do formulára vložíme dve grafické plochy Image - upravíme im rozmery tak, aby boli rovnako veľké 250x250
  • do formulára vložíme niekoľko tlačidiel - postupne im budeme priraďovať rôzne funkcie
  • formulár teraz môže vyzerať takto:

Projekt uložíme do priečinka na disku a tiež sem do tohto istého priečinka prekopírujeme niekoľko obrázkov (súborov s príponou .BMP). Tieto súbory si môžete stiahnuť z obrazky.zip. Postupne priradíme tlačidlám Button1, Button2 a Button3 akcie prečítanie bitmapových obrázkov do prvej grafickej plochy Image1:

procedure TForm1.Button1Click(Sender: TObject);
begin
  Image1.Picture.LoadFromFile('panthere.bmp');
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  Image1.Picture.LoadFromFile('perroquet.bmp');
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
  Image1.Picture.LoadFromFile('hory.bmp');
end;

Stavová premenná Pixels (pre Canvas grafickej plochy) nám umožňuje pristupovať k jednotlivým pixelom (farebným bodom) obrázka. Pixels je ako dvojrozmerné pole prvkov typu TColor (farba). Treba si zapamätať, že Pixels má prvý index x-ovú súradnicu (stĺpec) a druhý index y-ovú súradnicu (riadok). Postupne budeme kopírovať obrázok z Image1 do Image2 po riadkoch:

procedure TForm1.Button4Click(Sender: TObject);
var
  x,y: Integer;

begin
  for y := 0 to Image1.Height-1 do
    begin
      for x := 0 to Image1.Width-1 do
       Image2.Canvas.Pixels[x,y] := Image1.Canvas.Pixels[x,y];
       Image2.Repaint;
    end;
end;

Image2.Repaint prekreslí druhú grafickú plochu po prekopírovaní každého riadka, aby sa postupne zobrazovali kopírované riadky (inak by sa zobrazila až záverečná zmena).
Ďalší variant programu využíva funkciu RGB a funkcie pre zistenie farby bodu GetRValue, GetGValue a GetBValue:

procedure TForm1.Button5Click(Sender: TObject);
var
 x,y: Integer;
 farba: TColor;
 R,G,B: Byte;

begin
 for y := 0 to Image1.Height-1 do
   begin
     for x := 0 to Image1.Width-1 do
       begin
         R := GetRValue(Image1.Canvas.Pixels[x,y]);
         G := GetGValue(Image1.Canvas.Pixels[x,y]);
         B := GetBValue(Image1.Canvas.Pixels[x,y]);
         Image2.Canvas.Pixels[x,y] := RGB(R,G,B);
         Image2.Repaint;
       end;
   end;
end;

Funkcia GetRValue vráti červenú zložku farby, podobne GetGValue a GetBValue vrátia zelenú a modrú zložku. Konkrétne tento príklad neurobí nič iné, ako skopíruje obrázok z Image1 do Image2.

Tu môžete experimentovať s farbami:

  • niektorú zložku vynulovať,

procedure TForm1.Button6Click(Sender: TObject);
var
 x,y: Integer;
 farba: TColor;
 R,G,B: Byte;

begin
 for y := 0 to Image1.Height-1 do
   begin
     for x := 0 to Image1.Width-1 do
       begin
         R := GetRValue(Image1.Canvas.Pixels[x,y]);
         G := GetGValue(Image1.Canvas.Pixels[x,y]);
         B := 0;
         Image2.Canvas.Pixels[x,y] := RGB(R,G,B);
         Image2.Repaint;
       end;
   end;
end;

  • niektorú zložku vydeliť dvomi,

procedure TForm1.Button7Click(Sender: TObject);
var
 x,y: Integer;
 farba: TColor;
 R,G,B: Byte;

begin
 for y := 0 to Image1.Height-1 do
   begin
     for x := 0 to Image1.Width-1 do
       begin
         R := GetRValue(Image1.Canvas.Pixels[x,y]);
         G := GetGValue(Image1.Canvas.Pixels[x,y]);
         B := GetBValue(Image1.Canvas.Pixels[x,y]);;
         Image2.Canvas.Pixels[x,y] := RGB(R,G div 2,B);
         Image2.Repaint;
       end;
   end;
end;

  • všetky tri zložky spriemerovať (vznikne čiernobiely obrázok).

procedure TForm1.Button8Click(Sender: TObject);
var
 x,y: Integer;
 farba: TColor;
 R,G,B,P: Byte;

begin
 for y := 0 to Image1.Height-1 do
   begin
     for x := 0 to Image1.Width-1 do
       begin
         R := GetRValue(Image1.Canvas.Pixels[x,y]);
         G := GetGValue(Image1.Canvas.Pixels[x,y]);
         B := GetBValue(Image1.Canvas.Pixels[x,y]);
         P := (R+G+B) div 3;
         Image2.Canvas.Pixels[x,y] := RGB(P,P,P);
         Image2.Repaint;
       end;
   end;
end;

Ak sa stane, že grafická plocha pri každom prekresľovaní veľmi bliká, vtedy pomôže riadok, ktorý pridáme do procedúry FormCreate (táto procedúra sa vytvorí napr. dvojklikom do formulára na prázdne miesto bez komponentu):

procedure TForm1.FormCreate(Sender: TObject);
begin
  DoubleBuffered := True;
end;

Práca s myšou

V Delphi sa s myšou pracuje pomocou udalostí, ktoré automaticky vznikajú pri každom pohybe myši na obrazovke – OnMouseMove. Pri pohybe myši túto udalosť dostáva ten komponent formulára, nad ktorým sa myš práve nachádza (napr. grafická plocha alebo tlačidlo). Procedúra, ktorá sa vyvolá ako reakcia na udalosť pohyb myši, dostáva ako parametre aj súradnice myši (X, Y) - tieto sú vždy relatívne vzhľadom na ľavý horný roh komponentu - v grafickej ploche sú to normálne grafické súradnice bodu.
Napíšeme procedúru, ktorá sa zavolá vždy, keď pohneme kurzorom myši nad plochou Image2 - táto procedúra prekopíruje len jednu bodku z Image1 a to presne bodku z pozície myši. Najprv vo formulári klikneme na Image2 a potom v Inšpektore Objektov prepneme záložku  Events a dvojklikneme na pravú časť riadka s OnMouseMove:

Pripraví sa procedúra TForm1.Image2MouseMove, do ktorej napíšeme, čo všetko chceme urobiť pri každom pohnutí myši nad plochou Image2:

procedure TForm1.Image2MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
 Image2.Canvas.Pixels[X,Y] := Image1.Canvas.Pixels[X,Y];
end;

Aby sa pri pohybe neobjavovala len malá bodka ale nejaké okolie bodu, môžeme zapísať:

procedure TForm1.Image2MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
const
  D = 10;

var
  XX,YY: Integer;

begin
 for XX := X-D to X+D do
   begin
     for YY := Y-D to Y+D do
       Image2.Canvas.Pixels[X,Y] := Image1.Canvas.Pixels[X,Y];
   end;
end;

Upravme procedúru tak, aby sa body kopírovali len vtedy, keď je stlačené ľavé tlačidlo myši. Využijeme na to parameter Shift , ktorý je množinového  typu TShiftState, ktorý je definovaný takto:

type
  TShiftState = set of (ssShift, ssAlt, ssCtrl, ssLeft, ssRight, ssMiddle, ssDouble);

Parameter Shift môže mať napr. tieto hodnoty:

Shift = []                    // nezatlačili sme žiadne tlačidlo
Shift = [ssLeft]              // zatlačili sme len ľavé tlačidlo
Shift = [ssRight]             // zatlačili sme len pravé tlačidlo
Shift = [ssLeft, ssRight]     // zatlačili sme naraz obe tlačidlá

V tomto parametri sa môžeme dozvedieť či sú zatlačené tlačidlá myši ale aj niektoré špeciálne klávesy na klávesnici (Shift, Alt alebo Ctrl).

procedure TForm1.Image2MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
const
  D = 10;

var
  XX,YY: Integer;

begin
 if Shift = [ssLeft] then
 begin
   for XX := X-D to X+D do
     begin
       for YY := Y-D to Y+D do
         Image2.Canvas.Pixels[X,Y] := Image1.Canvas.Pixels[X,Y];
     end;
 end;
end;

Dodefinujme ešte procedúru, ktorá zmaže grafickú plochu Image2, keď stlačíme pravé tlačidlo myši. Použijeme na to udalosť, ktorá vznikne vždy keď stlačíme tlačidlo myši – OnMouseDown.
V procedúre  názvom TForm1.Image2MouseDown otestujeme či bolo stlačené pravé tlačidlo myši. Ak áno zmažeme grafickú plochu Image2.

procedure TForm1.Image2MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if Shift = [ssRight] then
    begin
      Image2.Canvas.Brush.Color := clWhite;
      Image2.Canvas.FillRect(Image2.ClientRect);
    end;
end;

Ak chceme vidieť aktuálne súradnice kurzora myši pri pohybe nad plochou Image2, pridáme do formulára komponent Label a do procedúru Form1.Image2MouseMove upravíme nasledovne:

procedure TForm1.Image2MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
const
  D = 10;

var
  XX,YY: Integer;

begin
 if Shift = [ssLeft] then
 begin
   for XX := X-D to X+D do
     begin
       for YY := Y-D to Y+D do
         Image2.Canvas.Pixels[X,Y] := Image1.Canvas.Pixels[X,Y];
     end;
 end;
 Label1.Caption := 'X: '+IntToStr(X)+', Y: '+IntToStr(Y);
end;

Späť

Vyhľadávanie

(c) 2008 Všetky práva vyhradené.