Sun, 21 Apr 2024 19:26:50 +0300
added stable interval for denoising
0 | 1 | ################################ |
2 | # Code relevant to optical flow | |
3 | ################################ | |
4 | ||
5 | __precompile__() | |
6 | ||
7 | module OpticalFlow | |
8 | ||
9 | using AlgTools.Util | |
10 | using ImageTools.Gradient | |
11 | import ImageTools.Translate | |
12 | using ImageTools.ImFilter | |
13 | ||
8
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
14 | # using ImageTransformations |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
15 | # using Images, CoordinateTransformations, Rotations, OffsetArrays |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
16 | # using Interpolations |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
17 | |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
18 | import Images: center, warp |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
19 | import CoordinateTransformations: recenter |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
20 | import Rotations: RotMatrix |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
21 | import Interpolations: Flat |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
22 | |
0 | 23 | ########## |
24 | # Exports | |
25 | ########## | |
26 | ||
27 | export flow!, | |
28 | pdflow!, | |
29 | flow_grad!, | |
30 | flow_interp!, | |
31 | estimate_Λ², | |
32 | estimate_linear_Λ², | |
33 | pointwise_gradiprod_2d!, | |
34 | pointwise_gradiprod_2dᵀ!, | |
35 | horn_schunck_reg_prox!, | |
36 | horn_schunck_reg_prox_op!, | |
37 | mldivide_step_plus_sym2x2!, | |
38 | linearised_optical_flow_error, | |
39 | Image, AbstractImage, ImageSize, | |
40 | Gradient, Displacement, | |
41 | DisplacementFull, DisplacementConstant, | |
42 | HornSchunckData, | |
8
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
43 | filter_hs, |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
44 | petpdflow! |
0 | 45 | |
46 | ############################################### | |
47 | # Types (several imported from ImageTools.Translate) | |
48 | ############################################### | |
49 | ||
50 | Image = Translate.Image | |
51 | AbstractImage = AbstractArray{Float64,2} | |
52 | Displacement = Translate.Displacement | |
53 | DisplacementFull = Translate.DisplacementFull | |
54 | DisplacementConstant = Translate.DisplacementConstant | |
55 | Gradient = Array{Float64,3} | |
56 | ImageSize = Tuple{Int64,Int64} | |
57 | ||
58 | ################################# | |
59 | # Displacement field based flow | |
60 | ################################# | |
61 | ||
62 | function flow_interp!(x::AbstractImage, u::Displacement, tmp::AbstractImage; | |
63 | threads = false) | |
64 | tmp .= x | |
65 | Translate.translate_image!(x, tmp, u; threads=threads) | |
66 | end | |
67 | ||
68 | function flow_interp!(x::AbstractImage, u::Displacement; | |
69 | threads = false) | |
70 | tmp = copy(x) | |
71 | Translate.translate_image!(x, tmp, u; threads=threads) | |
72 | end | |
73 | ||
74 | flow! = flow_interp! | |
75 | ||
76 | function pdflow!(x, Δx, y, Δy, u, dual_flow; threads=:none) | |
77 | if dual_flow | |
78 | #flow!((x, @view(y[1, :, :]), @view(y[2, :, :])), diffu, | |
79 | # (Δx, @view(Δy[1, :, :]), @view(Δy[2, :, :]))) | |
80 | @backgroundif (threads==:outer) begin | |
81 | flow!(x, u, Δx; threads=(threads==:inner)) | |
82 | end begin | |
83 | flow!(@view(y[1, :, :]), u, @view(Δy[1, :, :]); threads=(threads==:inner)) | |
84 | flow!(@view(y[2, :, :]), u, @view(Δy[2, :, :]); threads=(threads==:inner)) | |
85 | end | |
86 | else | |
87 | flow!(x, u, Δx) | |
88 | end | |
89 | end | |
90 | ||
91 | function pdflow!(x, Δx, y, Δy, z, Δz, u, dual_flow; threads=:none) | |
92 | if dual_flow | |
93 | @backgroundif (threads==:outer) begin | |
94 | flow!(x, u, Δx; threads=(threads==:inner)) | |
95 | flow!(z, u, Δz; threads=(threads==:inner)) | |
96 | end begin | |
97 | flow!(@view(y[1, :, :]), u, @view(Δy[1, :, :]); threads=(threads==:inner)) | |
98 | flow!(@view(y[2, :, :]), u, @view(Δy[2, :, :]); threads=(threads==:inner)) | |
99 | end | |
100 | else | |
101 | flow!(x, u, Δx; threads=(threads==:inner)) | |
102 | flow!(z, u, Δz; threads=(threads==:inner)) | |
103 | end | |
104 | end | |
105 | ||
5 | 106 | # Additional method for Greedy |
107 | function pdflow!(x, Δx, y, Δy, u; threads=:none) | |
108 | @assert(size(u)==(2,)) | |
109 | Δx .= x | |
110 | Δy .= y | |
111 | flow!(x, u; threads=(threads==:inner)) | |
112 | Dxx = similar(Δy) | |
113 | DΔx = similar(Δy) | |
114 | ∇₂!(Dxx, x) | |
115 | ∇₂!(DΔx, Δx) | |
116 | inds = abs.(Dxx) .≤ 1e-1 | |
117 | Dxx[inds] .= 1 | |
118 | DΔx[inds] .= 1 | |
119 | y .= y.* DΔx ./ Dxx | |
120 | end | |
121 | ||
122 | # Additional method for Rotation | |
123 | function pdflow!(x, Δx, y, u; threads=:none) | |
124 | @assert(size(u)==(2,)) | |
125 | Δx .= x | |
126 | flow!(x, u; threads=(threads==:inner)) | |
127 | ||
128 | (m,n) = size(x) | |
129 | dx = similar(y) | |
130 | dx_banana = similar(y) | |
131 | ∇₂!(dx, Δx) | |
132 | ∇₂!(dx_banana, x) | |
133 | ||
134 | for i=1:m | |
135 | for j=1:n | |
136 | ndx = @views sum(dx[:, i, j].^2) | |
137 | ndx_banana = @views sum(dx_banana[:, i, j].^2) | |
138 | if ndx > 1e-4 && ndx_banana > 1e-4 | |
139 | A = dx[:, i, j] | |
140 | B = dx_banana[:, i, j] | |
141 | theta = atan(B[1] * A[2] - B[2] * A[1], B[1] * A[1] + B[2] * A[2]) # Oriented angle from A to B | |
142 | cos_theta = cos(theta) | |
143 | sin_theta = sin(theta) | |
144 | a = cos_theta * y[1, i, j] - sin_theta * y[2, i, j] | |
145 | b = sin_theta * y[1, i, j] + cos_theta * y[2, i, j] | |
146 | y[1, i, j] = a | |
147 | y[2, i, j] = b | |
148 | end | |
149 | end | |
150 | end | |
151 | end | |
152 | ||
153 | # Additional method for Dual Scaling | |
154 | function pdflow!(x, y, u; threads=:none) | |
155 | @assert(size(u)==(2,)) | |
156 | oldx = copy(x) | |
157 | flow!(x, u; threads=(threads==:inner)) | |
158 | C = similar(y) | |
159 | cc = abs.(x-oldx) | |
160 | cm = max(1e-12,maximum(cc)) | |
161 | c = 1 .* (1 .- cc./ cm) .^(10) | |
162 | C[1,:,:] .= c | |
163 | C[2,:,:] .= c | |
164 | y .= C.*y | |
165 | end | |
166 | ||
8
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
167 | |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
168 | ########################## |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
169 | # PET |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
170 | ########################## |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
171 | function petflow_interp!(x::AbstractImage, tmp::AbstractImage, u::DisplacementConstant, theta_known::DisplacementConstant; |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
172 | threads = false) |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
173 | tmp .= x |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
174 | center_point = center(x) .+ u |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
175 | tform = recenter(RotMatrix(theta_known[1]), center_point) |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
176 | tmp = warp(x, tform, axes(x), fillvalue=Flat()) |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
177 | x .= tmp |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
178 | end |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
179 | |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
180 | petflow! = petflow_interp! |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
181 | |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
182 | function petpdflow!(x, Δx, y, Δy, u, theta_known, dual_flow; threads=:none) |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
183 | if dual_flow |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
184 | @backgroundif (threads==:outer) begin |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
185 | petflow!(x, Δx, u, theta_known; threads=(threads==:inner)) |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
186 | end begin |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
187 | petflow!(@view(y[1, :, :]), @view(Δy[1, :, :]), u, theta_known; threads=(threads==:inner)) |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
188 | petflow!(@view(y[2, :, :]), @view(Δy[2, :, :]), u, theta_known; threads=(threads==:inner)) |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
189 | end |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
190 | else |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
191 | petflow!(x, Δx, u, theta_known) |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
192 | end |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
193 | end |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
194 | |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
195 | # Method for greedy predictor |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
196 | function petpdflow!(x, Δx, y, Δy, u, theta_known, dual_flow, β; threads=:none) |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
197 | oldx = copy(x) |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
198 | center_point = center(x) .+ u |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
199 | tform = recenter(RotMatrix(theta_known[1]), center_point) |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
200 | Δx = warp(x, tform, axes(x), fillvalue=Flat()) |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
201 | @. x = Δx |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
202 | @. Δy = y |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
203 | if dual_flow |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
204 | Dxx = copy(Δy) |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
205 | DΔx = copy(Δy) |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
206 | ∇₂!(Dxx, x) |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
207 | ∇₂!(DΔx, oldx) |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
208 | inds = abs.(Dxx) .≤ β |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
209 | Dxx[inds] .= 1 |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
210 | DΔx[inds] .= 1 |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
211 | y .= y.* DΔx ./ Dxx |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
212 | end |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
213 | end |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
214 | |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
215 | # Method for affine predictor |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
216 | function petpdflow!(x, Δx, y, u, theta_known, dual_flow; threads=:none) |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
217 | oldx = copy(x) |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
218 | center_point = center(x) .+ u |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
219 | tform = recenter(RotMatrix(theta_known[1]), center_point) |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
220 | Δx = warp(x, tform, axes(x), fillvalue=Flat()) |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
221 | @. x = Δx |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
222 | C = similar(y) |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
223 | cc = abs.(x-oldx) |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
224 | if dual_flow |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
225 | cm = max(1e-12,maximum(cc)) |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
226 | c = 1 .* (1 .- cc./ cm) .^(10) |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
227 | C[1,:,:] .= c |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
228 | C[2,:,:] .= c |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
229 | y .= C.*y |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
230 | end |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
231 | end |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
232 | |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
233 | # Method for rotation prediction (exploiting property of inverse rotation) |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
234 | function petpdflow!(x, Δx, y, Δy, u, theta_known, dual_flow, β₁, β₂; threads=:none) |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
235 | if dual_flow |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
236 | @backgroundif (threads==:outer) begin |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
237 | petflow!(x, Δx, u, theta_known; threads=(threads==:inner)) |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
238 | end begin |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
239 | petflow!(@view(y[1, :, :]), @view(Δy[1, :, :]), u, -theta_known; threads=(threads==:inner)) |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
240 | petflow!(@view(y[2, :, :]), @view(Δy[2, :, :]), u, -theta_known; threads=(threads==:inner)) |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
241 | end |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
242 | else |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
243 | petflow!(x, Δx, u, theta_known) |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
244 | end |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
245 | end |
e4ad8f7ce671
Added PET and updated README
Neil Dizon <neil.dizon@helsinki.fi>
parents:
5
diff
changeset
|
246 | |
0 | 247 | ########################## |
248 | # Linearised optical flow | |
249 | ########################## | |
250 | ||
251 | # ⟨⟨u, ∇b⟩⟩ | |
252 | function pointwise_gradiprod_2d!(y::Image, vtmp::Gradient, | |
253 | u::DisplacementFull, b::Image; | |
254 | add = false) | |
255 | ∇₂c!(vtmp, b) | |
256 | ||
257 | u′=reshape(u, (size(u, 1), prod(size(u)[2:end]))) | |
258 | vtmp′=reshape(vtmp, (size(vtmp, 1), prod(size(vtmp)[2:end]))) | |
259 | y′=reshape(y, prod(size(y))) | |
260 | ||
261 | if add | |
262 | @simd for i = 1:length(y′) | |
263 | @inbounds y′[i] += dot(@view(u′[:, i]), @view(vtmp′[:, i])) | |
264 | end | |
265 | else | |
266 | @simd for i = 1:length(y′) | |
267 | @inbounds y′[i] = dot(@view(u′[:, i]), @view(vtmp′[:, i])) | |
268 | end | |
269 | end | |
270 | end | |
271 | ||
272 | function pointwise_gradiprod_2d!(y::Image, vtmp::Gradient, | |
273 | u::DisplacementConstant, b::Image; | |
274 | add = false) | |
275 | ∇₂c!(vtmp, b) | |
276 | ||
277 | vtmp′=reshape(vtmp, (size(vtmp, 1), prod(size(vtmp)[2:end]))) | |
278 | y′=reshape(y, prod(size(y))) | |
279 | ||
280 | if add | |
281 | @simd for i = 1:length(y′) | |
282 | @inbounds y′[i] += dot(u, @view(vtmp′[:, i])) | |
283 | end | |
284 | else | |
285 | @simd for i = 1:length(y′) | |
286 | @inbounds y′[i] = dot(u, @view(vtmp′[:, i])) | |
287 | end | |
288 | end | |
289 | end | |
290 | ||
291 | # ∇b ⋅ y | |
292 | function pointwise_gradiprod_2dᵀ!(u::DisplacementFull, y::Image, b::Image) | |
293 | ∇₂c!(u, b) | |
294 | ||
295 | u′=reshape(u, (size(u, 1), prod(size(u)[2:end]))) | |
296 | y′=reshape(y, prod(size(y))) | |
297 | ||
298 | @simd for i=1:length(y′) | |
299 | @inbounds @. u′[:, i] *= y′[i] | |
300 | end | |
301 | end | |
302 | ||
303 | function pointwise_gradiprod_2dᵀ!(u::DisplacementConstant, y::Image, b::Image) | |
304 | @assert(size(y)==size(b) && size(u)==(2,)) | |
305 | u .= 0 | |
306 | ∇₂cfold!(b, nothing) do g, st, (i, j) | |
307 | @inbounds u .+= g.*y[i, j] | |
308 | return st | |
309 | end | |
310 | # Reweight to be with respect to 𝟙^*𝟙 inner product. | |
311 | u ./= prod(size(b)) | |
312 | end | |
313 | ||
314 | mutable struct ConstantDisplacementHornSchunckData | |
315 | M₀::Array{Float64,2} | |
316 | z::Array{Float64,1} | |
317 | Mv::Array{Float64,2} | |
318 | av::Array{Float64,1} | |
319 | cv::Float64 | |
320 | ||
321 | function ConstantDisplacementHornSchunckData() | |
322 | return new(zeros(2, 2), zeros(2), zeros(2,2), zeros(2), 0) | |
323 | end | |
324 | end | |
325 | ||
326 | # For DisplacementConstant, for the simple prox step | |
327 | # | |
328 | # (1) argmin_u 1/(2τ)|u-ũ|^2 + (θ/2)|b⁺-b+<<u-ŭ,∇b>>|^2 + (λ/2)|u-ŭ|^2, | |
329 | # | |
330 | # construct matrix M₀ and vector z such that we can solve u from | |
331 | # | |
332 | # (2) (I/τ+M₀)u = M₀ŭ + ũ/τ - z | |
333 | # | |
334 | # Note that the problem | |
335 | # | |
336 | # argmin_u 1/(2τ)|u-ũ|^2 + (θ/2)|b⁺-b+<<u-ŭ,∇b>>|^2 + (λ/2)|u-ŭ|^2 | |
337 | # + (θ/2)|b⁺⁺-b⁺+<<uʹ-u,∇b⁺>>|^2 + (λ/2)|u-uʹ|^2 | |
338 | # | |
339 | # has with respect to u the system | |
340 | # | |
341 | # (I/τ+M₀+M₀ʹ)u = M₀ŭ + M₀ʹuʹ + ũ/τ - z + zʹ, | |
342 | # | |
343 | # where the primed variables correspond to (2) for (1) for uʹ in place of u: | |
344 | # | |
345 | # argmin_uʹ 1/(2τ)|uʹ-ũʹ|^2 + (θ/2)|b⁺⁺-b⁺+<<uʹ-u,∇b⁺>>|^2 + (λ/2)|uʹ-u|^2 | |
346 | # | |
347 | function horn_schunck_reg_prox_op!(hs::ConstantDisplacementHornSchunckData, | |
348 | bnext::Image, b::Image, θ, λ, T) | |
349 | @assert(size(b)==size(bnext)) | |
350 | w = prod(size(b)) | |
351 | z = hs.z | |
352 | cv = 0 | |
353 | # Factors of symmetric matrix [a c; c d] | |
354 | a, c, d = 0.0, 0.0, 0.0 | |
355 | # This used to use ∇₂cfold but it is faster to allocate temporary | |
356 | # storage for the full gradient due to probably better memory and SIMD | |
357 | # instruction usage. | |
358 | g = zeros(2, size(b)...) | |
359 | ∇₂c!(g, b) | |
360 | @inbounds for i=1:size(b, 1) | |
361 | for j=1:size(b, 2) | |
362 | δ = bnext[i,j]-b[i,j] | |
363 | @. z += g[:,i,j]*δ | |
364 | cv += δ*δ | |
365 | a += g[1,i,j]*g[1,i,j] | |
366 | c += g[1,i,j]*g[2,i,j] | |
367 | d += g[2,i,j]*g[2,i,j] | |
368 | end | |
369 | end | |
370 | w₀ = λ | |
371 | w₂ = θ/w | |
372 | aʹ = w₀ + w₂*a | |
373 | cʹ = w₂*c | |
374 | dʹ = w₀ + w₂*d | |
375 | hs.M₀ .= [aʹ cʹ; cʹ dʹ] | |
376 | hs.Mv .= [w*λ+θ*a θ*c; θ*c w*λ+θ*d] | |
377 | hs.cv = cv*θ | |
378 | hs.av .= hs.z.*θ | |
379 | hs.z .*= w₂/T | |
380 | end | |
381 | ||
382 | # Solve the 2D system (I/τ+M₀)u = z | |
383 | @inline function mldivide_step_plus_sym2x2!(u, M₀, z, τ) | |
384 | a = 1/τ+M₀[1, 1] | |
385 | c = M₀[1, 2] | |
386 | d = 1/τ+M₀[2, 2] | |
387 | u .= ([d -c; -c a]*z)./(a*d-c*c) | |
388 | end | |
389 | ||
390 | function horn_schunck_reg_prox!(u::DisplacementConstant, bnext::Image, b::Image, | |
391 | θ, λ, T, τ) | |
392 | hs=ConstantDisplacementHornSchunckData() | |
393 | horn_schunck_reg_prox_op!(hs, bnext, b, θ, λ, T) | |
394 | mldivide_step_plus_sym2x2!(u, hs.M₀, (u./τ)-hs.z, τ) | |
395 | end | |
396 | ||
397 | function flow_grad!(x::Image, vtmp::Gradient, u::Displacement; δ=nothing) | |
398 | if !isnothing(δ) | |
399 | u = δ.*u | |
400 | end | |
401 | pointwise_gradiprod_2d!(x, vtmp, u, x; add=true) | |
402 | end | |
403 | ||
404 | # Error b-b_prev+⟨⟨u, ∇b⟩⟩ for Horn–Schunck type penalisation | |
405 | function linearised_optical_flow_error(u::Displacement, b::Image, b_prev::Image) | |
406 | imdim = size(b) | |
407 | vtmp = zeros(2, imdim...) | |
408 | tmp = b-b_prev | |
409 | pointwise_gradiprod_2d!(tmp, vtmp, u, b_prev; add=true) | |
410 | return tmp | |
411 | end | |
412 | ||
413 | ############################################## | |
414 | # Helper to smooth data for Horn–Schunck term | |
415 | ############################################## | |
416 | ||
417 | function filter_hs(b, b_next, b_next_filt, kernel) | |
418 | if kernel==nothing | |
419 | f = x -> x | |
420 | else | |
421 | f = x -> simple_imfilter(x, kernel; threads=true) | |
422 | end | |
423 | ||
424 | # We already filtered b in the previous step (b_next in that step) | |
425 | b_filt = b_next_filt==nothing ? f(b) : b_next_filt | |
426 | b_next_filt = f(b_next) | |
427 | ||
428 | return b_filt, b_next_filt | |
429 | end | |
430 | ||
431 | end # Module |