特别声明:本文采用 GNU Affero General Public License v3.0 许可协议。
问题
关于什么是照片测星定位,什么是天顶,我懒得写了 这里就不赘述了。我们直接来看这个问题的数学和工程形式:
现有平面上多条直线相交于同一点,已知每条直线上两点坐标(但是有误差),如何求出这个交点?
归一化矩阵伪逆 (matrix_inverse_normalized)
简介
这一算法是我在 WANG Lei 的矩阵伪逆 (matrix_inverse) 的基础上改良而来,添加了直线方程系数归一化的步骤,使本就名列前茅的精度更加遥遥领先!以下是一众算法的测试成绩:
无畸变
有畸变
数据来源:灭点计算误差测试框架
直线方程
记一条直线上已知的两点坐标为 (x1,y1) 和 (x2,y2),那么不难写出该直线的两点式方程:
y1−y2y−y2=x1−x2x−x2
为了后面把它放到矩阵里面算,需要给它化成 ax+by=c 的形式:
(y2−y1)x+(x1−x2)y=x1y2−x2y1
直线方程系数归一化
对上面得到的每个直线方程 ax+by=c,我们对它的系数进行归一化,得到:
a+b+cax+a+b+cby=a+b+cc
归一化的目的是让每条直线对最终结果的影响的权重都是相同的,而不是方程系数越大的直线影响越大。
矩阵伪逆
记一共有 n 条直线,其中第 i 条直线的归一化后的方程为 aix+biy=ci,则有超定方程组:
⎩⎨⎧a1x+b1y=c1a2x+b2y=c2⋮anx+bny=cn
写成矩阵形式就是:
a1a2⋮anb1b2⋮bn[xy]=c1c2⋮cn
我们把它记为:
Ax=c
对于这个超定方程组,我们通过构造正规方程求得最小二乘解:
ATAx=ATc
x=(ATA)−1ATc
这个 x,就是我们想要的天顶(交点)坐标。
该算法推广到更高维也是一样可行的。
代码实现
https://github.com/BengbuGuards/StarLocator/blob/main/prototype/core/positioning/top_point/methods/matrix_inverse_normalized.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| import numpy as np
def intersection(lines: np.ndarray) -> np.ndarray: """ 在 matrix_inverse 基础上改良:对直线方程的系数进行归一化 Find the intersection point of given lines. params: lines: numpy array, each row contains two points. [((x1, y1), (x2, y2)), ...] return: intersection point (x, y) """ V = lines[:, 1] - lines[:, 0]
A = np.zeros_like(V) A[:, 0] = V[:, 1] A[:, 1] = -V[:, 0]
lines_3d = np.dstack((lines, np.zeros((lines.shape[0], 2, 1)))) C = np.cross(lines_3d[:, 0], lines_3d[:, 1])[:, 2]
for i in range(len(A)): a, b = A[i] c = C[i] m = a + b + c A[i] /= m C[i] /= m
A_inv = np.linalg.pinv(A)
point = A_inv @ C
return point
|