diff --git a/scripts/run.jl b/scripts/run.jl index e7a2ed44c0575a68a380081e867b9f6e86866fc2..97bb1781224efc526324bf1ee998b07e16a91009 100644 --- a/scripts/run.jl +++ b/scripts/run.jl @@ -27,3 +27,5 @@ ctx(experiment_denoise, "fem/denoise") ctx(experiment_inpaint, "fem/inpaint") # adaptive optical flow ctx(experiment_optflow_middlebury_all, "fem/optflow/middlebury") + +# additional experiments for paper diff --git a/scripts/run_experiments.jl b/scripts/run_experiments.jl index 104a5e861b239dfe24a8dbaf187b9fa1e42b4d16..94670c932dfe694e39a6797d3717273f2fe7d6c8 100644 --- a/scripts/run_experiments.jl +++ b/scripts/run_experiments.jl @@ -28,6 +28,38 @@ isdefined(Main, :Revise) && Revise.track(joinpath(@__DIR__, "util.jl")) using .Util +module Operators + +struct TIdentity end +(::TIdentity)(tdata, u) = u +(::TIdentity)(::typeof(adjoint), tdata, v) = v +Base.show(io, ::MIME"text/latex", ::TIdentity) = + print(io, raw"\ensuremath{I}") + +struct TInpaint end +(::TInpaint)(tdata, u) = abs(tdata[begin] - 1.) < 1e-8 ? u : zero(u) +(T::TInpaint)(::typeof(adjoint), tdata, v) = T(tdata, v) +Base.show(io, ::MIME"text/latex", ::TInpaint) = + print(io, raw"\ensuremath{T_{\mathrm{inpaint}}}") + +struct TOptflow end +(::TOptflow)(tdata, u) = tdata * u +(::TOptflow)(::typeof(adjoint), tdata, v) = tdata' * v +Base.show(io, ::MIME"text/latex", ::TOptflow) = + print(io, raw"\ensuremath{T_{\mathrm{optflow}}}") + +struct SIdentity end +(::SIdentity)(u, nablau) = u +Base.show(io, ::MIME"text/latex", ::SIdentity) = + print(io, raw"\ensuremath{I}") + +struct SNabla end +(::SNabla)(u, nablau) = nablau' +Base.show(io, ::MIME"text/latex", ::SNabla) = + print(io, raw"\ensuremath{\nabla}") + +end + grayclamp(value) = Gray(clamp(value, 0., 1.)) loadimg(x) = Float64.(FileIO.load(x)) saveimg(io, x::Array{<:Gray}) = FileIO.save(io, grayclamp.(x)) @@ -156,7 +188,7 @@ function OptFlowState(mesh; # tdata will be something like nabla(fw) T(tdata, u) = tdata * u T(::typeof(adjoint), tdata, v) = tdata' * v - S(u, nablau) = nablau + S(u, nablau) = nablau' est = FeFunction(Vest, name = "est") g = FeFunction(Vg, name = "g") @@ -817,12 +849,8 @@ function denoise(ctx) mesh = init_grid(g_arr, floor.(Int, size(g_arr) ./ 2^(n_refine / 2))...) mesh_area = area(mesh) - T(tdata, u) = u - T(::typeof(adjoint), tdata, v) = v - S(u, nablau) = u - st = L1L2TVState{1}(mesh; - T, tdata = nothing, S, + T = Operators.TIdentity(), tdata = nothing, S = Operators.SIdentity(), ctx.params.alpha1, ctx.params.alpha2, ctx.params.lambda, ctx.params.beta, ctx.params.gamma1, ctx.params.gamma2) @@ -1276,33 +1304,37 @@ end function inpaint(ctx) # expect ctx.params.g_arr + #project_image! = project_l2_lagrange! project_image! = project_qi_lagrange! - n_refine = 5 # convert to cartesian coordinates g_arr = from_img(ctx.params.g_arr) mask_arr = from_img(ctx.params.mask_arr) - mesh = init_grid(g_arr, floor.(Int, size(g_arr) ./ 2^(n_refine / 2))...) + mesh = init_grid(g_arr, floor.(Int, size(g_arr) ./ 2^(ctx.params.n_refine / 2))...) mesh_area = area(mesh) # inpaint specific stuff Vg = FeSpace(mesh, P1(), (1,)) _mask = FeFunction(Vg, name = "mask") - T(tdata, u) = abs(tdata[begin] - 1.) < 1e-8 ? u : zero(u) - T(::typeof(adjoint), tdata, v) = T(tdata, v) - S(u, nablau) = u - st = L1L2TVState{1}(mesh; - T, tdata = _mask, S, + T = Operators.TInpaint(), tdata = _mask, ctx.params.S, ctx.params.alpha1, ctx.params.alpha2, ctx.params.lambda, ctx.params.beta, ctx.params.gamma1, ctx.params.gamma2) function interpolate_image_data!() println("interpolate image data ...") - project_image!(st.g, g_arr) + if ctx.params.n_refine == 0 + # if we use a grid at image resolution, we wan't to avoid + # information loss at all cost. + # projet_l2_pixel is not suited for inpainting as it is a global + # operator, which may leak data from the inpainting domain + interpolate!(st.g, x -> evaluate_bilinear(g_arr, x)) + else + project_image!(st.g, g_arr) + end project_image!(st.tdata, mask_arr) end @@ -1313,6 +1345,7 @@ function inpaint(ctx) pvd = paraview_collection(joinpath(ctx.outdir, "output.pvd")) do pvd interpolate_image_data!() + pvd[0] = save_step(0) i = 0 @@ -1338,7 +1371,7 @@ function inpaint(ctx) # refinement stop criterion k_refine += 1 - k_refine > n_refine && break + k_refine > ctx.params.n_refine && break println("refine ...") #estimate_res!(st) marked_cells = Set(mark(st; theta = 0.5)) @@ -1362,11 +1395,11 @@ function inpaint(ctx) #CSV.write(joinpath(ctx.outdir, "energies.csv"), df) u_sampled = sample(st.u) - saveimg(joinpath(ctx.outdir, "g.png"), to_img(g_arr)) + saveimg(joinpath(ctx.outdir, "g.png"), grayclamp.(to_img(g_arr))) saveimg(joinpath(ctx.outdir, "output.png"), grayclamp.(to_img(u_sampled))) save_csv(joinpath(ctx.outdir, "mesh.csv"), st.u) savedata(joinpath(ctx.outdir, "data.tex"); - ctx.params.eps_newton, n_refine, + ctx.params.eps_newton, ctx.params.n_refine, st.alpha1, st.alpha2, st.lambda, st.beta, st.gamma1, st.gamma2, width=size(u_sampled, 1), height=size(u_sampled, 2)) return st @@ -1377,15 +1410,44 @@ function experiment_inpaint(ctx) mask_arr = loadimg(joinpath(ctx.indir, "mask.png")) mesh = init_grid(g_arr;) - df = DataFrame() - inpaint(Util.Context(ctx; name = "test", df, + inpaint(Util.Context(ctx; name = "test", + S = Operators.SIdentity, + n_refine = 5, g_arr, mask_arr, mesh, alpha1 = 0., alpha2 = 50., lambda = 1., beta = 1e-5, gamma1 = 1e-4, gamma2 = 1e-4, - eps_newton = 1e-4, adaptive = true, + eps_newton = 1e-4, )) end +function experiment_inpaint_denoise(ctx) + g_arr = loadimg(joinpath(ctx.indir, "input.png")) + mask_arr = loadimg(joinpath(ctx.indir, "mask.png")) + mesh = init_grid(g_arr;) + + params = ( + name = "test", + n_refine = 0, + g_arr, mask_arr, mesh, + noise_sigma = 0.1, noise_p = 0.02, + alpha1 = 0.2, alpha2 = 8., lambda = 1., #= beta see below =# + gamma1 = 1e-4, gamma2 = 1e-4, + eps_newton = 1e-4) + + params.g_arr .= add_noise(g_arr; params.noise_sigma, params.noise_p) + saveimg(joinpath(ctx.outdir, "input_noisy.png"), grayclamp.(g_arr)) + + ctx(inpaint, "s-identity_beta-large"; params..., + S = Operators.SIdentity(), beta = 3e-1) + ctx(inpaint, "s-identity_beta-small"; params..., + S = Operators.SIdentity(), beta = 3e-4) + + ctx(inpaint, "s-nabla_beta-large"; params..., + S = Operators.SNabla(), beta = 5e1) + ctx(inpaint, "s-nabla_beta-small"; params..., + S = Operators.SNabla(), beta = 5e-2) +end + function optflow(ctx) size(ctx.params.imgf0) == size(ctx.params.imgf1) || throw(ArgumentError("non-matching image sizes"))