-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathunit_interpolate.pas
165 lines (136 loc) · 5.98 KB
/
unit_interpolate.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
unit unit_interpolate;
{Copyright (C) 2024 by Han Kleijn, www.hnsky.org
email: han.k.. at...hnsky.org
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at https://mozilla.org/MPL/2.0/. }
interface
uses
Classes, SysUtils, math,astap_main;
type
pixel = array[0..2] of double;
function bilinear_interpolation(const img :Timage_array; x,y:double; out colour: pixel): boolean; {calculate image pixel value on subpixel level}
function BicubicInterpolate(const Img: Timage_array; X, Y: Double; out colour: pixel): boolean;
implementation
//the following function is not used since calculating the rectangle areas covered by an imaginary square pixel works a little better. See function hfd()
function bilinear_interpolation(const img :Timage_array; x,y:double; out colour: pixel): boolean; //calculate image pixel value on subpixel level
var
X0, Y0, X1, Y1,width5,height5,col,nrcolours: Integer;
Q11, Q12, Q21, Q22: Double;
R1, R2: Double;
begin
result:=true;
width5:=Length(img[0,0]);{width}
height5:=Length(img[0]); {height}
nrcolours:=Length(img);
X0 := Floor(X);
Y0 := Floor(Y);
X1 := X0 + 1;
Y1 := Y0 + 1;
if ((X0 <=0) or (X1 >= width5-1) or (Y0 <= 0) or (Y1 >= height5-1)) then
begin
for col:=0 to nrcolours do colour[col]:=0;
result:=false;
exit;
end;
for col:=0 to nrcolours-1 do
begin
Q11 := img[col,y0,x0];
Q12 := img[col,y0,x1];
Q21 := img[col,y1,x0];
Q22 := img[col,y1,x1];
colour[col]:= (Y1 - Y) * (X1 - X) * Q11 + (Y1 - Y) * (X - X0) * Q21 + (Y - Y0) * (X1 - X) * Q12 + (Y - Y0) * (X - X0) * Q22;
end;
end;
function CatmullRom(p0, p1, p2, p3, t: Double): Double;
// A Catmull-Rom spline is a type of cubic Hermite spline that passes through a set of control points.
// It is C1 continuous, meaning that it has continuous first derivatives.
// The spline is not C2 continuous. The second derivative is linearly interpolated within each segment, causing the curvature to vary linearly over the length of the segment.
// The factor 0.5 is called tention and typically provides a good balance between smoothness and sharpness.
//
//
// [ -1 3 -3 1 ] | P0 |
// [ 2 -5 4 -1 ] | P1 |
// P(t):= 0.5*[t^3, t^2, t, 1] * [ -1 0 1 0 ] * | P2 |
// [ 0 2 0 0 ] | P3 |
//
// This becomes:
//
// P(t) = 0.5 * ((-p0 + 3*p1 -3*p2 + p3)*t*t*t
// + (2*p0 -5*p1 + 4*p2 - p3)*t*t
// + (-p0+p2)*t
// + 2*p1)
//
// The interpolated value represents a point on the curve defined by the four control points p0,p1,p2 and p3.
// This curve segment is influenced by the surrounding points, providing a smooth transition that maintains the shape defined by these points.
//
// The function takes four control points: p0, p1, p2, and p3.
// p1 and p2 are the primary points between which the interpolation occurs.
// p0 and p3 influence the shape of the curve but are not directly interpolated between.
// The output of the Catmull-rom is the estimated value between p1 and p2.
//
// t is the interpolation parameter that determines the position along the curve between two control points p1 and p2.
// When t=0, the interpolation result corresponds exactly to the position of the first control point p1.
// At t=0.5, the point is halfway along the curve between p1 and p2.
// When t=1, the result corresponds exactly to the position of the second control point p2.
var
t2, t3: Double;
a0, a1, a2, a3: Double;
begin
t2 := t * t;
t3 := t2 * t;
// Coefficients for the cubic polynomial with tension parameter
a0 := 0.5 * (-p0 + 3.0 * p1 - 3.0 * p2 + p3);
a1 := 0.5 * (2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3);
a2 := 0.5 * (-p0 + p2);
a3 := 0.5 * 2.0 * p1;
Result := a0 * t3 + a1 * t2 + a2 * t + a3;
end;
function BicubicInterpolate(const Img: Timage_array; X, Y: Double; out colour: pixel): boolean;
var
i, j, width5,height5,nrcolours,col: Integer;
Row: array[0..3] of Double;
IntX, IntY: Integer;
DX, DY: Double;
begin
result:=true;
width5:=Length(img[0,0]);{width}
height5:=Length(img[0]); {height}
nrcolours:=Length(img);
// Determine integer coordinates
IntX := Floor(X);
IntY := Floor(Y);
// Calculate fractional part of the coordinates
DX := X - IntX;
DY := Y - IntY;
// Boundary checks (ensure we have a 4x4 grid to interpolate within)
if (IntX <= 1) or (IntX >= width5 - 2) or (IntY <= 1) or (IntY >=height5 - 2) then
begin
for i:=0 to 2 do colour[i]:=0;
Exit(false);
end;
for col:=0 to nrcolours-1 do
begin
// Interpolate along the rows
for i := -1 to 2 do
Row[i + 1] := CatmullRom( Img[col,IntY + i,IntX - 1],
Img[col,IntY + i,IntX],
Img[col,IntY + i,(IntX + 1)],
Img[col,IntY + i,(IntX + 2)],
DX );
// Interpolate the result along the column
colour[col] := CatmullRom(Row[0], Row[1], Row[2], Row[3], DY);
end;
end;
//test data
{ img[0,0,0] := 5; img[0,1,0] := 6; img[0,2,0] := 7; img[0,3,0] := 8; img[0,4,0] := 9;
img[0,0,1] := 10; img[0,1,1] := 11; img[0,2,1] := 12; img[0,3,1] := 13; img[0,4,1] := 14;
img[0,0,2] := 15; img[0,1,2] := 16; img[0,2,2] := 17; img[0,3,2] := 18; img[0,4,2] := 19;
img[0,0,3] := 20; img[0,1,3] := 21; img[0,2,3] := 22; img[0,3,3] := 23; img[0,4,3] := 24;
img[0,0,4] := 25; img[0,1,4] := 26; img[0,2,4] := 27; img[0,3,4] := 28; img[0,4,4] := 29;
img[0,0,4] := 30; img[0,1,4] := 31; img[0,2,4] := 32; img[0,3,4] := 33; img[0,4,4] := 34;
val:=value_bilinear(2.5,2.5);//20
val:=BicubicInterpolate(2.5,2.5);
}
begin
end.