如何使用Python执行坐标仿射变换?第二部分。

15

我遇到了与这里描述的问题相同的情况:如何使用Python执行坐标仿射变换?

我尝试使用所描述的方法,但由于某些原因我收到了错误消息。 我对代码进行的更改是替换原始系统和次要系统点。我使用不同的原点创建了次要坐标点。在我研究这个主题的实际案例中,在测量坐标时会有一些误差。

primary_system1 = (40.0, 1160.0, 0.0)
primary_system2 = (40.0, 40.0, 0.0)
primary_system3 = (260.0, 40.0, 0.0)
primary_system4 = (260.0, 1160.0, 0.0)

secondary_system1 = (610.0, 560.0, 0.0) 
secondary_system2 = (610.0,-560.0, 0.0) 
secondary_system3 = (390.0, -560.0, 0.0)
secondary_system4 = (390.0, 560.0, 0.0)

执行时我收到的错误如下。

*Traceback (most recent call last):
  File "affine_try.py", line 57, in <module>
    secondary_system3, secondary_system4 )
  File "affine_try.py", line 22, in solve_affine
    A2 = y * x.I
  File "/usr/lib/python2.7/dist-packages/numpy/matrixlib/defmatrix.py", line 850, in getI
    return asmatrix(func(self))
  File "/usr/lib/python2.7/dist-packages/numpy/linalg/linalg.py", line 445, in inv
    return wrap(solve(a, identity(a.shape[0], dtype=a.dtype)))
  File "/usr/lib/python2.7/dist-packages/numpy/linalg/linalg.py", line 328, in solve
    raise LinAlgError, 'Singular matrix'
numpy.linalg.linalg.LinAlgError: Singular matrix*

可能出了什么问题?

1个回答

44

问题在于您的矩阵是奇异的,意味着它无法被反转。由于您试图对其取逆,所以这是一个问题。您链接到的线程是解决您问题的基本方法,但不是最佳解决方案。实际上,您想要做的不仅仅是反转矩阵,而是解决一个最小二乘问题,以找到可能带有噪声的数据的最佳仿射变换矩阵。以下是如何执行该操作:

import numpy as np

primary = np.array([[40., 1160., 0.],
                    [40., 40., 0.],
                    [260., 40., 0.],
                    [260., 1160., 0.]])

secondary = np.array([[610., 560., 0.],
                      [610., -560., 0.],
                      [390., -560., 0.],
                      [390., 560., 0.]])

# Pad the data with ones, so that our transformation can do translations too
n = primary.shape[0]
pad = lambda x: np.hstack([x, np.ones((x.shape[0], 1))])
unpad = lambda x: x[:,:-1]
X = pad(primary)
Y = pad(secondary)

# Solve the least squares problem X * A = Y
# to find our transformation matrix A
A, res, rank, s = np.linalg.lstsq(X, Y)

transform = lambda x: unpad(np.dot(pad(x), A))

print "Target:"
print secondary
print "Result:"
print transform(primary)
print "Max error:", np.abs(secondary - transform(primary)).max()

你的原始矩阵奇异的原因是第三个坐标始终为零,因此无法确定该坐标的转换方式(零乘以任何值都为零,因此任何值都可以使用)。

打印A的值可以告诉您最小二乘法找到的转换:

A[np.abs(A) < 1e-10] = 0  # set really small values to zero
print A

结果为

[[  -1.    0.    0.    0.]
 [   0.    1.    0.    0.]
 [   0.    0.    0.    0.]
 [ 650. -600.    0.    1.]]

这相当于 x2 = -x1 + 650, y2 = y1 - 600, z2 = 0,其中x1、y1、z1是原始系统中的坐标,x2、y2、z2是新系统中的坐标。可以看出,最小二乘法将所有与第三维相关的项设置为零,因为您的系统实际上是二维的。


这个很好用,我强烈推荐!顺便说一下,对于二维点,只需添加零作为第三个坐标,它仍然有效。 - Lordalcol

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