|
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 |