| |
1 ###################################### |
| |
2 # Image subpixel accuracy translation |
| |
3 ###################################### |
| |
4 |
| |
5 module Translate |
| |
6 |
| |
7 ########## |
| |
8 # Exports |
| |
9 ########## |
| |
10 |
| |
11 export interpolate2d, |
| |
12 interpolate2d_quadrants, |
| |
13 extract_subimage!, |
| |
14 translate_image!, |
| |
15 DisplacementFull, |
| |
16 DisplacementConstant, |
| |
17 Displacement, |
| |
18 Image |
| |
19 |
| |
20 ################## |
| |
21 # Types |
| |
22 ################## |
| |
23 |
| |
24 # Two different types of displacement data supported: |
| |
25 # a) given in each pixel |
| |
26 # b) constant in space |
| |
27 Image = Array{Float64,2} |
| |
28 DisplacementFull = Array{Float64,3} |
| |
29 DisplacementConstant = Array{Float64,1} |
| |
30 Displacement = Union{DisplacementFull,DisplacementConstant} |
| |
31 |
| |
32 ############################# |
| |
33 # Base interpolation routine |
| |
34 ############################# |
| |
35 |
| |
36 @inline function interpolate2d_quadrants(v, (x, y)) |
| |
37 (m, n) = size(v) |
| |
38 clipx = xʹ -> max(1, min(xʹ, m)) |
| |
39 clipy = yʹ -> max(1, min(yʹ, n)) |
| |
40 |
| |
41 xfℤ = clipx(floor(Int, x)) |
| |
42 xcℤ = clipx(ceil(Int, x)) |
| |
43 yfℤ = clipy(floor(Int, y)) |
| |
44 ycℤ = clipy(ceil(Int, y)) |
| |
45 |
| |
46 xf = convert(Float64, xfℤ) |
| |
47 xc = convert(Float64, xcℤ) |
| |
48 yf = convert(Float64, yfℤ) |
| |
49 yc = convert(Float64, ycℤ) |
| |
50 xm = (xf+xc)/2 |
| |
51 ym = (yf+yc)/2 |
| |
52 |
| |
53 vff = @inbounds v[xfℤ, yfℤ] |
| |
54 vfc = @inbounds v[xfℤ, ycℤ] |
| |
55 vcf = @inbounds v[xcℤ, yfℤ] |
| |
56 vcc = @inbounds v[xcℤ, ycℤ] |
| |
57 vmm = (vff+vfc+vcf+vcc)/4 |
| |
58 |
| |
59 if xfℤ==xcℤ |
| |
60 if yfℤ==ycℤ |
| |
61 # Completely degenerate case |
| |
62 v = vmm |
| |
63 else |
| |
64 # Degenerate x |
| |
65 v = vff+(y-yf)/(yc-yf)*(vfc-vff) |
| |
66 end |
| |
67 elseif yfℤ==ycℤ |
| |
68 # Degenerate y |
| |
69 v = vff + (x-xf)/(xc-xf)*(vcf-vff) |
| |
70 elseif y-ym ≥ x-xm |
| |
71 # top-left half |
| |
72 if (y-ym) + (x-xm) ≥ 0 |
| |
73 # top quadrant |
| |
74 v = vfc + (x-xf)/(xc-xf)*(vcc-vfc) + (y-yc)/(ym-yc)*(vmm-(vcc+vfc)/2) |
| |
75 else |
| |
76 # left quadrant |
| |
77 v = vff + (y-yf)/(yc-yf)*(vfc-vff) + (x-xf)/(xm-xf)*(vmm-(vfc+vff)/2) |
| |
78 end |
| |
79 else |
| |
80 # bottom-left half |
| |
81 if (y-ym) + (x-xm) ≥ 0 |
| |
82 # right quadrant |
| |
83 v = vcf + (y-yf)/(yc-yf)*(vcc-vcf) + (x-xc)/(xm-xc)*(vmm-(vcc+vcf)/2) |
| |
84 else |
| |
85 # bottom quadrant |
| |
86 v = vff + (x-xf)/(xc-xf)*(vcf-vff) + (y-yf)/(ym-yf)*(vmm-(vcf+vff)/2) |
| |
87 end |
| |
88 end |
| |
89 |
| |
90 return v |
| |
91 end |
| |
92 |
| |
93 interpolate2d = interpolate2d_quadrants |
| |
94 |
| |
95 ############## |
| |
96 # Translation |
| |
97 ############## |
| |
98 |
| |
99 @polly function translate_image!(x, z, u::DisplacementFull) |
| |
100 @assert(size(u, 1)==2 && size(x)==size(u)[2:end] && size(x)==size(z)) |
| |
101 |
| |
102 @inbounds @simd for i=1:size(x, 1) |
| |
103 @simd for j=1:size(x, 2) |
| |
104 pt = (i - u[1, i, j], j - u[2, i, j]) |
| |
105 x[i, j] = interpolate2d(z, pt) |
| |
106 end |
| |
107 end |
| |
108 end |
| |
109 |
| |
110 @polly function translate_image!(x, z, u::DisplacementConstant) |
| |
111 @assert(size(u)==(2,) && size(x)==size(z)) |
| |
112 |
| |
113 @inbounds @simd for i=1:size(x, 1) |
| |
114 @simd for j=1:size(x, 2) |
| |
115 pt = (i - u[1], j - u[2]) |
| |
116 x[i, j] = interpolate2d(z, pt) |
| |
117 end |
| |
118 end |
| |
119 end |
| |
120 |
| |
121 ###################### |
| |
122 # Subimage extraction |
| |
123 ###################### |
| |
124 |
| |
125 @polly function extract_subimage!(b, im, v::DisplacementConstant) |
| |
126 (imx, imy) = size(im) |
| |
127 (bx, by) = size(b) |
| |
128 |
| |
129 # Translation from target to source coordinates |
| |
130 vxʹ = v[1] + (imx-bx)/2 |
| |
131 vyʹ = v[2] + (imy-by)/2 |
| |
132 |
| |
133 # Target image indices within source image |
| |
134 px = ceil(Int, max(1, vxʹ + 1) - vxʹ) |
| |
135 py = ceil(Int, max(1, vyʹ + 1) - vyʹ) |
| |
136 qx = floor(Int, min(imx, vxʹ + bx) - vxʹ) |
| |
137 qy = floor(Int, min(imy, vyʹ + by) - vyʹ) |
| |
138 |
| |
139 b .= 0 |
| |
140 |
| |
141 @inbounds @simd for i=px:qx |
| |
142 for j=py:qy |
| |
143 b[i, j] = interpolate2d(im, (i+vxʹ, j+vyʹ)) |
| |
144 end |
| |
145 end |
| |
146 end |
| |
147 |
| |
148 end |