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...
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)
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.
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.
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.
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.
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]]
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]])
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With