仿射变换算法

24

有没有人知道基于已知两个坐标系中一组确定点的标准算法来确定仿射变换矩阵?


如果我还记得我的大学时代,你不应该可以通过建立一组方程并解决转换来完成这个问题吗?顺便问一下,这是你的家庭作业吗? - WhirlWind
这不更适合在http://mathoverflow.net上提问吗? - BalusC
1
@WhirlWind 不,这不是我的作业。我已经自己想出了一个解决方案,但它似乎有点“hacky”,而且似乎不能很好地处理一些情况。我一直在寻找标准算法,但到目前为止都没有成功。我想知道这里是否有人知道其中的一个。@BalusC 是吗?那我应该去那里问吗?抱歉 :) 我在这里还是有点新。 - Adam C.
2
@BalusC:不,这绝对不是一个适合在MathOverflow上提问的问题。请阅读他们的常见问题解答:http://mathoverflow.net/faq 它不是用于作业帮助,而是用于关于“研究级数学...文章或研究生级别书籍”的问题。 - Cascabel
1
@thehawk90:抱歉,我不是要暗示你的问题是家庭作业;我知道你已经说了不是。我只是想非常清楚地告诉BalusC mathoverflow适合什么类型的问题 - 任何可能是家庭作业的问题(除了数学研究生阶段之外)肯定不是他们想要的问题。不过感谢你的解释! - Cascabel
2个回答

37

仿射变换使用2x3矩阵来表示。我们通过将二维输入(x y)扩展为三维向量(x y 1),然后在左侧乘以M来执行仿射变换M。

因此,如果我们有三个点(x1 y1) (x2 y2) (x3 y3)映射到(u1 v1) (u2 v2) (u3 v3),则我们有

   [x1 x2 x3]   [u1 u2 u3]
M  [y1 y2 y3] = [v1 v2 v3].
   [ 1  1  1]

你可以通过右侧乘以的逆矩阵来得到M

[x1 x2 x3]
[y1 y2 y3]
[ 1  1  1].

将一个2x3矩阵右乘一个3x3矩阵,可以得到我们想要的2x3矩阵。(实际上不需要完全求逆,但如果有矩阵求逆可用,则很容易使用。)

很容易适应其他维度。如果您有超过3个点,您可能需要进行最小二乘拟合。但这需要再次询问,并且会更加困难。


翻译怎么样? - jeff
1
M的最后一列给出了翻译。您可以将M视为线性映射(由左侧的2x2矩阵给出),然后是最后一列的平移。但您不必将其视为两个单独的变换。要转换2D点,您需要附加1以使其成为3D点,然后乘以M。结果是一个应用了线性和平移部分的2D向量。 - sigfpe
如果(x1,y1)、(x2,y2)和(x3,y3)的测量值存在噪声,那么确保不会在M中引入偏斜/扭曲的最佳方法是什么? - BenB

1
我不确定这个公式有多标准,但是在 "初学者指南:简单形体的仿射映射" 和 "简单形体的仿射映射练习册" 中都有一个适用于你情况的好公式。 将其转化为代码应该像这样(对于糟糕的代码风格我很抱歉——我是数学家,不是程序员)。
import numpy as np
# input data
ins = [[1, 1, 2], [2, 3, 0], [3, 2, -2], [-2, 2, 3]]  # <- points
out = [[0, 2, 1], [1, 2, 2], [-2, -1, 6], [4, 1, -3]] # <- mapped to
# calculations
l = len(ins)
B = np.vstack([np.transpose(ins), np.ones(l)])
D = 1.0 / np.linalg.det(B)
entry = lambda r,d: np.linalg.det(np.delete(np.vstack([r, B]), (d+1), axis=0))
M = [[(-1)**i * D * entry(R, i) for i in range(l)] for R in np.transpose(out)]
A, t = np.hsplit(np.array(M), [l-1])
t = np.transpose(t)[0]
# output
print("Affine transformation matrix:\n", A)
print("Affine transformation translation vector:\n", t)
# unittests
print("TESTING:")
for p, P in zip(np.array(ins), np.array(out)):
  image_p = np.dot(A, p) + t
  result = "[OK]" if np.allclose(image_p, P) else "[ERROR]"
  print(p, " mapped to: ", image_p, " ; expected: ", P, result)

这段代码从给定的点中恢复仿射变换(将“ins”转换为“outs”),并测试其是否有效。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接