RegisterDeformation

This package represents spatial deformations, sometimes also called diffeomorphisms or warps. Under a deformation, a rectangular grid might change into something like this:

diffeo

A deformation (or warp) of space is represented by a function ϕ(x). For an image, the warped version of the image is specified by "looking up" the pixel value at a location ϕ(x) = x + u(x). u(x) thus expresses the displacement, in pixels, at position x. Note that a constant deformation, u(x) = x0, corresponds to a shift of the coordinates by x0, and therefore a shift of the image in the opposite direction.

Currently this package supports just one kind of deformation, one defined on a rectangular grid of u values. The package is designed for the case where the number of positions in the u grid is much smaller than the number of pixels in your image. Between grid points, the deformation can be defined by interpolation. There are two "flavors" of such deformations, "naive" (constructed directly from a u array) and "interpolating" (one that has been prepared for interpolation). You can prepare a "naive" deformation for interpolation with ϕi = interpolate(ϕ); be aware that ϕi.u ≠ ϕ.u even though , but the two

You can obtain a summary of the major functions in this package with ?RegisterDeformation.

Demo

Let's load an image for testing:

using RegisterDeformation, TestImages
img = testimage("lighthouse")

Now we create a deformation over the span of the image:

# Create a deformation
gridsize = (5, 5)                   # a coarse grid
u = 20*randn(2, gridsize...)        # each displacement is 2-dimensional
# The nodes specify the location of each value in the `u` array
# relative to the image that we want to warp. This choice spans
# the entire image.
nodes = map(axes(img), gridsize) do ax, g
    range(first(ax), stop=last(ax), length=g)
end
ϕ = GridDeformation(u, nodes)

# output

5×5 GridDeformation{Float64} over a domain 1.0..512.0×1.0..768.0

This is a "naive" deformation, so we can't evaluate it at an arbitrary position:

julia> ϕ(3.2, 1.4)
ERROR: call `ϕi = interpolate(ϕ)` and use `ϕi` for evaluating the deformation.
Stacktrace:
 [1] error(::String) at ./error.jl:33
[...]

But it works if we create the corresponding interpolating deformation:

julia> ϕi = interpolate(ϕ)
Interpolating 5×5 GridDeformation{Float64} over a domain 1.0..512.0×1.0..768.0

julia> ϕi(3.2, 1.4)
2-element StaticArrays.SArray{Tuple{2},Float64,1,2} with indices SOneTo(2):
 4.5304980552861736
 2.913923557974086

Now let's use this to warp the image (note it's more efficient to use ϕi here, but warp will call interpolate for you if necessary):

imgw = warp(img, ϕ)
axes(imgw)

# output

(Base.OneTo(512), Base.OneTo(768))

You might get results somewhat like these:

OriginalWarped
lhwarped

The black pixels near the edge represent locations where the deformation ϕ returned a location that lies beyond the edge of the original image. The corresponding output pixels are marked with NaN values.