6

I'm struggling with a simple question. I have a numpy array of the form:

[[[ 1152.07507324   430.84799194]
  [ 4107.82910156   413.95199585]
  [ 4127.64941406  2872.32006836]
  [ 1191.71643066  2906.11206055]]]

And I want to calculate the bounding box, meaning, I want to have the leftmost, topmost, rightmost and bottommost point.

This should be a correct solution

[[[ 1152.07507324   413.95199585]
  [ 4127.64941406   413.95199585]
  [ 4127.64941406  2906.11206055]
  [ 1152.07507324  2906.11206055]]]

I developed a nasty function that does the trick, but I'm very unsatisfied with it since its not really pythonic/numpyic

def bounding_box(iterable):
    minimum_x = min(iterable[0], key=lambda x:x[0])[0]
    maximum_x = max(iterable[0], key=lambda x:x[0])[0]
    minimum_y = min(iterable[0], key=lambda x:x[1])[1]
    maximum_y = max(iterable[0], key=lambda x:x[1])[1]

    return numpy.array([[(minimum_x, minimum_y), (maximum_x, minimum_y), (maximum_x, maximum_y), (minimum_x, maximum_y)]], dtype=numpy.float32)

Do you have any idea how to optimize the function above, perhaps using numpy builtins?

1
  • 1
    Why does your sample array have three levels of square brackets? That makes it looks like a 3D array with shape (1,n,2). Is that intentional? Commented Sep 17, 2012 at 2:08

2 Answers 2

11

Use the numpy.min and numpy.max builtins:

def bounding_box(iterable):
    min_x, min_y = numpy.min(iterable[0], axis=0)
    max_x, max_y = numpy.max(iterable[0], axis=0)
    return numpy.array([(min_x, min_y), (max_x, min_y), (max_x, max_y), (min_x, max_y)])
Sign up to request clarification or add additional context in comments.

5 Comments

Argv. I was working on a shorter trick to get the Cartesian product of the results, but it's the same basic idea.
itertools.product? Only problem is that it gives the answer in the wrong order.
But if you can get around that and still have short code, by all means, post it. I am curious :)
I was thinking of something like c = np.array([b.min(0), b.max(0)]); list(np.broadcast(*np.ix_(*c.T))) -- but that second part is too clever, and the order's wrong anyway. I'd much rather do it manually like you and the OP did so that it's instantly obvious what the result is.
Save yourself a tiny bit of hassle and (1) transform iterable into a 2D array iterable=iterable.squeeze(), (2) use the .min/.max methods instead of the np.min/np.max functions. Otherwise, +1
3

returns the same as previous answer but shorter and cleaner

returns 2*2 ndarray

def bbox(points):
    """
    [xmin xmax]
    [ymin ymax]
    """
    a = zeros((2,2))
    a[:,0] = np.min(points, axis=0)
    a[:,1] = np.max(points, axis=0)
    return a

1 Comment

Consider adding some text to your answer, to explain what you're doing here and how this is different from the already accepted answer. Answers that are just code blobs aren't very useful.

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.