找到给定距离矩阵的中心点

时间:2017-10-19 17:46:06

标签: matrix computer-vision distance mathematical-optimization numerical-methods

我有一个矩阵(实际上是一个加载的图像),其中每个元素都是距离某个未知中心点的L2距离。

这是一个简单的例子

A = [1.4142  1.0000  1.4142  2.2361]
    [1.0000  0.0000  1.0000  2.0000]
    [1.4142  1.0000  1.4142  2.2361]

在这种情况下,中心显然位于坐标(1,1)(0索引矩阵或2D数组中的索引A [1,1])。

然而,在我的中心不被限制为整数指数的情况下,它不再那么明显。例如,给定此矩阵B,我的中心坐标在哪里?

B = [3.0292  1.9612  2.8932  5.8252]
    [1.2292  0.1612  1.0932  4.0252]
    [1.4292  0.3612  1.2932  4.2252]

在这种情况下,您如何找到答案是在行1.034和第1.4列?

我知道trilateration解决方案(有provided MATLAB code to visualize that in 3D previously),但是有更有效的方法(例如没有矩阵倒置的方法)吗?

这个问题与语言无关,因为我正在寻找更多的算法帮助。如果您在解决方案中坚持使用MATLAB,Python或C ++,那就太棒了; - )。

2 个答案:

答案 0 :(得分:1)

虽然没有类似任务的经验,但我读了一些东西并尝试了一些东西。

当不熟悉这个主题时,很难理解它,我发现的所有资源都有点混乱。

关于我的理论还不清楚:

  • 是如上所述的问题,凸优化问题(local-minimum = global-minimum;意味着可以访问强大的求解器!)
    • 有更多关于更常见问题的资源(传感器网络 本地化),它是非凸的,并且已经开发出极其复杂的方法
  • 是您的三边法 - 能够利用> 3分(trilateration与multilateration;至少这段代码看起来不像它可能意味着:噪音表现不好!)

这里有一些示例代码,有两种方法:

  • A:凸优化:SOCP-Relaxation
  • B:非线性编程优化
    • 使用scipy.optimize
    • 实施
    • 我的合成实验非常完美;嘈杂的情况下效果更佳;尽管我们正在使用数值微分(自动差异难以在这里使用)

其他一些评论:

  • 你的例子B肯定有一些(非常糟糕的)噪音或其他一些问题在我看来,因为我的方法是完全关闭的;特别是方法B为我的合成数据(至少那是我的印象)闪耀着

<强>代码:

import numpy as np
import cvxpy as cvx
from scipy.spatial.distance import cdist
from scipy.optimize import minimize
np.random.seed(1)

""" Create noise-free (not anymore!) fake-problem """
real_x = np.random.random(size=2) * 3

M, N = 5, 10
NOISE_DISTS = 0.1
pos = np.array([(i,j) for i in range(M) for j in range(N)])  # ugly -> tile/repeat/stack
real_x_stacked = np.vstack([real_x for i in range(pos.shape[0])])
Y = cdist(pos, real_x[np.newaxis])
Y += np.random.normal(size=Y.shape)*NOISE_DISTS  # Let's add some noise!
print('-----')
print('PROBLEM')
print('-------')
print('real x: ', real_x)
print('dist mat: ', np.round(Y,3).T)

""" Helper """
def cost(x, Y, pos):
    res = np.linalg.norm(pos - x, ord=2, axis=1) - Y.ravel()
    return np.linalg.norm(res, 2)

print('cost with real_x (check vs. noisy): ', cost(real_x, Y, pos))

""" SOLVER SOCP """
def solve_socp_relax(pos, Y):
    x = cvx.Variable(2)
    y = cvx.Variable(pos.shape[0])
    fake_stack = [x for i in range(pos.shape[0])]                     # hacky

    objective = cvx.sum_entries(cvx.norm(y - Y))
    x_stacked = cvx.reshape(cvx.vstack(*fake_stack), pos.shape[0], 2) # hacky
    constraints = [cvx.norm(pos - x_stacked, 2, axis=1) <= y]

    problem = cvx.Problem(cvx.Minimize(objective), constraints)
    problem.solve(solver=cvx.ECOS, verbose=False)
    return x.value.T

""" SOLVER NLP """
def solve_nlp(pos, Y):
    sol = minimize(cost, np.zeros(pos.shape[1]), args=(Y, pos), method='BFGS')
    # print(sol)
    return sol.x

