Skip to content

Commit

Permalink
Construct affine transforms from point-pairs
Browse files Browse the repository at this point in the history
Given a set of point pairs `from => to`, compute the affine
transformation that best reproduces the observed mapping.

Closes #30
  • Loading branch information
timholy committed Apr 29, 2023
1 parent 78f5a5c commit 232acc6
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 0 deletions.
19 changes: 19 additions & 0 deletions src/affine.jl
Original file line number Diff line number Diff line change
Expand Up @@ -209,3 +209,22 @@ recenter(trans::AbstractMatrix, origin::Union{AbstractVector, Tuple}) = recenter

transform_deriv(trans::AffineMap, x) = trans.linear
# TODO transform_deriv_params

"""
AffineMap([from1=>to1, from2=>to2, ...]) → trans
Create an Affine transformation that approximately maps the `from` points to the `to` points.
At least `n+1` non-degenerate points are required to map an `n`-dimensional space.
If there are more points than this, the transformation will be over-determined and a least-squares
solution will be computed.
"""
function AffineMap(mappedpairs::AbstractVector{<:Pair})
froms = reduce(hcat, [vcat(pr.first, 1) for pr in mappedpairs])
tos = reduce(hcat, [pr.second for pr in mappedpairs])
AffineMap_(froms, tos)
end

function AffineMap_(froms, tos)
M = tos * pinv(froms)
AffineMap(M[:, 1:end-1], M[:, end])
end
10 changes: 10 additions & 0 deletions test/affine.jl
Original file line number Diff line number Diff line change
Expand Up @@ -127,4 +127,14 @@ end
@test expected.origin result.origin
@test expected.direction result.direction
end

@testset "construction from points" begin
M = [1.0 2.0; 3.0 4.0]
v = [-1.0, 1.0]
A = AffineMap(M,v)
froms = [[0.0, 0.0], [1.0, 0.0], [0.0, 1.0], [1.0, 1.0]]
mappedpoints = [from => A(from) for from in froms]
A2 = AffineMap(mappedpoints)
@test A2 A
end
end

0 comments on commit 232acc6

Please sign in to comment.