Search code examples
pythonarrayssortingnumpyopencv3.0

Sorting points from distance to a given point x,y here in my case (x=0,y=o)


I would like to sort (shortest to longest) an array 'a' (as given below) to the distance from the origin or a point (in my case 0,0) and store it to a similar array type 'b' or replacing the array 'a'

the below given points are 3d numpy array

[[[  510.    11.]]

 [[  651.   276.]]

 [[  269.    70.]]

 [[  920.    26.]]

 [[  513.    21.]]

 [[ 1197.   620.]]

 [[  407.   268.]]

 [[  452.    35.]]

 [[  435.     3.]]

 [[  520.    20.]]

 [[ 1151.   499.]]

 [[  104.    26.]]

 [[  754.    28.]]

 [[  263.   111.]]

 [[  731.    12.]]

 [[  972.   200.]]

 [[ 1186.   614.]]

 [[  437.     2.]]

 [[ 1096.    68.]]

 [[  997.   201.]]

 [[ 1087.   200.]]

 [[  913.   201.]]

 [[ 1156.   510.]]

 [[  994.   230.]]

 [[  793.    29.]]

 [[  514.    19.]]]

I cannot find any helpful information regarding these kind of 3d np arrays sorting

ps: These points 'a' were obtained from Goodfeaturestotrack ,OPEN CV ,python 3.6

and how do you clear an array to Null type ?

 #this is  clustering algorithm    
    for index in range(len(a): #a is the above matrix 3d np array
#find distance was already defined and is euclidean distance formula
            if findDistance(a[index][0], a[index][1], a[index + 1][0], a[index + 1][1]) < 3: #calculation euclidean distance between ai and ai+1
                c.append(index)
            if findDistance(a[index][0], a[index][1], a[index + 1][0], a[index + 1][1]) > 3: #calculation euclidean distance between ai and ai+1
                if len(c) > 10:
                    cp = np.insert(cp, c, 0)

                    c = [] # should clear c **is this correct ??**

Solution

  • I like to keep this handy to calculate distances in several array formats... it isn't a one-liner, but it works. Details on its implementations can be found elsewhere on stack by searching for 'einsum' and numpy as keywords. Import numpy as np required, this is just the def and you need 2 arrays

    import numpy as np
    
    def e_dist(a, b, metric='euclidean'):
    
    """Distance calculation for 1D, 2D and 3D points using einsum
    : a, b   - list, tuple, array in 1,2 or 3D form
    : metric - euclidean ('e','eu'...), sqeuclidean ('s','sq'...),
    :-----------------------------------------------------------------------
    """
    a = np.asarray(a)
    b = np.atleast_2d(b)
    a_dim = a.ndim
    b_dim = b.ndim
    if a_dim == 1:
        a = a.reshape(1, 1, a.shape[0])
    if a_dim >= 2:
        a = a.reshape(np.prod(a.shape[:-1]), 1, a.shape[-1])
    if b_dim > 2:
        b = b.reshape(np.prod(b.shape[:-1]), b.shape[-1])
    diff = a - b
    dist_arr = np.einsum('ijk,ijk->ij', diff, diff)
    if metric[:1] == 'e':
        dist_arr = np.sqrt(dist_arr)
    dist_arr = np.squeeze(dist_arr)
    return dist_arr
    

    Then you can sort the result if needed, for example

    a = np.random.randint(0, 10, size=(10,2))
    
    orig = np.array([0,0])
    
        e_dist(a, orig)
    
        array([  4.12,   9.9 ,   7.07,   6.08,   3.16,  10.63,   8.54,   7.28,   7.21,
                 6.08])
        np.sort(e_dist(a, orig))
    
        array([  3.16,   4.12,   6.08,   6.08,   7.07,   7.21,   7.28,   8.54,   9.9 ,
                10.63])
    

    ADDENDUM

    I should have added that you can get the sorted values using argsort as exemplified below

    np.argsort(e_dist(a, orig))
    array([4, 0, 3, 9, 2, 8, 7, 6, 1, 5], dtype=int64)
    
    idx = np.argsort(art.e_dist(a, orig))
    
    closest = a[idx]
    array([[3, 1],
           [1, 4],
           [1, 6],
           [6, 1],
           [5, 5],
           [4, 6],
           [2, 7],
           [8, 3],
           [7, 7],
           [7, 8]])