Sun, 21 Apr 2024 13:41:35 +0300
added stable interval for PET
| 0 | 1 | ###################################################################### |
| 2 | # Predictive online PDPS for optical flow with unknown velocity field | |
| 3 | ###################################################################### | |
| 4 | ||
| 5 | __precompile__() | |
| 6 | ||
| 7 | module AlgorithmBothMulti | |
| 8 | ||
| 9 | identifier = "pdps_unknownmulti" | |
| 10 | ||
| 11 | using Printf | |
| 12 | ||
| 13 | using AlgTools.Util | |
| 14 | import AlgTools.Iterate | |
| 15 | using ImageTools.Gradient | |
| 16 | using ImageTools.ImFilter | |
| 17 | ||
| 18 | using ..OpticalFlow: Image, | |
| 19 | ImageSize, | |
| 20 | DisplacementConstant, | |
| 21 | pdflow!, | |
| 22 | horn_schunck_reg_prox!, | |
| 23 | pointwise_gradiprod_2d!, | |
| 24 | horn_schunck_reg_prox_op!, | |
| 25 | mldivide_step_plus_sym2x2!, | |
| 26 | ConstantDisplacementHornSchunckData, | |
| 27 | filter_hs | |
| 28 | ||
| 29 | using ..Algorithm: step_lengths | |
| 30 | ||
| 31 | ######################### | |
| 32 | # Iterate initialisation | |
| 33 | ######################### | |
| 34 | ||
| 35 | function init_displ(xinit::Image, ::Type{DisplacementConstant}, n::Integer) | |
| 36 | return xinit, zeros(n, 2) | |
| 37 | end | |
| 38 | ||
| 39 | # function init_displ(xinit::Image, ::Type{DisplacementFull}, n::Integer) | |
| 40 | # return xinit, zeros(n, 2, size(xinit)...) | |
| 41 | # end | |
| 42 | ||
| 43 | function init_rest(x::Image, u::DisplacementT) where DisplacementT | |
| 44 | imdim=size(x) | |
| 45 | ||
| 46 | y = zeros(2, imdim...) | |
| 47 | Δx = copy(x) | |
| 48 | Δy = copy(y) | |
| 49 | x̄ = copy(x) | |
| 50 | ||
| 51 | return x, y, Δx, Δy, x̄, u | |
| 52 | end | |
| 53 | ||
| 54 | function init_iterates( :: Type{DisplacementT}, | |
| 55 | xinit::Image, | |
| 56 | n::Integer) where DisplacementT | |
| 57 | return init_rest(init_displ(copy(xinit), DisplacementT, n)...) | |
| 58 | end | |
| 59 | ||
| 60 | function init_iterates( :: Type{DisplacementT}, | |
| 61 | dim::ImageSize, | |
| 62 | n::Integer) where DisplacementT | |
| 63 | return init_rest(init_displ(zeros(dim...), DisplacementT, n)...) | |
| 64 | end | |
| 65 | ||
| 66 | ############ | |
| 67 | # Algorithm | |
| 68 | ############ | |
| 69 | ||
| 70 | function solve( :: Type{DisplacementT}; | |
| 71 | dim :: ImageSize, | |
| 72 | iterate = AlgTools.simple_iterate, | |
| 73 | params::NamedTuple) where DisplacementT | |
| 74 | ||
| 75 | ###################### | |
| 76 | # Initialise iterates | |
| 77 | ###################### | |
| 78 | ||
| 79 | n = params.displacement_count | |
| 80 | k = 0 # number of displacements we have already | |
| 81 | ||
| 82 | x, y, Δx, Δy, x̄, u = init_iterates(DisplacementT, dim, n) | |
| 83 | init_data = (params.init == :data) | |
| 84 | hs = [ConstantDisplacementHornSchunckData() for i=1:n] | |
| 85 | #hs = Array{ConstantDisplacementHornSchunckData}(undef, n) | |
| 86 | A = Array{Float64,3}(undef, n, 2, 2) | |
| 87 | d = Array{Float64,2}(undef, n, 2) | |
| 88 | ||
| 89 | # … for tracking cumulative movement | |
| 90 | ucumulbase = [0.0, 0.0] | |
| 91 | ||
| 92 | ############################################# | |
| 93 | # Extract parameters and set up step lengths | |
| 94 | ############################################# | |
| 95 | ||
| 96 | α, ρ, λ, θ = params.α, params.ρ, params.λ, params.θ | |
| 97 | R_K² = ∇₂_norm₂₂_est² | |
| 98 | γ = 1 | |
| 99 | τ, σ, σ̃, ρ̃ = step_lengths(params, γ, R_K²) | |
| 100 | ||
| 101 | kernel = params.kernel | |
| 102 | T = params.timestep | |
| 103 | ||
| 104 | #################### | |
| 105 | # Run the algorithm | |
| 106 | #################### | |
| 107 | ||
| 108 | b_next_filt = nothing | |
| 109 | diffu = similar(u[1, :]) | |
| 110 | ||
| 111 | v = iterate(params) do verbose :: Function, | |
| 112 | b :: Image, | |
| 113 | 🚫unused_v_known :: DisplacementT, | |
| 114 | b_next :: Image | |
| 115 | ||
| 116 | #################################### | |
| 117 | # Smooth data for Horn–Schunck term | |
| 118 | #################################### | |
| 119 | ||
| 120 | b_filt, b_next_filt = filter_hs(b, b_next, b_next_filt, kernel) | |
| 121 | ||
| 122 | ################################################ | |
| 123 | # Prediction step | |
| 124 | ################################################ | |
| 125 | ||
| 126 | # Predict x and y | |
| 127 | if k==0 | |
| 128 | if init_data | |
| 129 | x .= b | |
| 130 | init_data = false | |
| 131 | end | |
| 132 | else | |
| 133 | # Displacement from previous to this image is estimated as | |
| 134 | # the difference of their displacements from beginning of window. | |
| 135 | if k>1 | |
| 136 | @. @views diffu = u[k, :] - u[k-1, :] | |
| 137 | else | |
| 138 | @. @views diffu = u[k, :] | |
| 139 | end | |
| 140 | ||
| 141 | pdflow!(x, Δx, y, Δy, diffu, params.dual_flow) | |
| 142 | end | |
| 143 | ||
| 144 | # Shift stored prox matrices | |
| 145 | if k==n | |
| 146 | tmp = copy(u[1, :]) | |
| 147 | ucumulbase .+= tmp | |
| 148 | for j=1:(n-1) | |
| 149 | @. @views u[j, :] = u[j+1, :] - tmp | |
| 150 | hs[j] = hs[j+1] | |
| 151 | end | |
| 152 | # Create new struct as original contains references to objects that | |
| 153 | # have been moved to index n-1. | |
| 154 | hs[n]=ConstantDisplacementHornSchunckData() | |
| 155 | else | |
| 156 | k += 1 | |
| 157 | end | |
| 158 | ||
| 159 | # Predict u: zero displacement from current to next image, i.e., | |
| 160 | # same displacement to beginning of window. | |
| 161 | if k==1 | |
| 162 | @. @views u[k, :] = 0.0 | |
| 163 | else | |
| 164 | @. @views u[k, :] = u[k-1, :] | |
| 165 | end | |
| 166 | ||
| 167 | # Predictor proximals tep | |
| 168 | if params.prox_predict | |
| 169 | ∇₂!(Δy, x) | |
| 170 | @. y = (y + σ̃*Δy)/(1 + σ̃*(ρ̃+ρ/α)) | |
| 171 | proj_norm₂₁ball!(y, α) | |
| 172 | end | |
| 173 | ||
| 174 | ################################################################################# | |
| 175 | # PDPS step | |
| 176 | # | |
| 177 | # For the displacements, with τ̃=τ/k, we need to solve for 2≤j<k, | |
| 178 | # | |
| 179 | # (1) (I/τ̃+M₀^j+M₀^{j+1})u^j = M₀^ju^{j-1} + M₀^{j+1}u^{j+1} | |
| 180 | # + ũ^j/τ̃ - z^j + z^{j+1}, | |
| 181 | # | |
| 182 | # as well as | |
| 183 | # | |
| 184 | # (2) (I/τ̃+M₀^k)u^k = M₀^k u^{k-1} + ũ^k/τ̃ - z^k | |
| 185 | # | |
| 186 | # and | |
| 187 | # | |
| 188 | # (3) (I/τ̃+M₀^1+M₀^2)u^1 = 0 + M₀^{2}u^{2} + ũ^1/τ̃ - z^1 + z^{2} | |
| 189 | # | |
| 190 | # We first construct from (2) that | |
| 191 | # | |
| 192 | # u^k = A^k u^{k-1} + d^k | |
| 193 | # | |
| 194 | # for | |
| 195 | # | |
| 196 | # A^k := (I/τ̃+M₀^k)^{-1} M₀^k | |
| 197 | # d_k := (I/τ̃+M₀^k)^{-1} (ũ^k/τ̃ - z^k). | |
| 198 | # | |
| 199 | # Inserting this into (1) we need | |
| 200 | # | |
| 201 | # (4) (I/τ̃+M₀^j+M₀^{j+1}(I-A^{j+1}))u^j = M₀^ju^{j-1} + M₀^{j+1}d^{j+1} | |
| 202 | # + ũ^j/τ̃ - z^j + z^{j+1}. | |
| 203 | # | |
| 204 | # This is well-defined because A^{j+1} < I. It also has the same form as (1), so | |
| 205 | # we continue with | |
| 206 | # | |
| 207 | # (5) u^j = A^j u^{j-1} + d^j | |
| 208 | # | |
| 209 | # for | |
| 210 | # | |
| 211 | # A^j := (I/τ̃+M₀^j+M₀^{j+1}(I-A^{j+1}))^{-1} M₀^j | |
| 212 | # d^j := (I/τ̃+M₀^j+M₀^{j+1}(I-A^{j+1}))^{-1} | |
| 213 | # (M₀^{j+1}d^{j+1} + ũ^j/τ̃ - z^j + z^{j+1}) | |
| 214 | # | |
| 215 | # Finally from (3) with these we need | |
| 216 | # | |
| 217 | # (I/τ̃+M₀^1+M₀^2(I-A^2))u^1 = M₀^2d^2 + ũ^1/τ̃ - z^1 + z^2, | |
| 218 | # | |
| 219 | # which is of the same form as (4) with u^0=0, so by (5) u^1=d^1. | |
| 220 | # | |
| 221 | ################################################################################# | |
| 222 | ||
| 223 | ∇₂ᵀ!(Δx, y) # primal step: | |
| 224 | @. x̄ = x # | save old x for over-relax | |
| 225 | @. x = (x-τ*(Δx-b))/(1+τ) # | prox | |
| 226 | # | | for displacement | |
| 227 | # Calculate matrices for latest data; rest is stored. | |
| 228 | @views begin | |
| 229 | horn_schunck_reg_prox_op!(hs[k], b_next_filt, b_filt, θ, λ, T) | |
| 230 | ||
| 231 | τ̃=τ/k | |
| 232 | ||
| 233 | B = hs[k].M₀ | |
| 234 | c = u[k, :]./τ̃-hs[k].z | |
| 235 | mldivide_step_plus_sym2x2!(A[k, :, :], B, B, τ̃) | |
| 236 | mldivide_step_plus_sym2x2!(d[k, :], B, c, τ̃) | |
| 237 | ||
| 238 | for j=(k-1):-1:1 | |
| 239 | B = hs[j].M₀+hs[j+1].M₀*([1 0; 0 1]-A[j+1, :, :]) | |
| 240 | c = hs[j+1].M₀*d[j+1, :]+u[j, :]./τ̃-hs[j].z+hs[j+1].z | |
| 241 | mldivide_step_plus_sym2x2!(A[j, :, :], B, hs[j].M₀, τ̃) | |
| 242 | mldivide_step_plus_sym2x2!(d[j, :], B, c, τ̃) | |
| 243 | end | |
| 244 | ||
| 245 | u[1, :] .= d[1, :] | |
| 246 | for j=2:k | |
| 247 | u[j, :] .= A[j, :, :]*u[j-1, :] + d[j, :] | |
| 248 | end | |
| 249 | end | |
| 250 | ||
| 251 | @. x̄ = 2x - x̄ # over-relax: x̄ = 2x-x_old | |
| 252 | ∇₂!(Δy, x̄) # dual step: y | |
| 253 | @. y = (y + σ*Δy)/(1 + σ*ρ/α) # | | |
| 254 | proj_norm₂₁ball!(y, α) # | prox | |
| 255 | ||
| 256 | ######################################################## | |
| 257 | # Give function value and cumulative movement if needed | |
| 258 | ######################################################## | |
| 259 | v = verbose() do | |
| 260 | ∇₂!(Δy, x) | |
| 261 | hs_plus_reg=0 | |
| 262 | for j=1:k | |
| 263 | v=(j==1 ? u[j, :] : u[j, :]-u[j-1, :]) | |
| 264 | hs_plus_reg += hs[j].cv/2 + dot(hs[j].Mv*v, v)/2+dot(hs[j].av, v) | |
| 265 | end | |
| 266 | value = (norm₂²(b-x)/2 + hs_plus_reg/k + α*γnorm₂₁(Δy, ρ)) | |
| 267 | ||
| 268 | value, x, u[k, :]+ucumulbase, u[1:k,:].+ucumulbase' | |
| 269 | end | |
| 270 | ||
| 271 | return v | |
| 272 | end | |
| 273 | ||
| 274 | return x, y, v | |
| 275 | end | |
| 276 | ||
| 277 | end # Module | |
| 278 | ||
| 279 |