Skip to content

Commit 3730650

Browse files
committed
add PerspectiveCorrect demo
1 parent 5084a49 commit 3730650

14 files changed

+6627
-94
lines changed

.gitignore

+7-13
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1+
*.identcache
2+
*.stat
3+
*.local
14
/ComponentsSource/__history
25
/Demo/ScrollYearsDemo.dproj.local
3-
/Demo/ScrollYearsDemo.identcache
46
/Demo/__history
57
/Demo/Win32/Debug
68
/ComponentsSource/FMXComponents.dproj.local
7-
/ComponentsSource/FMXComponents.identcache
89
/FMXComponentsGroup.groupproj.local
910
/FMXComponentsGroup_prjgroup.tvsconfig
1011
/ComponentsSource/Win32/Debug
@@ -14,30 +15,19 @@
1415
/Demo/FMXComponentsDemoMain.vlb
1516
/Demo/Android/Debug
1617
/Demo/FMXComponentsDemo.deployproj
17-
/Demo/FMXComponentsDemo.identcache
1818
/Demo/FMXComponentsDemo.stat
1919
/Demo/Win32/Release
20-
/ComponentsSource/FMXComponentEd.dproj.local
21-
/ComponentsSource/FMXComponentEd.identcache
22-
/ComponentsSource/*.stat
2320
/ComponentsSource/FMXComponentEd.res
24-
/Demo/LoadingIndicatorDemo.dproj.local
2521
/Demo/LoadingIndicatorDemo.res
26-
/Demo/LoadingIndicatorDemo.identcache
27-
/Demo/LoadingIndicatorDemo.stat
2822
/Demo/OSX32/Debug
2923
/Demo/FMXGR32DemoProj.res
3024
/ComponentsSource/Android/Debug
3125
/Demo/TestINativeCanvas/Android/Debug
3226
/Demo/TestINativeCanvas/__history
3327
/Demo/TestINativeCanvas/Win32/Debug
34-
/Demo/TestINativeCanvas/TestINativeCanvas.dproj.local
3528
/Demo/TestINativeCanvas/TestINativeCanvas.res
3629
/Demo/TestCallout/TestFMXCallout.stat
37-
/Demo/TestINativeCanvas/TestDrawBitmap.stat
3830
/Demo/TestCallout/TestFMXCallout.identcache
39-
/Demo/TestINativeCanvas/TestINativeCanvas.identcache
40-
/Demo/TestINativeCanvas/TestINativeCanvas.stat
4131
/Demo/RotatingTextDemo/OSX32/Debug
4232
/Demo/RotatingTextDemo/iOSSimulator/Debug
4333
/Demo/TestCallout/OSX32/Debug
@@ -47,3 +37,7 @@
4737
/Demo/TestBezierAnimation/Win32/Debug
4838
/Demo/TestBezierAnimation/Android/Debug
4939
/Demo/TestINativeCanvas/iOSDevice64/Debug
40+
/Demo/PhotoCorrect/Win32/Debug
41+
/Demo/PhotoCorrect/__history
42+
/Demo/PhotoCorrect/PhotoCorrect.res
43+
/Demo/TestBezierAnimation/TestBezierAnimation.res
+346
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,346 @@
1+
unit PerspectiveCorrect;
2+
3+
interface
4+
5+
uses
6+
System.Math,
7+
SimpleSVD,
8+
GR32,
9+
GR32_Transforms,
10+
GR32_Math,
11+
GR32_Blend;
12+
13+
type
14+
TMyProjectiveTransformation = class(T3x3Transformation)
15+
private
16+
FDestHeight: TFloat;
17+
FDestWidth: TFloat;
18+
FQuadX: array [0..3] of TFloat;
19+
FQuadY: array [0..3] of TFloat;
20+
function GetDestHeight: TFloat;
21+
function GetDestWidth: TFloat;
22+
procedure SetX0(Value: TFloat); {$IFDEF UseInlining} inline; {$ENDIF}
23+
procedure SetX1(Value: TFloat); {$IFDEF UseInlining} inline; {$ENDIF}
24+
procedure SetX2(Value: TFloat); {$IFDEF UseInlining} inline; {$ENDIF}
25+
procedure SetX3(Value: TFloat); {$IFDEF UseInlining} inline; {$ENDIF}
26+
procedure SetY0(Value: TFloat); {$IFDEF UseInlining} inline; {$ENDIF}
27+
procedure SetY1(Value: TFloat); {$IFDEF UseInlining} inline; {$ENDIF}
28+
procedure SetY2(Value: TFloat); {$IFDEF UseInlining} inline; {$ENDIF}
29+
procedure SetY3(Value: TFloat); {$IFDEF UseInlining} inline; {$ENDIF}
30+
protected
31+
procedure PrepareTransform; override;
32+
procedure ReverseTransformFixed(DstX, DstY: TFixed; out SrcX, SrcY: TFixed); override;
33+
procedure ReverseTransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); override;
34+
procedure TransformFixed(SrcX, SrcY: TFixed; out DstX, DstY: TFixed); override;
35+
procedure TransformFloat(SrcX, SrcY: TFloat; out DstX, DstY: TFloat); override;
36+
public
37+
function GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect; override;
38+
property DestWidth: TFloat read GetDestWidth;
39+
property DestHeight: TFloat read GetDestHeight;
40+
published
41+
property X0: TFloat read FQuadX[0] write SetX0;
42+
property X1: TFloat read FQuadX[1] write SetX1;
43+
property X2: TFloat read FQuadX[2] write SetX2;
44+
property X3: TFloat read FQuadX[3] write SetX3;
45+
property Y0: TFloat read FQuadY[0] write SetY0;
46+
property Y1: TFloat read FQuadY[1] write SetY1;
47+
property Y2: TFloat read FQuadY[2] write SetY2;
48+
property Y3: TFloat read FQuadY[3] write SetY3;
49+
end;
50+
51+
function getPerspectiveTransform(const src,
52+
dst: TArray<TFloatPoint>): TFloatMatrix;
53+
implementation
54+
55+
function getPerspectiveTransform(const src,
56+
dst: TArray<TFloatPoint>): TFloatMatrix;
57+
const
58+
DECOMP_SVD = 1;
59+
60+
var
61+
A, b, c: TMatrix;
62+
M, N, i: Integer;
63+
svd_deomposition: TSVD;
64+
A_pinv: TMatrix;
65+
Mat: TFloatMatrix;
66+
begin
67+
M := 8;
68+
N := 8;
69+
A := TMatrix.Create(M, N, 'A', TMatrix.AS_MATRIX);
70+
b := TMatrix.Create(M, 1, 'b', TMatrix.AS_VECTOR);
71+
c := TMatrix.Create(N, 1, 'c', TMatrix.AS_VECTOR);
72+
73+
for i := 0 to 3 do
74+
begin
75+
A[i,0] := src[i].X;
76+
A[i+4,3] := src[i].X;
77+
A[i,1] := src[i].Y;
78+
a[i+4,4] := src[i].Y;
79+
A[i,2] := 1;
80+
A[i+4,5] := 1;
81+
A[i,3] := 0;
82+
A[i,4] := 0;
83+
A[i,5] := 0;
84+
A[i+4,0] := 0;
85+
A[i+4,1] := 0;
86+
A[i+4,2] := 0;
87+
A[i,6] := -src[i].x*dst[i].x;
88+
A[i,7] := -src[i].y*dst[i].x;
89+
A[i+4,6] := -src[i].x*dst[i].y;
90+
A[i+4,7] := -src[i].y*dst[i].y;
91+
B.Mat[i] := dst[i].x;
92+
B.Mat[i+4] := dst[i].y;
93+
end;
94+
svd_deomposition := TSVD.Create;
95+
A_pinv := nil;
96+
try
97+
A_pinv := svd_deomposition.PinvCompute(A, A.Rows, A.Cols);
98+
svd_deomposition.multiply(A_pinv, b, c);
99+
Mat[0][0] := c.Mat[0];
100+
Mat[1][0] := c.Mat[1];
101+
Mat[2][0] := c.Mat[2];
102+
Mat[0][1] := c.Mat[3];
103+
Mat[1][1] := c.Mat[4];
104+
Mat[2][1] := c.Mat[5];
105+
Mat[0][2] := c.Mat[6];
106+
Mat[1][2] := c.Mat[7];
107+
Mat[2][2] := 1;
108+
Result := Mat;
109+
finally
110+
A_pinv.Free;
111+
svd_deomposition.Free;
112+
end;
113+
end;
114+
115+
{ TMyProjectiveTransformation }
116+
117+
function TMyProjectiveTransformation.GetDestHeight: TFloat;
118+
begin
119+
if not TransformValid then PrepareTransform;
120+
Result := FDestHeight;
121+
end;
122+
123+
function TMyProjectiveTransformation.GetDestWidth: TFloat;
124+
begin
125+
if not TransformValid then PrepareTransform;
126+
Result := FDestWidth;
127+
end;
128+
129+
function TMyProjectiveTransformation.GetTransformedBounds(
130+
const ASrcRect: TFloatRect): TFloatRect;
131+
var
132+
p0, p1, p2, p3: TFloatPoint;
133+
begin
134+
p0 := Transform(FloatPoint(X0, Y0));
135+
p1 := Transform(FloatPoint(X1, Y1));
136+
p2 := Transform(FloatPoint(X2, Y2));
137+
p3 := Transform(FloatPoint(X3, Y3));
138+
139+
// p0 := (FloatPoint(X0, Y0));
140+
// p1 := (FloatPoint(X1, Y1));
141+
// p2 := (FloatPoint(X2, Y2));
142+
// p3 := (FloatPoint(X3, Y3));
143+
144+
Result.Left := Min(Min(p0.X, p1.X), Min(p2.X, p3.X));
145+
Result.Right := Max(Max(p0.X, p1.X), Max(p2.X, p3.X));
146+
Result.Top := Min(Min(p0.Y, p1.Y), Min(p2.Y, p3.Y));
147+
Result.Bottom := Max(Max(p0.Y, p1.Y), Max(p2.Y, p3.Y));
148+
end;
149+
150+
function Distance(P1, P2: TFloatPoint): Single;
151+
begin
152+
Result := Sqrt(Sqr(P1.X - P2.X) + Sqr(P1.Y - P2.Y));
153+
end;
154+
155+
procedure TMyProjectiveTransformation.PrepareTransform;
156+
var
157+
widthA, widthB, heightA, heightB: TFloat;
158+
src, dst: TArray<TFloatPoint>;
159+
begin
160+
src := TArray<TFloatPoint>.Create(
161+
FloatPoint(X0, Y0),
162+
FloatPoint(X1, Y1),
163+
FloatPoint(X2, Y2),
164+
FloatPoint(X3, Y3)
165+
);
166+
widthA := Distance(src[2], src[3]);
167+
widthB := Distance(src[1], src[0]);
168+
FDestWidth := Max(widthA, widthB);
169+
170+
heightA := Distance(src[1], src[2]);
171+
heightB := Distance(src[0], src[3]);
172+
FDestHeight := Max(heightA, heightB);
173+
174+
dst := TArray<TFloatPoint>.Create(
175+
FloatPoint(0, 0),
176+
FloatPoint(FDestWidth, 0),
177+
FloatPoint(FDestWidth, FDestHeight),
178+
FloatPoint(0, FDestHeight)
179+
);
180+
181+
FMatrix := getPerspectiveTransform(src, dst);
182+
// Invert(FMatrix);
183+
inherited;
184+
end;
185+
186+
procedure TMyProjectiveTransformation.ReverseTransformFixed(DstX, DstY: TFixed;
187+
out SrcX, SrcY: TFixed);
188+
var
189+
Z: TFixed;
190+
Zf: TFloat;
191+
begin
192+
Z := FixedMul(FInverseFixedMatrix[0, 2], DstX) +
193+
FixedMul(FInverseFixedMatrix[1, 2], DstY) + FInverseFixedMatrix[2, 2];
194+
195+
if Z = 0 then Exit;
196+
197+
{$IFDEF UseInlining}
198+
SrcX := FixedMul(DstX, FInverseFixedMatrix[0, 0]) +
199+
FixedMul(DstY, FInverseFixedMatrix[1, 0]) + FInverseFixedMatrix[2, 0];
200+
SrcY := FixedMul(DstX, FInverseFixedMatrix[0,1]) +
201+
FixedMul(DstY, FInverseFixedMatrix[1, 1]) + FInverseFixedMatrix[2, 1];
202+
{$ELSE}
203+
inherited;
204+
{$ENDIF}
205+
206+
if Z <> FixedOne then
207+
begin
208+
EMMS;
209+
Zf := FixedOne / Z;
210+
SrcX := Round(SrcX * Zf);
211+
SrcY := Round(SrcY * Zf);
212+
end;
213+
end;
214+
215+
procedure TMyProjectiveTransformation.ReverseTransformFloat(DstX, DstY: TFloat;
216+
out SrcX, SrcY: TFloat);
217+
var
218+
Z: TFloat;
219+
begin
220+
EMMS;
221+
Z := FInverseMatrix[0, 2] * DstX + FInverseMatrix[1, 2] * DstY +
222+
FInverseMatrix[2, 2];
223+
224+
if Z = 0 then Exit;
225+
226+
{$IFDEF UseInlining}
227+
SrcX := DstX * FInverseMatrix[0, 0] + DstY * FInverseMatrix[1, 0] +
228+
FInverseMatrix[2, 0];
229+
SrcY := DstX * FInverseMatrix[0, 1] + DstY * FInverseMatrix[1, 1] +
230+
FInverseMatrix[2, 1];
231+
{$ELSE}
232+
inherited;
233+
{$ENDIF}
234+
235+
if Z <> 1 then
236+
begin
237+
Z := 1 / Z;
238+
SrcX := SrcX * Z;
239+
SrcY := SrcY * Z;
240+
end;
241+
end;
242+
243+
procedure TMyProjectiveTransformation.SetX0(Value: TFloat);
244+
begin
245+
FQuadX[0] := Value;
246+
Changed;
247+
end;
248+
249+
procedure TMyProjectiveTransformation.SetX1(Value: TFloat);
250+
begin
251+
FQuadX[1] := Value;
252+
Changed;
253+
end;
254+
255+
procedure TMyProjectiveTransformation.SetX2(Value: TFloat);
256+
begin
257+
FQuadX[2] := Value;
258+
Changed;
259+
end;
260+
261+
procedure TMyProjectiveTransformation.SetX3(Value: TFloat);
262+
begin
263+
FQuadX[3] := Value;
264+
Changed;
265+
end;
266+
267+
procedure TMyProjectiveTransformation.SetY0(Value: TFloat);
268+
begin
269+
FQuadY[0] := Value;
270+
Changed;
271+
end;
272+
273+
procedure TMyProjectiveTransformation.SetY1(Value: TFloat);
274+
begin
275+
FQuadY[1] := Value;
276+
Changed;
277+
end;
278+
279+
procedure TMyProjectiveTransformation.SetY2(Value: TFloat);
280+
begin
281+
FQuadY[2] := Value;
282+
Changed;
283+
end;
284+
285+
procedure TMyProjectiveTransformation.SetY3(Value: TFloat);
286+
begin
287+
FQuadY[3] := Value;
288+
Changed;
289+
end;
290+
291+
292+
procedure TMyProjectiveTransformation.TransformFixed(SrcX, SrcY: TFixed;
293+
out DstX, DstY: TFixed);
294+
var
295+
Z: TFixed;
296+
Zf: TFloat;
297+
begin
298+
Z := FixedMul(FFixedMatrix[0, 2], SrcX) +
299+
FixedMul(FFixedMatrix[1, 2], SrcY) + FFixedMatrix[2, 2];
300+
301+
if Z = 0 then Exit;
302+
303+
{$IFDEF UseInlining}
304+
DstX := FixedMul(SrcX, FFixedMatrix[0, 0]) +
305+
FixedMul(SrcY, FFixedMatrix[1, 0]) + FFixedMatrix[2, 0];
306+
DstY := FixedMul(SrcX, FFixedMatrix[0, 1]) +
307+
FixedMul(SrcY, FFixedMatrix[1, 1]) + FFixedMatrix[2, 1];
308+
{$ELSE}
309+
inherited;
310+
{$ENDIF}
311+
312+
if Z <> FixedOne then
313+
begin
314+
EMMS;
315+
Zf := FixedOne / Z;
316+
DstX := Round(DstX * Zf);
317+
DstY := Round(DstY * Zf);
318+
end;
319+
end;
320+
321+
procedure TMyProjectiveTransformation.TransformFloat(SrcX, SrcY: TFloat;
322+
out DstX, DstY: TFloat);
323+
var
324+
Z: TFloat;
325+
begin
326+
EMMS;
327+
Z := FMatrix[0, 2] * SrcX + FMatrix[1, 2] * SrcY + FMatrix[2, 2];
328+
329+
if Z = 0 then Exit;
330+
331+
{$IFDEF UseInlining}
332+
DstX := SrcX * Matrix[0, 0] + SrcY * Matrix[1, 0] + Matrix[2, 0];
333+
DstY := SrcX * Matrix[0, 1] + SrcY * Matrix[1, 1] + Matrix[2, 1];
334+
{$ELSE}
335+
inherited;
336+
{$ENDIF}
337+
338+
if Z <> 1 then
339+
begin
340+
Z := 1 / Z;
341+
DstX := DstX * Z;
342+
DstY := DstY * Z;
343+
end;
344+
end;
345+
346+
end.

0 commit comments

Comments
 (0)