Noam Naveh
Noam Naveh

Reputation: 143

find polygon top-left, top-right, bottom-right and bottom-left points

I have a set of x,y coordinates representing a contour as follows:

array([[[   0,    0]],
       [[   0,    3]],
       [[   1,    3]],
       [[   2,    4]],
       ...,
       [[1189,    5]],
       [[1188,    5]],
       [[1183,    0]]], dtype=int32)

How do I find the TYPOLOGICAL top-left,top-right,bottom-right and bottom-left extreme points?

clarification following a comment below: The points sought after are the 'obvious' extreme points / corners of a 4 edges Quadrilateral such as a square, rectangle, chevron or trapezoid. Note that the data is organic and that 2 points which may seem, visibly, on the same horizontal / vertical line may not be, e.g. (10,60),(9,58)

I have followed the following logic so far (example for top-left and top-right):

# slice k smallest y value elements
l = c[np.argsort(c.reshape(-1,2), axis=0)[:k][:,1]]

#ARBITRARAY - only examinie items whose y value is below 20
l = l[l[:,:,1]<20]

#sort by X value
l = sorted(l, key =lambda x:x[0])
    
minX = l[0][0]
maxX = l[len(l)-1][0]

However this rather imperfect and inelegant. Example image attached

smample image

Upvotes: 2

Views: 4152

Answers (1)

Lenormju
Lenormju

Reputation: 4378

EDIT: based on your precisions on this answer's comments, here is the updated version :

import numpy as np


def find_corners(polygon):
    #    topmost,leftmost ───────────►xxxxxxxxxx◄────────── topmost,rightmost
    #                              xxxx         xx
    #    leftmost,topmost ──────►xxx             xx
    #                            x                xx◄────── rightmost,topmost
    #                            x                 x
    # leftmost,bottommost ──────►xx                x
    #                             xx              xx◄────── rightmost,bottommost
    #                              x             xx
    # bottommost,leftmost ────────►xxxxxxxxxxxxxxx◄──────── bottommost,rightmost

    # topmost is minimum Y
    # leftmost is minimum X
    # rightmost is maximum X, or minimum -X
    # bottommost is maximum Y, or minimum -Y
    # X is `pt[0][0]`, Y is `pt[0][1]`

    # going clock-wise :
    topmost_then_rightmost_point =    min(polygon, key=lambda pt: ( pt[0][1], -pt[0][0]))[0]
    rightmost_then_topmost_point =    min(polygon, key=lambda pt: (-pt[0][0],  pt[0][1]))[0]
    rightmost_then_bottommost_point = min(polygon, key=lambda pt: (-pt[0][0], -pt[0][1]))[0]
    bottommost_then_rightmost_point = min(polygon, key=lambda pt: (-pt[0][1], -pt[0][0]))[0]
    bottommost_then_leftmost_point =  min(polygon, key=lambda pt: (-pt[0][1],  pt[0][0]))[0]
    leftmost_then_bottommost_point =  min(polygon, key=lambda pt: ( pt[0][0], -pt[0][1]))[0]
    leftmost_then_topmost_point =     min(polygon, key=lambda pt: ( pt[0][0],  pt[0][1]))[0]
    topmost_then_leftmost_point =     min(polygon, key=lambda pt: ( pt[0][1],  pt[0][0]))[0]

    top_left = topmost_then_leftmost_point
    top_right = topmost_then_rightmost_point
    bottom_right = bottommost_then_rightmost_point
    bottom_left = bottommost_then_leftmost_point

    return tuple(top_left), tuple(top_right), tuple(bottom_right), tuple(bottom_left)


# example from OP :
a = np.array([[[   0,    0]],
              [[   0,    3]],
              [[   1,    3]],
              [[   2,    4]],
              [[1189,    5]],
              [[1188,    5]],
              [[1183,    0]]], dtype=np.int32)
assert find_corners(a) == ((0, 0), (1183, 0), (1189, 5), (1188, 5))


# another example, based on the polygon drawn in the function's comments :
# v---------------------------------------------v
#                x        x
#             x x
#
#           x                xx
#           x
#            x
#             x               x
#                            x
#              x            x
# ^---------------------------------------------^
# using the coordinates you get when putting it in a text editor (starting at line=Y=1, column=X=1) you get clock-wise :
b = np.array(
    [
        [[27, 1]],
        [[30, 4]],
        [[31, 4]],
        [[31, 7]],
        [[30, 8]],
        [[29, 9]],
        [[16, 9]],
        [[15, 7]],
        [[14, 6]],
        [[13, 5]],
        [[13, 4]],
        [[15, 2]],
        [[17, 2]],
        [[18, 1]],
    ], dtype=np.int32)
assert find_corners(b) == ((18, 1), (27, 1), (29, 9), (16, 9))

Upvotes: 3

Related Questions