Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Numpy: Get rectangle area just the size of mask

I have an image and a mask. Both are numpy array. I get the mask through GraphSegmentation (cv2.ximgproc.segmentation), so the area isn't rectangle, but not divided. I'd like to get a rectangle just the size of masked area, but I don't know the efficient way.

In other words, unmasked pixels are value of 0 and masked pixels are value over 0, so I want to get a rectangle where...

  • top = the smallest index of axis 0 whose value > 0
  • bottom = the largest index of axis 0 whose value > 0
  • left = the smallest index axis 1 whose value > 0
  • right = the largest index axis 1 whose value > 0
  • image = src[top : bottom, left : right]

My code is below

segmentation = cv2.ximgproc.segmentation.createGraphSegmentation()
src = cv2.imread('image_file')
segment = segmentation.processImage(src)
for i in range(np.max(segment)):
    dst = np.array(src)
    dst[segment != i] = 0
    cv2.imwrite('output_file', dst)
like image 338
ScenesK Avatar asked Aug 29 '16 13:08

ScenesK


People also ask

What does size attribute do in NumPy?

size: This attribute calculates the total number of elements present in the NumPy array. dtype: This attribute helps to check what type of elements are stored in the NumPy array. itemsize: This attribute helps to find the length of each element of NumPy array in bytes.

Which property is used to find the size tuple of a NumPy array?

In NumPy we will use an attribute called shape which returns a tuple, the elements of the tuple give the lengths of the corresponding array dimensions.

What NumPy attributes refers to the size of each dimensions?

Size of the first dimension of the NumPy array: len() len() is the Python built-in function that returns the number of elements in a list or the number of characters in a string. For numpy. ndarray , len() returns the size of the first dimension.

How do you check dimensions on Python?

Use ndim attribute available with the NumPy array as numpy_array_name. ndim to get the number of dimensions. Alternatively, we can use the shape attribute to get the size of each dimension and then use len() function for the number of dimensions.


2 Answers

If you prefer pure Numpy, you can achieve this using np.where and np.meshgrid:

i, j = np.where(mask)
indices = np.meshgrid(np.arange(min(i), max(i) + 1),
                      np.arange(min(j), max(j) + 1),
                      indexing='ij')
sub_image = image[indices]

np.where returns a tuple of arrays specifying, pairwise, the indices in each axis for each non-zero element of mask. We then create arrays of all the row and column indices we will want using np.arange, and use np.meshgrid to generate two grid-shaped arrays that index the part of the image we're interested in. Note that we specify matrix-style indexing using index='ij' to avoid having to transpose the result (the default is Cartesian-style indexing).

Essentially, meshgrid constructs indices so that:

image[indices][a, b] == image[indices[0][a, b], indices[1][a, b]]

Example

Start with the following:

>>> image = np.arange(12).reshape((4, 3))
>>> image
array([[ 0,  1,  2],
       [ 3,  4,  5],
       [ 6,  7,  8],
       [ 9, 10, 11]])

Let's say we want to extract the [[3,4],[6,7]] sub-matrix, which is the bounding rectangle for the the following mask:

>>> mask = np.array([[0,0,0],[0,1,0],[1,0,0],[0,0,0]])
>>> mask
array([[0, 0, 0],
       [0, 1, 0],
       [1, 0, 0],
       [0, 0, 0]])

Then, applying the above method:

>>> i, j = np.where(mask)
>>> indices = np.meshgrid(np.arange(min(i), max(i) + 1), np.arange(min(j), max(j) + 1), indexing='ij')
>>> image[indices]
array([[3, 4],
       [6, 7]])

Here, indices[0] is a matrix of row indices, while indices[1] is the corresponding matrix of column indices:

>>> indices[0]
array([[1, 1],
       [2, 2]])
>>> indices[1]
array([[0, 1],
       [0, 1]])
like image 167
Will Vousden Avatar answered Sep 18 '22 18:09

Will Vousden


I think using np.amax and np.amin and cropping the image is much faster.

i, j = np.where(mask)
indices = np.meshgrid(np.arange(min(i), max(i) + 1),
              np.arange(min(j), max(j) + 1),
              indexing='ij')
sub_image = image[indices]

Time taken: 50 msec

where = np.array(np.where(mask))

x1, y1 = np.amin(where, axis=1)
x2, y2 = np.amax(where, axis=1)
sub_image = image[x1:x2, y1:y2]

Time taken: 5.6 msec

like image 20
Hans K Avatar answered Sep 20 '22 18:09

Hans K