Thu, 25 Apr 2024 19:16:17 +0300
seed number changed
16 | 1 | #################################################################### |
2 | # Predictive online PDPS for optical flow with known velocity field | |
3 | #################################################################### | |
4 | ||
5 | __precompile__() | |
6 | ||
7 | module AlgorithmZeroDual | |
8 | ||
9 | identifier = "pdps_known_zerodual" | |
10 | ||
11 | using Printf | |
12 | ||
13 | using AlgTools.Util | |
14 | import AlgTools.Iterate | |
15 | using ImageTools.Gradient | |
16 | using ImageTools.Translate | |
17 | ||
18 | using ..Radon | |
19 | using ImageTransformations | |
20 | using Images, CoordinateTransformations, Rotations, OffsetArrays | |
21 | using ImageCore, Interpolations | |
22 | ||
23 | using ..OpticalFlow: ImageSize, | |
24 | Image, | |
25 | petpdflow! | |
26 | ||
27 | ######################### | |
28 | # Iterate initialisation | |
29 | ######################### | |
30 | ||
31 | function init_rest(x::Image) | |
32 | imdim=size(x) | |
33 | y = zeros(2, imdim...) | |
34 | Δx = copy(x) | |
35 | Δy = copy(y) | |
36 | x̄ = copy(x) | |
37 | radonx = copy(x) | |
38 | return x, y, Δx, Δy, x̄, radonx | |
39 | end | |
40 | ||
41 | function init_iterates(xinit::Image) | |
42 | return init_rest(copy(xinit)) | |
43 | end | |
44 | ||
45 | function init_iterates(dim::ImageSize) | |
46 | return init_rest(zeros(dim...)) | |
47 | end | |
48 | ||
49 | ######################### | |
50 | # PETscan related | |
51 | ######################### | |
52 | function petvalue(x, b, c) | |
53 | tmp = similar(b) | |
54 | radon!(tmp, x) | |
55 | return sum(@. tmp - b*log(tmp+c)) | |
56 | end | |
57 | ||
58 | function petgrad!(res, x, b, c, S) | |
59 | tmp = similar(b) | |
60 | radon!(tmp, x) | |
61 | @. tmp = S .- b/(tmp+c) | |
62 | backproject!(res, S.*tmp) | |
63 | end | |
64 | ||
65 | function proj_nonneg!(y) | |
66 | @inbounds @simd for i=1:length(y) | |
67 | if y[i] < 0 | |
68 | y[i] = 0 | |
69 | end | |
70 | end | |
71 | return y | |
72 | end | |
73 | ||
74 | ############ | |
75 | # Algorithm | |
76 | ############ | |
77 | ||
78 | function solve( :: Type{DisplacementT}; | |
79 | dim :: ImageSize, | |
80 | iterate = AlgTools.simple_iterate, | |
81 | params::NamedTuple) where DisplacementT | |
82 | ||
83 | ################################ | |
84 | # Extract and set up parameters | |
85 | ################################ | |
86 | α, ρ = params.α, params.ρ | |
87 | R_K² = ∇₂_norm₂₂_est² | |
88 | γ = 1 | |
89 | L = params.L | |
90 | τ₀, σ₀ = params.τ₀, params.σ₀ | |
91 | τ = τ₀/L | |
92 | σ = σ₀*(1-τ₀)/(R_K²*τ) | |
93 | ||
94 | println("Step length parameters: τ=$(τ), σ=$(σ)") | |
95 | ||
96 | λ = params.λ | |
97 | c = params.c*ones(params.radondims...) | |
98 | ||
99 | ||
100 | ###################### | |
101 | # Initialise iterates | |
102 | ###################### | |
103 | ||
104 | x, y, Δx, Δy, x̄, r∇ = init_iterates(dim) | |
105 | ||
106 | if params.L_experiment | |
107 | oldpetgradx = zeros(size(x)...) | |
108 | petgradx = zeros(size(x)) | |
109 | oldx = ones(size(x)) | |
110 | end | |
111 | ||
112 | #################### | |
113 | # Run the algorithm | |
114 | #################### | |
115 | ||
116 | v = iterate(params) do verbose :: Function, | |
117 | b :: Image, # noisy_sinogram | |
118 | v_known :: DisplacementT, | |
119 | theta_known :: DisplacementT, | |
120 | b_true :: Image, | |
121 | S :: Image | |
122 | ||
123 | ################### | |
124 | # Prediction steps | |
125 | ################### | |
126 | ||
127 | petpdflow!(x, Δx, y, Δy, v_known, theta_known, false) | |
128 | y .= zeros(size(y)...) | |
129 | ||
130 | if params.L_experiment | |
131 | @. oldx = x | |
132 | end | |
133 | ||
134 | ############ | |
135 | # PDPS step | |
136 | ############ | |
137 | ||
138 | ∇₂ᵀ!(Δx, y) # primal step: | |
139 | @. x̄ = x # | save old x for over-relax | |
140 | petgrad!(r∇, x, b, c, S) # | Calculate gradient of fidelity term | |
141 | ||
142 | @. x = x-(τ*λ)*r∇-τ*Δx # | | |
143 | proj_nonneg!(x) # | non-negativity constaint prox | |
144 | @. x̄ = 2x - x̄ # over-relax: x̄ = 2x-x_old | |
145 | ∇₂!(Δy, x̄) # dual step: | |
146 | @. y = y + σ*Δy # | | |
147 | proj_norm₂₁ball!(y, α) # | prox | |
148 | ||
149 | ##################### | |
150 | # L update if needed | |
151 | ##################### | |
152 | if params.L_experiment | |
153 | petgrad!(petgradx, x, b, c, S) | |
154 | petgrad!(oldpetgradx, oldx, b, c, S) | |
155 | if norm₂(x-oldx)>1e-12 | |
156 | L = max(0.9*norm₂(petgradx - oldpetgradx)/norm₂(x-oldx),L) | |
157 | println("Step length parameters: L=$(L)") | |
158 | τ = τ₀/L | |
159 | σ = σ₀*(1-τ₀)/(R_K²*τ) | |
160 | end | |
161 | end | |
162 | ||
163 | ################################ | |
164 | # Give function value if needed | |
165 | ################################ | |
166 | ||
167 | v = verbose() do | |
168 | ∇₂!(Δy, x) | |
169 | value = λ*petvalue(x, b, c) + params.α*norm₂₁(Δy) | |
170 | value, x, [NaN, NaN], nothing, τ, σ | |
171 | end | |
172 | ||
173 | v | |
174 | end | |
175 | ||
176 | return x, y, v | |
177 | end | |
178 | ||
179 | end # Module | |
180 | ||
181 |