Reputation: 13
I am following this tutorial to implement object tracking for my project - 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). In this case, the recommendation is to use this - 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. I am about to loop over n times (however big the matrix is) and append to another matrix to construct the result I need. 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)
D is[[0.]]
If I have 3 objects, -
new Centroids is
[[228 79]
[ 45 127]
[103 123]]
shape of inputCentroids is (3, 2)
objectCentroids is
[[228 79]
[ 45 127]
[103 123]]
shape objectCentroids is (3, 2)
D is
[[ 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!
Upvotes: 1
Views: 444
Reputation: 3657
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.
So objectCentroid – newCentroid
will give you the vector between the point at objectCentroid
and the point at newCentroid
. Note that is between 2 points and not an array containing ALL points.
To get all combinations of points I've used itertools
& then reshaped the array to give the same output as 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)
Upvotes: 1
Reputation: 7121
You can use Numpy broadcasting to create a distance matrix.
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)
. Then subtract the arrays and use np.linalg.norm
to calculate the distance along axis ... hm ... probably the last one. That should yield a square (n,n)
distance matrix.
Upvotes: 0