简体   繁体   English

如何在 Python 中用 np.linalg.norm 替换 scipy.spatial.distance

[英]How to replace scipy.spatial.distance with np.linalg.norm in Python

I am following this tutorial to implement object tracking for my project - https://www.pyimagesearch.com/2018/07/23/simple-object-tracking-with-opencv/我正在按照本教程为我的项目实现对象跟踪 - https://www.pyimagesearch.com/2018/07/23/simple-object-tracking-with-opencv/

Method is to find centroids of detected objects in the initial frame, and then calculate the shortest distance to the other centroids of detected objects that show up on the next frame.方法是在初始帧中找到检测到的物体的质心,然后计算到下一帧出现的检测到的物体的其他质心的最短距离。 Assumption is that a centroid that is closest would be a same object.假设最接近的质心是同一个对象。

In the tutorial -在教程中——

from scipy.spatial import distance as dist
...
D = dist.cdist(np.array(objectCentroids), newCentroids)

is used to calculate the distance (Euclidean Distance).用于计算距离(欧几里得距离)。 Unfortunately, I cannot use scipy module as I am trying to deploy this to AWS Lambda (size limit).不幸的是,我无法使用 scipy 模块,因为我正在尝试将其部署到 AWS Lambda(大小限制)。 In this case, the recommendation is to use this - https://docs.scipy.org/doc/numpy/reference/generated/numpy.linalg.norm.html在这种情况下,建议使用它 - https://docs.scipy.org/doc/numpy/reference/generated/numpy.linalg.norm.html

D = np.linalg.norm(objectCentroids – newCentroids)

The issue with this is that, unlike dist.cdist , where it computes all and any matrix, np.linalg.norm only outputs 1 value, which is calculated after newCentroids is subtracted from objectCentroids matrix.问题在于,与dist.cdist计算所有矩阵和任何矩阵不同, np.linalg.norm仅输出 1 个值,该值是在从 objectCentroids 矩阵中减去 newCentroids 后计算的。 I am about to loop over n times (however big the matrix is) and append to another matrix to construct the result I need.我即将循环 n 次(无论矩阵有多大)并附加到另一个矩阵以构建我需要的结果。 However, I wasn't sure if my understanding of this concept is correct or not, so I wanted to seek out some help.但是,我不确定我对这个概念的理解是否正确,所以我想寻求一些帮助。 If anyone knows of a better way, I would appreciate any pointer.如果有人知道更好的方法,我将不胜感激。

UPDATE更新

Based on the feedback/answer I got, I updated the code a bit, and well... it seems to be working -根据我得到的反馈/答案,我稍微更新了代码,嗯……它似乎有效 -

n = arrayObjectCentroids.shape[0]
m = inputCentroids.shape[0]

T = []

for i in range(0,n):
    for z in range(0,m):
        Tv = np.linalg.norm(arrayObjectCentroids[i] - inputCentroids[z])
        # print(f'Tv is \n {Tv}')
        T = np.append(T, Tv)
        # print(f'T is \n {T}')
    print(f'new T is \n {T}')   
D = np.reshape(T, (n, m))
print(f'D is \n {D}')

In this case, if there is one object and moving a little -在这种情况下,如果有一个物体并且稍微移动 -

newCentroids is [[224 86]] , and the shape of it is (1, 2)... objectCentroids is [[224 86]] , and the shape objectCentroids is (1, 2) newCentroids 是[[224 86]] ,它的形状是 (1, 2)... objectCentroids 是[[224 86]] ,它的形状 objectCentroids 是 (1, 2)

D is [[0.]] D 是[[0.]]

If I have 3 objects, -如果我有 3 个对象,-

new Centroids is新质心是

 [[228  79]
 [ 45 127]
 [103 123]]

shape of inputCentroids is (3, 2) inputCentroids 的形状是 (3, 2)

objectCentroids is objectCentroids 是

 [[228  79]
 [ 45 127]
 [103 123]]

shape objectCentroids is (3, 2)形状 objectCentroids 是 (3, 2)

D is D 是

 [[  0.         189.19038031 132.51792332]
 [189.19038031   0.          58.13776741]
 [132.51792332  58.13776741   0.        ]]

Great that it works, but I feel like this may not be the best solution out there, and if you have any pointer, I would appreciate it!太好了,它有效,但我觉得这可能不是最好的解决方案,如果您有任何指示,我将不胜感激! Thanks!谢谢!

EDIT: Edited code to address comments below编辑:编辑代码以解决下面的评论

If in your case you have vectors in Euclidean space then np.linalg.norm will return the length of that vector.如果在您的情况下您在欧几里得空间中有向量,则np.linalg.norm将返回该向量的长度。

So objectCentroid – newCentroid will give you the vector between the point at objectCentroid and the point at newCentroid .所以objectCentroid – newCentroid会给你点之间的矢量objectCentroid并且该点处newCentroid Note that is between 2 points and not an array containing ALL points.请注意,在 2 个点之间,而不是包含所有点的数组。

To get all combinations of points I've used itertools & then reshaped the array to give the same output as dist为了获得点的所有组合,我使用了itertools然后重塑数组以提供与dist相同的输出

import numpy as np
from scipy.spatial import distance as dist
import itertools

# Example data
objectCentroids = np.array([[0,0,0],[1,1,1],[2,2,2], [3,3,3]])
newCentroids    = np.array([[4,4,4],[5,5,5],[6,6,6],[7,7,7]])
comb            = list(itertools.product(objectCentroids, newCentroids))
all_dist        = [] 

for pair in comb:

    dis = np.linalg.norm((pair[0] - pair[1]))
    all_dist.append(dis)

all_dist = np.reshape(all_dist, (len(objectCentroids), len(objectCentroids)))
D        = dist.cdist(objectCentroids, newCentroids)   

print(D)
print(" ")
print(all_dist)

You can use Numpy broadcasting to create a distance matrix.您可以使用 Numpy 广播来创建距离矩阵。

Read about it here and here . 在这里这里阅读它。

The basic idea is:基本思想是:

Stack (reshape) your centroids as (1, n, 3) and (n, 1, 3) where the last dimension with shape 3 is (x,y,z) .将质心堆叠(重塑)为(1, n, 3)(n, 1, 3) ,其中形状为 3 的最后一个维度是(x,y,z) Then subtract the arrays and use np.linalg.norm to calculate the distance along axis ... hm ... probably the last one.然后减去数组并使用np.linalg.norm计算沿轴的距离……嗯……可能是最后一个。 That should yield a square (n,n) distance matrix.这应该会产生一个平方(n,n)距离矩阵。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM