diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..8fce603003c1e5857013afec915ace9fc8bcdb8d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +data/ diff --git a/src/DualTVDD.jl b/src/DualTVDD.jl index 4fcafbd60c766079504ab15c871ce4fed0cd361d..220d7c8697c6e84008023b10099ce39ce4b95a0a 100644 --- a/src/DualTVDD.jl +++ b/src/DualTVDD.jl @@ -1,236 +1,193 @@ module DualTVDD +export init, step!, fetch, run + include("common.jl") include("problems.jl") include("chambolle.jl") include("dualtvdd.jl") include("projgrad.jl") -using Plots - -function run() - #g = [0. 2; 1 0.] - g = rand(10,10) - #g[4:17,4:17] .= 1 - #g[:size(g, 1)÷2,:] .= 1 - #g = [0. 2; 1 0.] - display(g) - - B = 0.1 * rand(length(g), length(g)) - B .+= diagm(ones(length(g))) - λ = 0.025 - - display(norm(B)) - - prob = DualTVDD.DualTVL1ROFOpProblem(g, B, λ) - ctx = DualTVDD.init(DualTVDD.ChambolleAlgorithm(prob)) - ctx2 = DualTVDD.init(DualTVDD.ProjGradAlgorithm(prob, τ=1/sqrt(8)/norm(B))) - - #scene = vbox( - # heatmap(ctx.s, colorrange=(0,1), colormap=:gray, scale_plot=false, show_axis=false), - # heatmap(ctx.s, colorrange=(0,1), colormap=:gray, scale_plot=false, show_axis=false), - # ) - #display(scene) - - #hm = last(scene) - for i in 1:10000 - step!(ctx) - step!(ctx2) - #hm[1] = ctx.s - #yield() - #sleep(0.2) - end - display(copy(ctx.p)) - #display(copy(recover_u!(ctx))) - println(energy(ctx)) - - println() - - display(copy(ctx2.p)) - #display(copy(recover_u!(ctx2))) - println(energy(ctx2)) - - ctx, ctx2 - #hm[1] = ctx.s - #yield() -end - -function alg_energy(alg, niter) - print("run ...") - res = Float64[] - (p, ctx) = iterate(alg) - push!(res, energy(ctx)) - for i in 1:niter - (p, ctx) = iterate(alg, ctx) - push!(res, energy(ctx)) - end - println(" finished") - return res -end - -function alg_error(alg, pmin, niter, ninner=1) - print("run ...") - res = Float64[] - ctx = init(alg) - push!(res, error(fetch(ctx), pmin, ctx.algorithm.problem)) - for i in 1:niter - for j in 1:ninner - step!(ctx) - end - push!(res, error(fetch(ctx), pmin, ctx.algorithm.problem)) - end - println(" finished") - return res -end - -function calc_energy(prob, niter) - alg_ref = DualTVDD.ChambolleAlgorithm(prob) - ctx = init(alg_ref) - for i in 1:niter - ctx = step!(ctx) - end - return energy(ctx), fetch(ctx) -end - -function rundd() - λ = 2.5 - β = 0 - #f = zeros(100,100) - #f[1] = 1 - #f = [0. 2; 1 0.] - - - #A = 0. * rand(length(f), length(f)) - #A .+= diagm(ones(length(f))) - #B = inv(A'*A + β*I) - - #g = similar(f) - #vec(g) .= A' * vec(f) - - g = rand(50, 50) - - prob = DualTVDD.DualTVL1ROFOpProblem(g, I, λ) - - alg_ref = DualTVDD.ChambolleAlgorithm(prob) - alg_dd = DualTVDD.DualTVDDAlgorithm(prob, M=(2,2), overlap=(4,4)) - alg_dd2 = DualTVDD.DualTVDDAlgorithm(prob, M=(2,2), overlap=(4,4), parallel=false) - - n = 1000 - - ref_energy, pmin = calc_energy(prob, 100000) - - lognan(x) = x > 0 ? x : NaN - - #y = [ - # lognan.(alg_energy(alg_ref, n) .- ref_energy), - # lognan.(alg_energy(alg_dd, n) .- ref_energy), - # lognan.(alg_energy(alg_dd2, n) .- ref_energy), - # ] - y = [ - lognan.(alg_error(alg_ref, pmin, n, 10)), - lognan.(alg_error(alg_dd, pmin, n)), - lognan.(alg_error(alg_dd2, pmin, n)), - ] - - plt = plot(y, xaxis=:log, yaxis=:log) - display(plt) - - #display(energy(ctx)) - #display(ctx.p) - #display(recover_u(p, prob)) - - #println(energy(ctx)) - #println(energy(ctx2)) -end - -function run3() - f = rand(20,20) - A = 0.1*rand(length(f), length(f)) - A .+= diagm(ones(length(f))) - - g = reshape(A'*vec(f), size(f)) - - β = 0 - B = inv(A'*A + β*I) - println(norm(A)) - - λ = 0.1 - - # Chambolle - md = DualTVDD.DualTVL1ROFOpProblem(g, B, λ) - alg = DualTVDD.ChambolleAlgorithm() - ctx = DualTVDD.init(md, alg) - - # Projected Gradient - md = DualTVDD.DualTVL1ROFOpProblem(f, A, λ, 0., 0.) - alg = DualTVDD.ProjGradAlgorithm(λ = 1/norm(A)^2) - ctx2 = DualTVDD.init(md, alg) - - for i in 1:100000 - step!(ctx) - step!(ctx2) - end - - #display(ctx.p) - #display(ctx2.p) - display(recover_u!(ctx)) - display(recover_u!(ctx2)) - - println(energy(ctx)) - println(energy(ctx2)) - - ctx, ctx2 -end - -function energy(ctx::Union{DualTVDDState,ProjGradState,ChambolleState}) - return energy(ctx.p, ctx.algorithm.problem) -end - -function error(p, pmin, prob::DualTVL1ROFOpProblem) - return energy_norm(p .- pmin, prob) / energy(pmin, prob) -end - -function energy(p, prob::DualTVL1ROFOpProblem) - d = ndims(p) - - @inline kfΛ(w) = @inbounds divergence(w) - kΛ = Kernel{ntuple(_->-1:1, d)}(kfΛ) - - v = similar(prob.g) - - # v = div(p) + g - map!(kΛ, v, extend(p, StaticKernels.ExtensionNothing())) - v .+= prob.g - #display(v) - - # |v|_B^2 / 2 - u = prob.B * vec(v) - return sum(u .* vec(v)) / 2 -end - -function energy_norm(p, prob::DualTVL1ROFOpProblem) - d = ndims(p) - - @inline kfΛ(w) = @inbounds divergence(w) - kΛ = Kernel{ntuple(_->-1:1, d)}(kfΛ) - - v = similar(prob.g) - - # v = div(p) - map!(kΛ, v, extend(p, StaticKernels.ExtensionNothing())) - #display(v) - - # |v|_B^2 / 2 - u = prob.B * vec(v) - return sum(u .* vec(v)) / 2 -end - - -function energy(md::DualTVL1ROFOpProblem, u::AbstractMatrix) - @inline kf(w) = @inbounds 1/2 * (w[0,0] - md.g[w.position])^2 + - md.λ * sqrt((w[1,0] - w[0,0])^2 + (w[0,1] - w[0,0])^2) - k = Kernel{(0:1, 0:1)}(kf, StaticKernels.ExtensionReplicate()) - return sum(k, u) -end +#using Plots: heatmap +# +#plotimage(u) = heatmap(u, c=:grayC, legend=:none, framestyle=:none, aspect_ratio=1) +# +#function alg_energy(alg, niter) +# print("run ...") +# res = Float64[] +# (p, ctx) = iterate(alg) +# push!(res, energy(ctx)) +# for i in 1:niter +# (p, ctx) = iterate(alg, ctx) +# push!(res, energy(ctx)) +# end +# println(" finished") +# return res +#end +# +#function alg_error(alg, pmin, niter, ninner=1) +# print("run ...") +# res = Float64[] +# ctx = init(alg) +# push!(res, error(fetch(ctx), pmin, ctx.algorithm.problem)) +# for i in 1:niter +# for j in 1:ninner +# step!(ctx) +# end +# push!(res, error(fetch(ctx), pmin, ctx.algorithm.problem)) +# end +# println(" finished") +# return res +#end +# +#function calc_energy(prob, niter) +# alg_ref = DualTVDD.ChambolleAlgorithm(prob) +# ctx = init(alg_ref) +# for i in 1:niter +# ctx = step!(ctx) +# end +# return energy(ctx), fetch(ctx) +#end +# +#function rundd() +# λ = 2.5 +# β = 0 +# #f = zeros(100,100) +# #f[1] = 1 +# #f = [0. 2; 1 0.] +# +# +# #A = 0. * rand(length(f), length(f)) +# #A .+= diagm(ones(length(f))) +# #B = inv(A'*A + β*I) +# +# #g = similar(f) +# #vec(g) .= A' * vec(f) +# +# g = rand(50, 50) +# +# prob = DualTVDD.DualTVL1ROFOpProblem(g, I, λ) +# +# alg_ref = DualTVDD.ChambolleAlgorithm(prob) +# alg_dd = DualTVDD.DualTVDDAlgorithm(prob, M=(2,2), overlap=(4,4)) +# alg_dd2 = DualTVDD.DualTVDDAlgorithm(prob, M=(2,2), overlap=(4,4), parallel=false) +# +# n = 1000 +# +# ref_energy, pmin = calc_energy(prob, 100000) +# +# lognan(x) = x > 0 ? x : NaN +# +# #y = [ +# # lognan.(alg_energy(alg_ref, n) .- ref_energy), +# # lognan.(alg_energy(alg_dd, n) .- ref_energy), +# # lognan.(alg_energy(alg_dd2, n) .- ref_energy), +# # ] +# y = [ +# lognan.(alg_error(alg_ref, pmin, n, 10)), +# lognan.(alg_error(alg_dd, pmin, n)), +# lognan.(alg_error(alg_dd2, pmin, n)), +# ] +# +# plt = plot(y, xaxis=:log, yaxis=:log) +# display(plt) +# +# #display(energy(ctx)) +# #display(ctx.p) +# #display(recover_u(p, prob)) +# +# #println(energy(ctx)) +# #println(energy(ctx2)) +#end +# +#function run3() +# f = rand(20,20) +# A = 0.1*rand(length(f), length(f)) +# A .+= diagm(ones(length(f))) +# +# g = reshape(A'*vec(f), size(f)) +# +# β = 0 +# B = inv(A'*A + β*I) +# println(norm(A)) +# +# λ = 0.1 +# +# # Chambolle +# md = DualTVDD.DualTVL1ROFOpProblem(g, B, λ) +# alg = DualTVDD.ChambolleAlgorithm() +# ctx = DualTVDD.init(md, alg) +# +# # Projected Gradient +# md = DualTVDD.DualTVL1ROFOpProblem(f, A, λ, 0., 0.) +# alg = DualTVDD.ProjGradAlgorithm(λ = 1/norm(A)^2) +# ctx2 = DualTVDD.init(md, alg) +# +# for i in 1:100000 +# step!(ctx) +# step!(ctx2) +# end +# +# #display(ctx.p) +# #display(ctx2.p) +# display(recover_u!(ctx)) +# display(recover_u!(ctx2)) +# +# println(energy(ctx)) +# println(energy(ctx2)) +# +# ctx, ctx2 +#end +# +#function energy(ctx::Union{DualTVDDState,ProjGradState,ChambolleState}) +# return energy(ctx.p, ctx.algorithm.problem) +#end +# +#function error(p, pmin, prob::DualTVL1ROFOpProblem) +# return energy_norm(p .- pmin, prob) / energy(pmin, prob) +#end +# +#function energy(p, prob::DualTVL1ROFOpProblem) +# d = ndims(p) +# +# @inline kfΛ(w) = @inbounds divergence(w) +# kΛ = Kernel{ntuple(_->-1:1, d)}(kfΛ) +# +# v = similar(prob.g) +# +# # v = div(p) + g +# map!(kΛ, v, extend(p, StaticKernels.ExtensionNothing())) +# v .+= prob.g +# #display(v) +# +# # |v|_B^2 / 2 +# u = prob.B * vec(v) +# return sum(u .* vec(v)) / 2 +#end +# +#function energy_norm(p, prob::DualTVL1ROFOpProblem) +# d = ndims(p) +# +# @inline kfΛ(w) = @inbounds divergence(w) +# kΛ = Kernel{ntuple(_->-1:1, d)}(kfΛ) +# +# v = similar(prob.g) +# +# # v = div(p) +# map!(kΛ, v, extend(p, StaticKernels.ExtensionNothing())) +# #display(v) +# +# # |v|_B^2 / 2 +# u = prob.B * vec(v) +# return sum(u .* vec(v)) / 2 +#end +# +# +#function energy(md::DualTVL1ROFOpProblem, u::AbstractMatrix) +# @inline kf(w) = @inbounds 1/2 * (w[0,0] - md.g[w.position])^2 + +# md.λ * sqrt((w[1,0] - w[0,0])^2 + (w[0,1] - w[0,0])^2) +# k = Kernel{(0:1, 0:1)}(kf, StaticKernels.ExtensionReplicate()) +# return sum(k, u) +#end end # module diff --git a/src/chambolle.jl b/src/chambolle.jl index 148937967f4d2b48efa56b6eb5872561470cef3c..fd8d0b995edbbdd221ba3e87e52cd9a16a6bee5c 100644 --- a/src/chambolle.jl +++ b/src/chambolle.jl @@ -48,18 +48,25 @@ struct ChambolleState{A,T,R,S,Sv,K1,K2} <: State k2::K2 end -projnorm(v, anisotropic) = anisotropic ? abs.(v) : norm(v) +projnorm(v) = projnorm(v, false) +projnorm(v, anisotropic) = anisotropic ? abs.(v) : norm(vec(v)) +const SVectorNest = SArray{<:Any,<:SArray{<:Any,Float64,1},1} +# TODO: respect anisotropic +#@inline projnorm(v::SVectorNest, _) = norm(norm.(v)) +@inline projnorm(v::SVectorNest, _) = sqrt(sum(sum(v[i] .^ 2) for i in eachindex(v))) function init(alg::ChambolleAlgorithm{<:DualTVL1ROFOpProblem}) g = alg.problem.g λ = alg.problem.λ d = ndims(g) - pv = zeros(d * length(g)) - rv = zeros(length(g)) + + pv = zeros(d * length(reinterpret(Float64, g))) + rv = zeros(eltype(g), length(g)) sv = zero(rv) - p = extend(reshape(reinterpret(SVector{d,Float64}, pv), size(g)), StaticKernels.ExtensionNothing()) - r = reshape(reinterpret(Float64, rv), size(g)) - s = extend(reshape(reinterpret(Float64, sv), size(g)), StaticKernels.ExtensionReplicate()) + + p = extend(reshape(reinterpret(SVector{d,eltype(g)}, pv), size(g)), StaticKernels.ExtensionNothing()) + r = reshape(rv, size(g)) + s = extend(reshape(sv, size(g)), StaticKernels.ExtensionReplicate()) @inline kf1(pw) = @inbounds divergence(pw) + g[pw.position] k1 = Kernel{ntuple(_->-1:1, d)}(kf1) @@ -78,6 +85,13 @@ function reset!(ctx::ChambolleState) fill!(ctx.p, zero(eltype(ctx.p))) end +# special case for diagonal ops +function LinearAlgebra.mul!(Y::AbstractVector{<:SVector}, A, B::AbstractVector{<:SVector}) + for i in eachindex(Y) + Y[i] = A[i,i] * B[i] + end +end + function step!(ctx::ChambolleState) alg = ctx.algorithm # r = div(p) + g diff --git a/src/common.jl b/src/common.jl index 29a2d9e116b1ef0db307eb335051e2ab222088cb..431f0ecd4d7c60ba4286a11302d361c0cbd1bccf 100644 --- a/src/common.jl +++ b/src/common.jl @@ -5,7 +5,7 @@ using StaticKernels <:Problem The abstract type hierarchy specifies the problem model interface (problem, -available data, available oracles). +available data, available oracles, solution form). """ abstract type Problem end diff --git a/src/dualtvdd.jl b/src/dualtvdd.jl index f3925fff20f64b6949777a759208b2eebc6640a5..77edede32a238281a490839679b42ff58242379c 100644 --- a/src/dualtvdd.jl +++ b/src/dualtvdd.jl @@ -37,15 +37,15 @@ function init(alg::DualTVDDAlgorithm{<:DualTVL1ROFOpProblem}) # subdomain axes subax = subaxes(size(g), alg.M, alg.overlap) # preallocated data for subproblems - subg = [Array{Float64, d}(undef, length.(x)) for x in subax] + subg = [Array{eltype(g), d}(undef, length.(x)) for x in subax] # locally dependent tv parameter subλ = [alg.problem.λ[subax[i]...] .* theta.(Ref(ax), Ref(subax[i]), Ref(alg.overlap), CartesianIndices(subax[i])) for i in CartesianIndices(subax)] # global dual variable - p = zeros(SVector{d,Float64}, size(g)) + p = zeros(SVector{d,eltype(g)}, size(g)) # local buffer variables - q = [extend(zeros(SVector{d,Float64}, length.(x)), StaticKernels.ExtensionNothing()) for x in subax] + q = [extend(zeros(SVector{d,eltype(g)}, length.(x)), StaticKernels.ExtensionNothing()) for x in subax] # create subproblem contexts li = LinearIndices(ax) @@ -132,6 +132,11 @@ fetch(ctx::DualTVDDState) = ctx.p end op_restrict(B::UniformScaling, ax, sax) = B +function op_restrict(B::Diagonal, ax, sax) + Bdiag = diag(B) + li = LinearIndices(ax) + return Diagonal(vec(collect(Bdiag[li[i]] for i in CartesianIndices(sax)))) +end function op_restrict(B, ax, sax) li = LinearIndices(ax) si = vec(li[sax...]) diff --git a/src/problems.jl b/src/problems.jl index 6f6a81cbe00eb3aa87f1835923ed28dfe6d4c340..63957f47946d73137e9a2beb443c9fccbc9b0084 100644 --- a/src/problems.jl +++ b/src/problems.jl @@ -1,4 +1,4 @@ -using LinearAlgebra: UniformScaling +using LinearAlgebra: UniformScaling, Diagonal #"min_u 1/2 * |Au-f|_2^2 + λ*TV(u) + β/2 |u|_2 + γ |u|_1" "min_p 1/2 * |p₂ - div(p₁) - g|_B^2 + χ_{|p₁|≤λ} + χ_{|p₂|≤γ}" @@ -14,7 +14,8 @@ struct DualTVL1ROFOpProblem{Tg,TB,Tλ,Tγ} <: Problem end DualTVL1ROFOpProblem(g, B, λ) = DualTVL1ROFOpProblem(g, B, λ, nothing) -DualTVL1ROFOpProblem(g, B, λ::Real) = DualTVL1ROFOpProblem(g, B, fill!(similar(g), λ)) +DualTVL1ROFOpProblem(g, B, λ::Real) = DualTVL1ROFOpProblem(g, B, fill!(similar(g, typeof(λ)), λ)) normB(p::DualTVL1ROFOpProblem{<:Any,<:UniformScaling}) = p.B.λ * sqrt(length(p.g)) normB(p::DualTVL1ROFOpProblem) = norm(p.B) +normB(p::DualTVL1ROFOpProblem{<:Any,<:Diagonal}) = sqrt(sum(norm.(diag(p.B)) .^ 2)) diff --git a/src/projgrad.jl b/src/projgrad.jl index e45080d956906ebc8bbe8db57fa5af6f608f9321..aa279c34cbcd1619a5e928b15b6f0556136fc798 100644 --- a/src/projgrad.jl +++ b/src/projgrad.jl @@ -32,26 +32,23 @@ end function init(alg::ProjGradAlgorithm{<:DualTVL1ROFOpProblem}) g = alg.problem.g + λ = alg.problem.λ d = ndims(g) - ax = axes(g) - p = extend(zeros(SVector{d,Float64}, ax), StaticKernels.ExtensionNothing()) - ge = extend(g, StaticKernels.ExtensionNothing()) + pv = zeros(d * length(reinterpret(Float64, g))) + rv = zeros(eltype(g), length(g)) + sv = zero(rv) - rv = zeros(length(g)) - sv = zeros(length(g)) + p = extend(reshape(reinterpret(SVector{d,eltype(g)}, pv), size(g)), StaticKernels.ExtensionNothing()) + r = reshape(rv, size(g)) + s = extend(reshape(sv, size(g)), StaticKernels.ExtensionReplicate()) - r = reshape(rv, ax) - s = extend(reshape(sv, ax), StaticKernels.ExtensionReplicate()) - - z = zero(CartesianIndex{d}) - - @inline kf1(pw) = @inbounds -divergence(pw) - ge[pw.position] + @inline kf1(pw) = @inbounds -divergence(pw) - g[pw.position] k1 = Kernel{ntuple(_->-1:1, d)}(kf1) @inline function kf2(pw, sw) - @inbounds q = pw[z] - alg.τ * gradient(sw) - return @inbounds q / max(norm(q) / alg.problem.λ[sw.position], 1) + @inbounds q = p[sw.position] - alg.τ * gradient(sw) + return @inbounds q ./ max.(projnorm(q) ./ λ[sw.position], 1) end k2 = Kernel{ntuple(_->0:1, d)}(kf2) diff --git a/test/inpaint.jl b/test/inpaint.jl new file mode 100644 index 0000000000000000000000000000000000000000..48db77548ca70af8ffc68e81286cf7be2c56dcbc --- /dev/null +++ b/test/inpaint.jl @@ -0,0 +1,47 @@ +using Revise +Revise.track(@__FILE__) + +using Colors: HSV +using DualTVDD: + ChambolleAlgorithm, ProjGradAlgorithm, + init, step!, fetch, recover_u +using FileIO +using Plots + + +function InpaintProblem(img::AbstractArray{T,d}, imgmask::AbstractArray{Bool,d}, λ, β = 1e-5) where {T,d} + Bval = inv.(imgmask .+ β .* Ref(I)) + B = Diagonal(vec(Bval)) + + g = imgmask .* img + return DualTVL1ROFOpProblem(g, B, λ) +end + +function run_inpaint(img, imgmask, λ=0.5, β=0.001) + prob = InpaintProblem(img, imgmask, λ, β) + #alg = ChambolleAlgorithm(prob, τ=0.0001) + alg = ProjGradAlgorithm(prob, τ=0.0001) + + ctx = init(alg) + for i in 1:10000 + step!(ctx) + end + plot_inpaint(ctx) + + return ctx +end + +function plot_inpaint(ctx) + u = recover_u(fetch(ctx), ctx.algorithm.problem) + + pltg = plot(Gray.(ctx.algorithm.problem.g), c=:grayC, legend=:none, framestyle=:none, aspect_ratio=1) + pltu = plot(Gray.(u), c=:grayC, legend=:none, framestyle=:none, aspect_ratio=1) + + #plt = plot(pltg, pltu, layout=(1,2)) + display(pltu) +end + +img = Float64.(load("data/other-data-gray/RubberWhale/frame10.png")) +imgmask = rand(Bool, size(img)) + +#run_inpaint(f0, f1) diff --git a/test/optflow.jl b/test/optflow.jl new file mode 100644 index 0000000000000000000000000000000000000000..63742f2ba80c3407bb722d441a452ad22b3b8c35 --- /dev/null +++ b/test/optflow.jl @@ -0,0 +1,58 @@ +using Revise +Revise.track(@__FILE__) + +using LinearAlgebra: Diagonal, dot + +using Colors: HSV +using DualTVDD: + DualTVL1ROFOpProblem, ChambolleAlgorithm, ProjGradAlgorithm, + init, step!, fetch, recover_u, gradient +using FileIO +using ImageIO +using Plots +using StaticKernels: Kernel, ExtensionReplicate, extend + + +function OptFlowProblem(f0::AbstractArray{T,d}, f1::AbstractArray{T,d}, λ, β = 1e-5) where {T,d} + ∇ = Kernel{ntuple(_->0:1, d)}(gradient) + ∇f0 = map(∇, extend(f0, ExtensionReplicate())) + + Bval = inv.(∇f0 .* adjoint.(∇f0) .+ β .* Ref(I)) + B = Diagonal(vec(Bval)) + + g = .-(f1 .- f0) .* ∇f0 + + return DualTVL1ROFOpProblem(g, B, λ) +end + +function run_optflow(f0, f1, λ=0.01, β=0.001) + prob = OptFlowProblem(f0, f1, λ, β) + #alg = ChambolleAlgorithm(prob, τ=1/10000) + alg = ProjGradAlgorithm(prob, τ=1/10000) + #alg = ProjGradAlgorithm(prob) + #alg = DualTVDD.DualTVDDAlgorithm(prob, M=(2,2), overlap=(4,4)) + + ctx = init(alg) + for i in 1:10000 + step!(ctx) + end + plot_optflow(ctx) + + return ctx +end + +color(v) = HSV(180 / pi * atan(v[1], v[2]), norm(v), 1) + +function plot_optflow(ctx) + u = recover_u(fetch(ctx), ctx.algorithm.problem) + + flowimg = color.(u) + + plt = plot(flowimg) + display(plt) +end + + +f0 = Float64.(load("data/other-data-gray/RubberWhale/frame10.png")) +f1 = Float64.(load("data/other-data-gray/RubberWhale/frame11.png")) +#run_optflow(f0, f1)