""" TEST """
print('-----')
print('SOLVE')
print('-----')

socp_relax_sol = solve_socp_relax(pos, Y)
print('SOCP RELAX SOL: ', socp_relax_sol)

nlp_sol = solve_nlp(pos, Y)
print('NLP SOL: ', nlp_sol)

<强>输出:

-----
PROBLEM
-------
real x:  [ 1.25106601  2.16097348]
dist mat:  [[ 2.444  1.599  1.348  1.276  2.399  3.026  4.07   4.973  6.118  6.746
   2.143  1.149  0.412  0.766  1.839  2.762  3.851  4.904  5.734  6.958
   2.377  1.432  0.856  1.056  1.973  2.843  3.885  4.95   5.818  6.84
   2.711  2.015  1.689  1.939  2.426  3.358  4.385  5.22   6.076  6.97
   3.422  3.153  2.759  2.81   3.326  4.162  4.734  5.627  6.484  7.336]]
cost with real_x (check vs. noisy):  0.665125233772
-----
SOLVE
-----
SOCP RELAX SOL:  [[ 1.95749275  2.00607253]]
NLP SOL:  [ 1.23560791  2.16756168]

编辑:使用非线性最小二乘法代替更一般的NLP方法,可以实现进一步的加速(特别是大规模)!我的结果仍然相同(如果问题是凸的,可以预期)。 NLP / NLS之间的时间可能看起来像9对0.5秒!

这是我推荐的方法!

def solve_nls(pos, Y):
    def res(x, Y, pos):
        return np.linalg.norm(pos - x, ord=2, axis=1) - Y.ravel()
    sol = least_squares(res, np.zeros(pos.shape[1]), args=(Y, pos), method='lm')
    # print(sol)
    return sol.x

特别是第二种方法(NLP)也将运行更大的实例(cvxpy的开销伤害;这不是SOCP解算器的缺点,它应该扩展得更好!)。

此处M, N = 500, 1000的一些输出带有更多噪音:

-----
PROBLEM
------- 
real x:  [ 12.51066014  21.6097348 ]
dist mat:  [[   24.706    23.573    23.693 ...,  1090.29   1091.216  
1090.817]]
cost with real_x (check vs. noisy):  353.354267797
-----
SOLVE
-----
NLP SOL:  [ 12.51082419  21.60911561]
used:  5.9552763315495625  # SECONDS

所以在我的实验中它起作用,但我不会给出任何全局收敛保证或重建保证(仍然缺少一些理论)。

起初我虽然使用轻松SOCP问题的全局最优作为NLP求解器的初始点,但我没有找到任何需要它的例子!

一些有趣的视觉效果使用:

M, N = 20, 30
NOISE_DISTS = 0.2
...

import matplotlib.pyplot as plt
plt.imshow(Y.reshape(M, N), cmap='viridis', interpolation='none')
plt.colorbar()
plt.scatter(nlp_sol[1], nlp_sol[0], color='red', s=20)
plt.xlim((0, N))
plt.ylim((0, M))
plt.show()

enter image description here

还有一些超级嘈杂的表壳(表现不错!):

M, N = 50, 100
NOISE_DISTS = 5

-----
PROBLEM
-------
real x:  [ 12.51066014  21.6097348 ]
dist mat:  [[ 22.329  18.745  27.588 ...,  94.967  80.034  91.206]]
cost with real_x (check vs. noisy):  354.527196716
-----
SOLVE
-----
NLP SOL:  [ 12.44158986  21.50164637]
used:  0.01050068340320306

enter image description here

答案 1 :(得分:0)

如果我理解正确,你有一个矩阵A,其中A [i,j]保持从(i,j)到某个未知点(y,x)的距离。你可以这样找到(y,x):

对A的每个元素进行平方,使矩阵B说出来。 然后我们想找到(y,x)所以

(y-i)*(y-i) + (x-j)*(x-j) = B[i,j]

从0,0等式中减去每个等式并重新排列:

2*i*y + 2*j*x = B[0,0] + i*i + j*j - B[i,j]

这可以通过线性最小二乘法来解决。请注意,由于存在2个未知数,因此涉及的matix反转(更好,因子分解)将位于2x2矩阵上,因此不会耗费时间。实际上,只要给出A的维数,就可以解析出所需的矩阵及其逆矩阵。