Nadesłany przez Andrzej Borucki, 25 lipca 2013 20:01
Kod przedstawiony poniżej przedstawia główną część rozwiązania problemu.Pobierz pełne rozwiązanie.
Jeżeli nie odpowiada Ci sposób formatowania kodu przez autora skorzystaj z pretty printer'a i dostosuj go automatycznie do siebie.
Morphing - Delphi/MorphUnit.pas:
//Morhping //www.algorytm.org unit MorphUnit; // {$MODE Delphi} interface uses Messages, SysUtils, Variants, Classes, Controls, Forms, Dialogs, ExtCtrls, StdCtrls, ComCtrls, Graphics, Buttons; var lambda:real=0.5; a: real; type //punkty charakterystyczne TChPoint = record px,py: integer; //pierwszt obraz qx,qy: integer; //drugi obraz tx,ty: single; //trzeci obraz rpx,rpy: single; rqx,rqy: single; end; PChPoint = ^TChPoint; //punkt czesciowo dodany THangPoint = record px,py: integer; //pierwszt obraz filledP: boolean; qx,qy: integer; //drugi obraz filledQ: boolean; end; TForm1 = class(TForm) btLoad: TButton; btProc: TButton; ProgressBar1: TProgressBar; imgLeft: TImage; imgRight: TImage; GaugeBar1: TTrackBar; imgEffect: TImage; Edit1: TEdit; GaugeBar2: TTrackBar; Edit2: TEdit; ListView: TListView; btnDelete: TBitBtn; OpenDialog: TOpenDialog; procedure btLoadClick(Sender: TObject); procedure btProcClick(Sender: TObject); procedure imgLeftMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure imgRightMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure GaugeBar1Change(Sender: TObject); procedure GaugeBar2Change(Sender: TObject); procedure ListViewSelectItem(Sender: TObject; Item: TListItem; Selected: Boolean); procedure btnDeleteClick(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FormCreate(Sender: TObject); private LeftImageName,RightImageName: string; ChPointList: TList; hangPoint: THangPoint; datFilename: string; procedure readTrans; procedure FreePointList; procedure ComputeTargetPoints; public procedure FindCoords(tx,ty:integer; var px,py,qx,qy: integer); procedure PointsToListView; end; var Form1: TForm1; implementation uses Math; {$R *.dfm} procedure TForm1.FreePointList; var i:integer; begin if ChPointList=nil then exit; for i:=0 to ChPointList.Count-1 do Dispose(PChPoint(ChPointList[i])); ChPointList.Free; ChPointList:=nil; end; procedure ValInt(S: PChar; out N,Code: integer); const MaxLen=31; var buf:array[0..MaxLen] of char; begin Code:=0; while (S^ in ['+','-'])and(Code<MaxLen) do begin buf[Code]:=S^; inc(Code); inc(S); end; while (S^ in ['0'..'9'])and(Code<MaxLen) do begin buf[Code]:=S^; inc(Code); inc(S); end; buf[Code]:=#0; N:=StrToInt(buf); while (S^ in ['0'..'9']) do begin inc(Code); inc(S); end; end; procedure TForm1.readTrans; var f:TextFile; line:string; s:PChar; i,code:integer; p: PChPoint; begin FreePointList; ChPointList:=TList.Create; //poniższe może opcjonalnie AssignFile(f,datFilename); Reset(f); i:=0; while not eof(f) do begin readln(f,line); if Line='' then continue; if i=0 then LeftImageName:=Line; if i=1 then RightImageName:=Line; if i>=2 then begin new(p); s:=PChar(line); ValInt(s,p.px,code); s:=s+Code+1; ValInt(s,p.py,code); s:=s+Code+1; ValInt(s,p.qx,code); s:=s+Code+1; ValInt(s,p.qy,code); ChPointList.Add(p); end; inc(i); end; CloseFile(f); end; procedure TForm1.ComputeTargetPoints; var i: integer; begin if ChPointList<>nil then for i:=0 to ChPointList.Count-1 do with PChPoint(ChPointList[i])^ do begin tx:=(1-lambda)*px+lambda*qx; ty:=(1-lambda)*py+lambda*qy; rpx:=px-tx; rpy:=py-ty; rqx:=qx-tx; rqy:=qy-ty; end; end; procedure TForm1.btLoadClick(Sender: TObject); begin OpenDialog.Filter:='*.dat'; OpenDialog.FileName:='*.dat'; if OpenDialog.Execute then datFilename:=OpenDialog.FileName; readTrans; imgLeft.Picture.LoadFromFile(LeftImageName); imgRight.Picture.LoadFromFile(RightImageName); PointsToListView; end; procedure TForm1.FindCoords(tx,ty:integer; var px,py,qx,qy: integer); var invd: real; //odwrotny kwadrat odleglosci i: integer; p: PChPoint; Spx,Spy,Sqx,Sqy,f: real; begin if ChPointList.Count=0 then begin px:=tx; py:=ty; qx:=tx; qy:=ty; exit; end; Spx:=0; Spy:=0; Sqx:=0; Sqy:=0; f:=0; for i:=0 to ChPointList.Count-1 do begin p:=ChPointList[i]; if (tx=p.tx)and(ty=p.ty) then begin px:=p.px; py:=p.py; qx:=p.qx; qy:=p.qy; exit; end; invd := 1/(Sqr(tx-p.tx)+Sqr(ty-p.ty)); Spx := Spx + p.rpx*invd; Spy := Spy + p.rpy*invd; Sqx := Sqx + p.rqx*invd; Sqy := Sqy + p.rqy*invd; f := f+invd; end; px := round(Spx/f+tx); py := round(Spy/f+ty); qx := round(Sqx/f+tx); qy := round(Sqy/f+ty); end; function TruncDown(f: double): int64; begin result:=Trunc(f); if (result <> f) and (f < 0) then result:=result-1; end; function combineColors(const color0, color1:TColor;lambda:real): TColor; var fR,fG,fB: real; begin fR:=(1.0-lambda)*(color0 and $ff)+lambda*(color1 and $ff); fG:=(1.0-lambda)*((color0 and $ff00) shr 8)+lambda*((color1 and $ff00) shr 8); fB:=(1.0-lambda)*((color0 and $ff0000) shr 16)+lambda*((color1 and $ff0000) shr 16); //contrast fR:=a*(fR-128)+128; fG:=a*(fG-128)+128; fB:=a*(fB-128)+128; if fR<0 then fR:=0 else if fR>255 then fR:=255; if fG<0 then fG:=0 else if fG>255 then fG:=255; if fB<0 then fB:=0 else if fB>255 then fB:=255; Result := (round(fB) shl 16)+ (round(fG) shl 8)+ round(fR); end; procedure TForm1.btProcClick(Sender: TObject); var x,y: integer; px,py,qx,qy: integer; color: TColor; begin if ChPointList = nil then exit; btLoad.Enabled:=false; btProc.Enabled:=false; a:=Power(4,GaugeBar2.Position/100); ComputeTargetPoints; for y:=1 to imgEffect.Height-1 do begin for x:=1 to imgEffect.Width-1 do begin FindCoords(x,y, px,py,qx,qy); color:=combineColors(imgLeft.Canvas.Pixels[px,py], imgRight.Canvas.Pixels[qx,qy],lambda); imgEffect.Canvas.Pixels[x,y]:=Color; end; end; btLoad.Enabled:=true; btProc.Enabled:=true; imgEffect.Repaint; end; procedure TForm1.imgLeftMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var item: TListItem; p: PChPoint; i:integer; begin Assert(not hangPoint.filledP or not hangPoint.filledQ); if hangPoint.filledP then begin item:=ListView.Items[ListView.Items.Count-1]; hangPoint.px:=X; item.Caption:=IntToStr(X); hangPoint.py:=Y; item.SubItems[0]:=IntToStr(Y); end else begin if hangPoint.filledQ then begin item:=ListView.Items[ListView.Items.Count-1]; new(p); p.px:=X; item.Caption:=IntToStr(X); p.py:=Y; item.SubItems[0]:=IntToStr(Y); p.qx:=hangPoint.qx; p.qy:=hangPoint.qy; item.Data:=p; ChPointList.Add(p); hangPoint.filledQ:=false; end else begin item:=ListView.Items.Add; for i:=0 to 2 do item.SubItems.Add(''); hangPoint.px:=X; item.Caption:=IntToStr(X); hangPoint.py:=Y; item.SubItems[0]:=IntToStr(Y); hangPoint.filledP:=true; end; end; item.MakeVisible(false); ListView.Selected:=item; ListView.SetFocus; imgLeft.Repaint; imgLeft.Canvas.Ellipse(X-4,Y-4,X+4,Y+4); btProcClick(Sender); end; procedure TForm1.imgRightMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var item: TListItem; p: PChPoint; i:integer; begin Assert(not hangPoint.filledP or not hangPoint.filledQ); if hangPoint.filledQ then begin item:=ListView.Items[ListView.Items.Count-1]; hangPoint.qx:=X; item.SubItems[1]:=IntToStr(Y); hangPoint.qy:=Y; item.SubItems[2]:=IntToStr(Y); end else begin if hangPoint.filledP then begin item:=ListView.Items[ListView.Items.Count-1]; new(p); p.px:=hangPoint.px; p.py:=hangPoint.py; p.qx:=X; item.SubItems[1]:=IntToStr(Y); p.qy:=Y; item.SubItems[2]:=IntToStr(Y); item.Data:=p; ChPointList.Add(p); hangPoint.filledP:=false; end else begin item:=ListView.Items.Add; for i:=0 to 2 do item.SubItems.Add(''); hangPoint.qx:=X; item.SubItems[1]:=IntToStr(Y); hangPoint.qy:=Y; item.SubItems[2]:=IntToStr(Y); hangPoint.filledQ:=true; end; end; item.MakeVisible(false); ListView.Selected:=item; ListView.SetFocus; imgRight.Repaint; imgRight.Canvas.Ellipse(X-4,Y-4,X+4,Y+4); btProcClick(Sender); end; procedure TForm1.GaugeBar1Change(Sender: TObject); begin lambda:=GaugeBar1.Position /100; Edit1.Text:=Format('%4f',[lambda]); GaugeBar1.Repaint; Edit1.Repaint; btProcClick(Sender); end; procedure TForm1.GaugeBar2Change(Sender: TObject); begin a:=Power(4,GaugeBar2.Position/100); Edit2.Text:=Format('%4f',[a]); GaugeBar2.Repaint; Edit2.Repaint; btProcClick(Sender); end; procedure TForm1.PointsToListView; var i: integer; x,y: integer; item: TListItem; begin ListView.Items.Clear; for i:=0 to ChPointList.Count-1 do with PChPOint(ChPointList[i])^ do begin item:=ListView.Items.Add; item.Data:=ChPointList[i]; item.Caption:=IntToStr(px); item.SubItems.Add(IntToStr(py)); item.SubItems.Add(IntToStr(qx)); item.SubItems.Add(IntToStr(qy)); end; end; procedure TForm1.ListViewSelectItem(Sender: TObject; Item: TListItem; Selected: Boolean); var p: PChPoint; begin if not Selected then exit; p:=Item.Data; if p=nil then exit; imgLeft.Repaint; imgLeft.Canvas.Ellipse(p.px-4,p.py-4,p.px+4,p.py+4); imgRight.Repaint; imgRight.Canvas.Ellipse(p.qx-4,p.qy-4,p.qx+4,p.qy+4); end; procedure TForm1.btnDeleteClick(Sender: TObject); var chPoint: PChPoint; begin if ListView.Selected<>nil then begin chPOint:=ListView.Selected.Data; ChPointList.Remove(chPoint); Dispose(chPoint); ListView.Selected.Delete; btProcClick(Sender); end; end; procedure TForm1.FormDestroy(Sender: TObject); begin FreePointList; end; procedure TForm1.FormCreate(Sender: TObject); begin ChPointList := nil; GaugeBar1Change(nil); GaugeBar2Change(nil); end; end.