3

I have a numpy array as the following:

my_array = np.float32([[[ 323. , 143.]], [[ 237. , 143.]], [[ 227. , 230.]], [[ 318. , 233.]]])

This 4 points represent the vertices of a rectangle that lies on a image, I need to reorder them clockwise and save it to a new np array, (top-left-> top-right -> bottom - right -> bottom - left). In my example it will be:

[237,  143] -> [323, 143] -> [318, 233] -> [227, 230]

I have read this but my skills on numpy aren't as good to implement it...

Thanks!

1

2 Answers 2

4

You could do something like this -

import numpy as np
from scipy.spatial import distance

def sortpts_clockwise(A):
    # Sort A based on Y(col-2) coordinates
    sortedAc2 = A[np.argsort(A[:,1]),:]

    # Get top two and bottom two points
    top2 = sortedAc2[0:2,:]
    bottom2 = sortedAc2[2:,:]

    # Sort top2 points to have the first row as the top-left one
    sortedtop2c1 = top2[np.argsort(top2[:,0]),:]
    top_left = sortedtop2c1[0,:]

    # Use top left point as pivot & calculate sq-euclidean dist against
    # bottom2 points & thus get bottom-right, bottom-left sequentially
    sqdists = distance.cdist(top_left[None], bottom2, 'sqeuclidean')
    rest2 = bottom2[np.argsort(np.max(sqdists,0))[::-1],:]

    # Concatenate all these points for the final output
    return np.concatenate((sortedtop2c1,rest2),axis =0)

Sample input, output -

In [85]: A
Out[85]: 
array([[ 281.,  147.],
       [ 213.,  170.],
       [ 239.,  242.],
       [ 307.,  219.]], dtype=float32)

In [86]: sortpts_clockwise(A)
Out[86]: 
array([[ 213.,  170.],
       [ 281.,  147.],
       [ 307.,  219.],
       [ 239.,  242.]], dtype=float32)
Sign up to request clarification or add additional context in comments.

3 Comments

Note to OP: If the input array is of shape 4 x 1 x 2, it could be squeezed to a shape of 4 x 2 at the start before proceeding with the rest of the code. So, A = np.squeeze(A) at the start could be used in such a case.
It works great but I need to change the tolerance for some matrices like A = np.float32([[281., 147.],[213. ,170.],[239. ,242.], [307. ,219.]]), so I made a variable tolerance, any advise how to pick this tolerance given the points?
@LuisEnrique Check out the edits please. Now, it uses eucl. dist., so must be more robust.
0

If you need such you show in your example

new_array = my_array[[1,0,3,2]]

Or exactly clockwise (and in general, not only for 4 points)

n = len(my_array)
order = [i for i in range(0, n-2)]
order.insert(0, n-1)
new_array = my_array[order]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.