我正在尝试使用Kloss给出的解决方案找到一个给定两个点的2-D仿射变形,以及Kloss在"使用NumPy的N维线性向量场回归"中给出的。(2010, The Python Papers Source Codes 2).
文章源代码。
它们提供了一种查找连接两组点 y 和 x 的仿射变换的方法,其中变换由矩阵 A 和向量 b 表示(即矩阵方程 y = Ax+b)。
在二维中,您有 6 个未知数,4 个定义 2x2 A 矩阵,2 个定义 b。
但是,在示例脚本和描述它的论文中,它们具有未知数 t=n^2+n,其中 n 是点数,这意味着您需要六个点,对于 2D 情况,这实际上是 12 个已知值(即图像上每个点的 x 和 y 值)。
他们通过以下方式对此进行测试:
def solve(point_list):
"""
This function solves the linear equation system involved in the n
dimensional linear extrapolation of a vector field to an arbitrary point.
f(x) = x * A + b
with:
A - The "slope" of the affine function in an n x n matrix.
b - The "offset" value for the n dimensional zero vector.
The function takes a list of n+1 point-value tuples (x, f(x)) and returns
the matrix A and the vector b. In case anything goes wrong, the function
returns the tuple (None, None).
These can then be used to compute directly any value in the linear
vector field.
"""dimensions = len(point_list[0][0])
unknowns = dimensions ** 2 + dimensions
number_points = len(point_list[0])
# Bail out if we do not have enough data.
if number_points < unknowns:
print ’For a %d dimensional problem I need at least %d data points.’ % (dimensions, unknowns)
print ’Only %d data points were given.’ % number_points return None, None.
。
问题:
为什么他们说你需要 6 分才能获得 2D 仿射变换?
opencv getAffineTransform只需要3个数据点就可以在2D中找到一个点,这是直观的数字,因为3个点定义了一个平面。当我从 Kloss 和 Kloss 代码中取出上述条件测试时,它在 3D 中工作 2 点。
为什么他们说你需要 6 分才能获得 2D 仿射变换?
对于此类变换,使用引入第三个w
坐标的齐次坐标非常方便,即:
-
(x, y)
变得(x, y, w)
, - 两点相当于 iff
x'/w' = x/w
和y'/w'= y/w
。
因此,您通常可以使用 w = 1
.
使用此系统,您可以使用矩阵乘法表示 2D 转换(平移、旋转等):
[x'] [x]
[y'] = A . [y]
[1 ] [1]
仿射变换是平移、缩放和旋转变换的组合,可以表示为:
[1 0 tx] [Sx 0 0] [cos(a) -sin(a) 0] [a b c]
A = [0 1 ty] . [0 Sy 0] . [sin(a) cos(a) 0] = [d e f]
[0 0 1 ] [0 0 1] [0 0 1] [0 0 1]
所以你有 6 个参数(又名未知数),因此你需要 3 对点来求解系统,因为每对点会给你 2 个方程。
换句话说,您需要(至少)6 个点(= 3 对)来计算转换。
注意:你至少需要6分,如果你得到的比这更多,那么你的系统就被过度确定,这意味着你可以找到一个近似解,例如最小二乘,这是你文章的重点。
说到点子上,
为什么他们说你需要 6 分才能获得 2D 仿射变换?
我猜你指的是文章等式 (4) 之前的位,他们说你至少需要 m>=n^2+n
.在那里,m
是点对的数量,n
是维度的数量。
我认为他们没有太注意,他们的意思是m>=n+1
.
这意味着在 2D 中需要 n+1=3
个点,而在 3D
中,我们需要n+1=4
个点来完全定义仿射变换。请注意,只要点不共线,您就可以找到解决方案。
这与你发布的opencv链接一致,3x2=6
输入nuber(3个源点,每个源点有两个坐标)和类似的6
输出数字:
(x1,y1,x2,y2,x3,y3)
X[x1,y1],Y[x1,y1],X[x2,y2],Y[x2,y2],X[x3,y3],Y[x3,y3]
(但请注意,opencv 评估了确切的仿射变换,而本文没有)
话虽如此,你往往不在乎这个。
您可能需要一个点比m
少的仿射变换,并且您对众多解决方案之一感兴趣。
您更经常需要对变换进行估计并最小化误差,例如在最小二乘意义上,这就是本文的内容:快速且使用 numpy。
要检索 2D 仿射变换,您需要正好 3 个点,并且它们不应位于一条线上。对于 N 维空间,有一个简单的规则:要明确恢复仿射变换,您应该知道 N+1 个点的图像,这些图像形成 2D 的单纯形---三角形、3D 的金字塔等。关于为什么它应该是这样的一个很好的解释,你可以在"仿射映射单纯形的初学者指南"中找到。上级:该指南的作者最近发表了"关于仿射映射单纯形的工作簿",其中包含许多通过对一定数量的点的操作来检索仿射变换的示例,也许您可以在那里找到有用的东西。