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.

