Package for smooth deformation of complex shapes.
Piecewise affine transformation resembles ordinary affine transformation, but instead of warping single region linearly, it splits down area under the question into a set of triangles and warps each such triangle separately.
Let's say, we have an image of a face and want to warp it to have different expression (destination image is here only for demonstration, we will not use it):
using PiecewiseAffineTransforms src_img = ... dst_img = ...
(full version of code is available in
|Source image||Destination image|
We will also assume that both faces are annotated with corresponding shape landmarks:
src_shape = ... # should be a Nx2 matrix of Float64, # where N is a number of landmarks dst_shape = ...
First of all, we need to split the shapes into triangles, i.e. triangulate them:
trigs = delaunayindexes(src_shape) # Tx3 matrix of Int, where T is # a number of resuling triangles # needs ImageView installed (Pkg.add("ImageView")) triplot(src_img, src_shape, trigs) triplot(dst_img, dst_shape, trigs)
WARNING: Triangulation is based on VoronoiDelaunay.jl, which currently has a bug resulting in one lost triangle from time to time. To overcome this, just get good sample of triangulation and save it for future use.
|Source shape||Destination shape|
dst_shape may be as simple as calling this:
@time warped = pa_warp(src_img, src_shape, dst_shape, trigs) # 1.44 seconds
But if you are going to repeat warping to
dst_shape for many source images or just many times, it's worth to prepare warp by creating
PAWarpParams object and using it for all future transformation to
@time pa_params = pa_warp_params(dst_shape, trigs, (480, 640)) # 5.92 seconds @time warped = pa_warp(pa_params, src_img, src_shape) # 0.075 seconds
But anyway, they both give (almost) the same result:
|Original image||Warped image|
Code for prepared warp was mostly extracted from ICAAM project by Luca Vezzaro.
6 months ago