Last active
April 2, 2024 09:24
-
-
Save empet/b2447da03d99358fbf90cf2b039a6672 to your computer and use it in GitHub Desktop.
Image Warping Through a Complex Function
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Images, ImageTransformations, CoordinateTransformations, Interpolations | |
import StaticArrays: @SMatrix, @SVector, SVector | |
mutable struct ImageRectangle{T<:Real} | |
img::Union{Matrix{RGB{T}}, Matrix{Gray{T}}} | |
inprectangle::NamedTuple | |
outrectangle::NamedTuple | |
end | |
function check_rectangle(a, b, c, d) | |
(a<b && c<d) || error("[$a $b] or [$c,$d] is not an interval") | |
end | |
function ImageRectangle(img::Union{Matrix{RGB{T}}, Matrix{Gray{T}}}, | |
inprectangle::NamedTuple, | |
outrectangle::NamedTuple) where T <:Real | |
length(inprectangle) == 4 && length(outrectangle) == 4 || | |
error("the named tuples must have length 4") | |
check_rectangle(values(inprectangle)...) | |
check_rectangle(values(outrectangle)...) | |
return ImageRectangle{T}(img, inprectangle, outrectangle) | |
end | |
struct ComplexTransformation{T<:Function} <:Transformation | |
f::T | |
end | |
function (cplxtform::ComplexTransformation)(x::SVector{2, T}) where T<:Real | |
w = cplxtform.f(x[1]+im*x[2]) | |
@SVector [real(w), imag(w)] | |
end | |
struct ModTransformation <:Transformation | |
m::Int | |
n::Int | |
end | |
function (modtform::ModTransformation)(x::SVector{2,T}) where T<:Real | |
@SVector [Base.mod(x[1], modtform.m), Base.mod(x[2], modtform.n)] | |
end | |
function outpix2coord(obj::ImageRectangle) | |
""" | |
Affine transformation from output pixels to the corresponding output cartesian coords | |
""" | |
m, n = size(obj.img) | |
A, B, C, D = values(obj.outrectangle) | |
Mout = @SMatrix [0 (B-A)/(n-1); -(D-C)/(m-1) 0] | |
vout = @SVector [(A*n-B)/(n-1), (D*m-C)/(m-1)] | |
return AffineMap(Mout, vout) | |
end | |
function inpcoord2pix(obj::ImageRectangle) | |
""" | |
Affine transformation from input cartesian coords to corresponding (approx)pixels | |
""" | |
m, n = size(obj.img) | |
a, b, c, d =values(obj.inprectangle) | |
Minp = @SMatrix [0 -(m-1)/(d-c); (n-1)/(b-a) 0] | |
vinp = @SVector [(d*m-c)/(d-c), (b-a*n)/(b-a)] | |
return AffineMap(Minp, vinp) | |
end | |
function get_invtform(obj::ImageRectangle, invf::T) where T <: Function | |
affine_right = outpix2coord(obj) | |
affine_left = inpcoord2pix(obj) | |
icplxtform = ComplexTransformation(invf) #inverse of the complex transformation | |
affine_left ∘ icplxtform ∘ affine_right | |
end | |
function complexwarped(obj::ImageRectangle, invf::T; fillvalue=1, method=BSpline(Linear())) where T<: Function | |
m, n = size(obj.img) | |
invtform = get_invtform(obj, invf) | |
warp(obj.img, invtform, (1:m, 1:n); fillvalue=fillvalue, method=method) | |
end | |
function complexwarped(obj::ImageRectangle, invf::T, transf::Transformation; fillvalue=1, method=BSpline(Linear())) where T<: Function | |
m, n = size(obj.img) | |
invtform = get_invtform(obj, invf) | |
warp(obj.img, transf ∘ invtform, (1:m, 1:n); fillvalue=fillvalue, method=method) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment