如何使用python执行坐标仿射变换?第2部分

时间:2013-12-12 14:28:58

标签: numpy 3d transformation affinetransform

我遇到的问题与此处描述的相同: how to perform coordinates affine transformation using python?

我试图使用所描述的方法,但有些原因我会收到错误消息。 我对代码所做的更改是替换主系统和辅助系统点。我通过使用不同的origo创建了辅助坐标点。在我正在研究的实际情况中,这个主题在测量坐标时会有一些错误。

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 个答案:

答案 0 :(得分:27)

问题是你的矩阵是单数的,这意味着它是不可逆的。既然你试图采取相反的方法,那就是一个问题。您链接的线程是您的问题的基本解决方案,但它不是真正的最佳解决方案。您实际想要做的是解决最小二乘最小化问题,而不仅仅是反转矩阵,以找到可能噪声数据的最佳仿射变换矩阵。以下是您将如何做到这一点:

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是新系统中的坐标。如您所见,最小二乘法只是将与第三维相关的所有术语设置为零,因为您的系统实际上是二维的。