Skip to content

Instantly share code, notes, and snippets.

@empet
Last active November 10, 2025 21:41
Show Gist options
  • Select an option

  • Save empet/b2447da03d99358fbf90cf2b039a6672 to your computer and use it in GitHub Desktop.

Select an option

Save empet/b2447da03d99358fbf90cf2b039a6672 to your computer and use it in GitHub Desktop.
Image Warping Through a Complex Function
using Images, ImageTransformations, CoordinateTransformations, Interpolations
import StaticArrays: @SMatrix, @SVector, SVector
mutable struct ImageRectangle{S, T1, T2 <:Real}
img::Union{Matrix{RGB{S}}, Matrix{Gray{S}}}
inprectangle::NamedTuple{(:a, :b, :c, :d), NTuple{4, T1}}
outrectangle::NamedTuple{(:A, :B, :C, :D), NTuple{4, T2}}
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{S}}, Matrix{Gray{S}}},
inprectangle::NamedTuple{(:a, :b, :c, :d), NTuple{4, T1}},
outrectangle::NamedTuple{(:A, :B, :C, :D), NTuple{4, T2}}) where {S, T1, T2 <:Real}
check_rectangle(inprectangle...)
check_rectangle(outrectangle...)
return ImageRectangle{S, T1, T2}(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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment