Skip to content
Snippets Groups Projects
Commit e398949b authored by Stephan Hilb's avatar Stephan Hilb
Browse files

implement image projection

parent a08de423
Branches
Tags
No related merge requests found
using Statistics: mean using Statistics: mean
using StaticArrays: SA, SArray, MVector, MMatrix using StaticArrays: SA, SArray, MVector, MMatrix
export FeSpace, Mapper, FeFunction, P1, DP0, DP1 export FeSpace, Mapper, FeFunction, ImageFunction, P1, DP0, DP1
export interpolate!, sample, bind!, evaluate, integrate, nabla export interpolate!, sample, bind!, evaluate, integrate, nabla
# Finite Elements # Finite Elements
...@@ -252,6 +252,20 @@ function evaluate(df::Derivative, x) ...@@ -252,6 +252,20 @@ function evaluate(df::Derivative, x)
return SArray{Tuple{df.f.space.size..., length(x)}}(jac) return SArray{Tuple{df.f.space.size..., length(x)}}(jac)
end end
# TODO: inherit from some abstract function type
struct ImageFunction{Img}
mesh::Mesh
img::Img
cell::Base.RefValue{Int}
end
ImageFunction(mesh, img) =
ImageFunction(mesh, img, Ref(1))
bind!(f::ImageFunction, cell) = f.cell[] = cell
evaluate(f::ImageFunction, xloc) =
interpolate_bilinear(f.img, elmap(f.mesh, f.cell[])(xloc))
function sample(f::FeFunction) function sample(f::FeFunction)
mesh = f.mapper.mesh mesh = f.mapper.mesh
......
...@@ -163,6 +163,9 @@ init_grid(img::Array{<:Any, 2}; type=:vertex) = ...@@ -163,6 +163,9 @@ init_grid(img::Array{<:Any, 2}; type=:vertex) =
init_grid(size(img, 1) - 1, size(img, 2) - 1, (1.0, 1.0), size(img)) : init_grid(size(img, 1) - 1, size(img, 2) - 1, (1.0, 1.0), size(img)) :
init_grid(size(img, 1), size(img, 2), (0.5, 0.5), size(img) .- (0.5, 0.5)) init_grid(size(img, 1), size(img, 2), (0.5, 0.5), size(img) .- (0.5, 0.5))
init_grid(img::Array{<:Any, 2}, m::Int, n::Int = m) =
init_grid(m, n, (0.5, 0.5), size(img) .- (0.5, 0.5))
# horribly implemented, please don't curse me # horribly implemented, please don't curse me
function bisect!(mesh::HMesh, marked_cells::Set) function bisect!(mesh::HMesh, marked_cells::Set)
refined_cells = Pair{Int, NTuple{2, Int}}[] refined_cells = Pair{Int, NTuple{2, Int}}[]
...@@ -337,7 +340,17 @@ function save(filename::String, mesh::Mesh, fs...) ...@@ -337,7 +340,17 @@ function save(filename::String, mesh::Mesh, fs...)
vtk_save(vtk) vtk_save(vtk)
end end
function diam(mesh, cell)
A = SArray{Tuple{ndims_space(mesh), nvertices_cell(mesh)}}(
view(mesh.vertices, :, view(mesh.cells, :, cell)))
return max(
norm(A[:, 1] - A[:, 2]),
norm(A[:, 2] - A[:, 3]),
norm(A[:, 3] - A[:, 1]))
end
function elmap(mesh, cell) function elmap(mesh, cell)
# TODO: can be improved
A = SArray{Tuple{ndims_space(mesh), nvertices_cell(mesh)}}( A = SArray{Tuple{ndims_space(mesh), nvertices_cell(mesh)}}(
view(mesh.vertices, :, view(mesh.cells, :, cell))) view(mesh.vertices, :, view(mesh.cells, :, cell)))
return x -> A * SA[1 - x[1] - x[2], x[1], x[2]] return x -> A * SA[1 - x[1] - x[2], x[1], x[2]]
......
...@@ -3,7 +3,7 @@ using LinearAlgebra: det, dot ...@@ -3,7 +3,7 @@ using LinearAlgebra: det, dot
using StaticArrays: SA, SArray, MArray using StaticArrays: SA, SArray, MArray
using ForwardDiff: jacobian using ForwardDiff: jacobian
export Poisson, L2Projection, init_point!, assemble export Poisson, L2Projection, init_point!, assemble, project_img
abstract type Operator end abstract type Operator end
...@@ -115,3 +115,95 @@ function assemble(space::FeSpace, a, l; params...) ...@@ -115,3 +115,95 @@ function assemble(space::FeSpace, a, l; params...)
A = sparse(I, J, V, ngdofs, ngdofs) A = sparse(I, J, V, ngdofs, ngdofs)
return A, b return A, b
end end
function project_img(space::FeSpace, img)
d = 2 # domain dimension
mesh = space.mesh
f = ImageFunction(mesh, img)
opparams = (; f)
nrdims = prod(space.size)
nldofs = ndofs(space.element) # number of element dofs (i.e. local dofs not counting range dimensions)
a(xloc, u, du, v, dv; f) = dot(u, v)
l(xloc, v, dv; f) = dot(f, v)
# composite midpoint quadrature on lagrange point lattice
function quadrature(p)
k = Iterators.filter(x -> sum(x) == p,
Iterators.product((0:p for _ in 1:d+1)...)) |> collect
weights = [1 / length(k) for _ in axes(k, 1)]
points = [x[i] / p for i in 1:2, x in k]
return weights::Vector{Float64}, points::Matrix{Float64}
end
I = Float64[]
J = Float64[]
V = Float64[]
b = zeros(ndofs(space))
gdof = LinearIndices((nrdims, ndofs(space)))
# mesh cells
for cell in cells(mesh)
foreach(f -> bind!(f, cell), opparams)
# cell map is assumed to be constant per cell
delmap = jacobian(elmap(mesh, cell), SA[0., 0.])
delmapinv = inv(delmap)
intel = abs(det(delmap))
p = ceil(Int, diam(mesh, cell))
qw, qx = quadrature(p)
nqpts = length(qw) # number of quadrature points
qphi = zeros(nrdims, nrdims, nldofs, nqpts)
dqphi = zeros(nrdims, d, nrdims, nldofs, nqpts)
for r in 1:nrdims
for k in axes(qx, 2)
qphi[r, r, :, k] .= evaluate_basis(space.element, qx[:, k])
dqphi[r, :, r, :, k] .= transpose(jacobian(x -> evaluate_basis(space.element, x), SVector{d}(qx[:, k])))
end
end
# quadrature points
for k in axes(qx, 2)
xhat = SVector{d}(qx[:, k])
x = elmap(mesh, cell)(xhat)
opvalues = map(f -> evaluate(f, xhat), opparams)
# local test-function dofs
for jdim in 1:nrdims, ldofj in 1:nldofs
gdofj = space.dofmap[jdim, ldofj, cell]
phij = SArray{Tuple{space.size...}}(qphi[:, jdim, ldofj, k])
dphij = SArray{Tuple{space.size..., d}}(dqphi[:, :, jdim, ldofj, k] * delmapinv)
lv = qw[k] * l(x, phij, dphij; opvalues...) * intel
b[gdofj] += lv
# local trial-function dofs
for idim in 1:nrdims, ldofi in 1:nldofs
gdofi = space.dofmap[idim, ldofi, cell]
phii = SArray{Tuple{space.size...}}(qphi[:, idim, ldofi, k])
dphii = SArray{Tuple{space.size..., d}}(dqphi[:, :, idim, ldofi, k] * delmapinv)
av = qw[k] * a(x, phii, dphii, phij, dphij; opvalues...) * intel
push!(I, gdofi)
push!(J, gdofj)
push!(V, av)
end
end
end
end
ngdofs = ndofs(space)
A = sparse(I, J, V, ngdofs, ngdofs)
u = FeFunction(space)
u.data .= A \ b
return u
end
...@@ -282,7 +282,8 @@ norm_l2(f) = sqrt(integrate(f.space.mesh, (x; f) -> dot(f, f); f)) ...@@ -282,7 +282,8 @@ norm_l2(f) = sqrt(integrate(f.space.mesh, (x; f) -> dot(f, f); f))
function denoise(img; name, params...) function denoise(img; name, params...)
m = 1 m = 1
mesh = init_grid(img; type=:vertex) #mesh = init_grid(img; type=:vertex)
mesh = init_grid(img, 5, 5)
T(tdata, u) = u T(tdata, u) = u
S(u, nablau) = u S(u, nablau) = u
...@@ -313,15 +314,20 @@ function denoise(img; name, params...) ...@@ -313,15 +314,20 @@ function denoise(img; name, params...)
println("primal energy: $(primal_energy(ctx))") println("primal energy: $(primal_energy(ctx))")
norm_step = sqrt(norm_l2(ctx.du)^2 + norm_l2(ctx.dp1)^2 + norm_l2(ctx.dp2)) norm_step = sqrt(norm_l2(ctx.du)^2 + norm_l2(ctx.dp1)^2 + norm_l2(ctx.dp2))
norm_step <= 1e-3 && break norm_step = sqrt(norm_l2(ctx.du)^2)
norm_step <= 1e-2 && break
end end
marked_cells = mark(ctx; theta = 0.5) marked_cells = mark(ctx; theta = 0.5)
#println(marked_cells) #println(marked_cells)
println("refining ...") println("refining ...")
ctx = refine(ctx, marked_cells) ctx = refine(ctx, marked_cells)
test_mesh(ctx.mesh) test_mesh(ctx.mesh)
gnew = project_img(ctx.g.space, img)
ctx.g.data .= gnew.data
#interpolate!(ctx.g, x -> norm(x .- m) < norm(m .- 1) / 3) #interpolate!(ctx.g, x -> norm(x .- m) < norm(m .- 1) / 3)
k >= 200 && break
k >= 50 && break
end end
vtk_save(pvd) vtk_save(pvd)
return ctx return ctx
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment