Add `Projective` transformation
It's better to have Projective transformation to ImageTransformations.jl.
# Definition of projective transformation
"""
Projective transformation.
"""
struct Projective <: Transformation
H::SArray{Tuple{3,3},Float64,2,9}
end
"""
Definition of projective transformation.
"""
function (p::Projective)(x)
x_ = SA[x[1],x[2],1.0]
x′_1, x′_2, x′_3 = p.H*x_
return SA[x′_1/x′_3, x′_2/x′_3]
end
"""
Inverse of projective transformation.
"""
function Base.inv(p::Projective)
Projective(inv(p.H))
end
Discussions in Slack: https://julialang.slack.com/archives/CB1R90P8R/p1626929588093000 https://julialang.slack.com/archives/CB1R90P8R/p1626983453103200
I feel the right place to add this is in CoordinateTransformations.jl
Or we could 1) first introduce a high-level API in ImageTransformations.jl with this Projective as internal type, and then 2) migrate it to upstream CoordinateTransformations, and finally 3) use the upstream version.
(The quoted words are by @johnnychen94)
This issue can be seperated into two parts:
- we want an invertible projective transformation so that
warp's defaultinds = autorange(img, inv(tform))is happy with it. - we might want a high-level API in ImageTransformations so that normal users don't need to talk to
warpdirectly. We currently only haveimrotateandimresize.
we want an invertible projective transformation
The Projective version you propose definitely works, but maybe the following is a better patch (since it doesn't introduce new concepts to the codebase):
function Base.inv(tform::CoordinateTransformations.ComposedTransformation{PerspectiveMap})
PerspectiveMap() ∘ inv(tform.t2)
end
julia> tform = PerspectiveMap() ∘ inv(AffineMap(RotX(0.3), SVector((0, 0, 0))));
julia> inv(tform)
(PerspectiveMap() ∘ AffineMap([1.0 0.0 0.0; 0.0 0.955336489125606 -0.29552020666133955; 0.0 0.29552020666133955 0.955336489125606], [-0.0, 0.0, -0.0]))
I didn't yet check whether this is equivalent to the Projective homography, though...
we might want a high-level API in ImageTransformations
This is highly application-oriented so I don't know what your target usage is. Perhaps one just need to properly document it with some small examples #141.
FYI, I'm reaching @c42f for the privilege to CoordinateTransformations
Agreed!
I didn't yet check whether this is equivalent to the Projective homography, though...
Hmm, the tform seems ℝ³→ℝ², so the following error occours:
julia> warp(img, tform)
ERROR: "Dimension mismatch: cannot rotate a vector of length 2"
...
I don't know what your target usage is
I mainly use homography for image registration. (Sorry for Japanese, but this might be a good exaple: https://zenn.dev/hyrodium/articles/5dc951f378b46bedb211)

we might want a high-level API in ImageTransformations so that normal users don't need to talk to warp directly.
I think we can create impinch method:
-
impinch(img, a1=>b1), this cause parallel translation. -
impinch(img, a1=>b1, a2=>b2), this cause similarity transformation. -
impinch(img, a1=>b1, a2=>b2, a3=>b3), this cause affine transformation. -
impinch(img, a1=>b1, a2=>b2, a3=>b3, a4=>b4), this cause projective transformation.
(I'm not sure "pinch" is an appropriate name for it.)