How to extend mask region (True) by 1 or 2 pixels? - python

I have a numpy mask of True and False values, detecting black regions in an image.
I want to extend the True regions by 1 or 2 pixel.
For example, considering this mask:
[[False False False False False]
[False False TRUE False False]
[False TRUE TRUE TRUE False]
[False False TRUE False False]
[False False False False False]
I want to have:
[[False False TRUE False False]
[False TRUE TRUE TRUE False]
[TRUE TRUE TRUE TRUE TRUE ]
[False TRUE TRUE TRUE False]
[False False TRUE False False]
Actually I could have made a for loop, but in a big image it's to slow.
Any ideas ?
Thanks !

Dilation is the easiest way to extend the "True" regions.
Consider the array:
a = np.array([[False, False, False, False, False],
[False, False, True, False, False],
[False, True, True, True, False],
[False, False, True, False, False],
[False, False, False, False, False]])
Convert to integer data type
a = a.astype(np.uint8)
You get:
array([[0, 0, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 1, 1, 1, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 0]], dtype=uint8)
Perform dilation using ellipse kernel of size 3x3:
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
dilate = cv2.dilate(a, kernel, iterations=1)
dilate:
array([[0, 0, 1, 0, 0],
[0, 1, 1, 1, 0],
[1, 1, 1, 1, 1],
[0, 1, 1, 1, 0],
[0, 0, 1, 0, 0]], dtype=uint8)
Convert the result to boolean data type:
d = np.array(dilate, dtype=bool)
Resulting array:
array([[False, False, True, False, False],
[False, True, True, True, False],
[ True, True, True, True, True],
[False, True, True, True, False],
[False, False, True, False, False]])
To extend the True regions further:
increase the kernel size
repeat dilation operation using iteration
Note: Boolean array cannot be used as input with cv2.dilate(), or else it throws error: (-5:Bad argument). Hence we convert it to int data type, perform the opertion and convert it back to bool data type.
It seems

You can use the boolean sum:
new_mask = mask.copy()
new_mask[:,1:] = mask[:,1:]+mask[:,:-1]
new_mask[1:,:] = new_mask[1:,:]+mask[:-1,:]
new_mask now is:
array([[False, False, False, False, False],
[False, False, True, False, False],
[False, True, True, True, True],
[False, True, True, True, False],
[False, False, True, False, False]])
the sum between two boolean works as a logical or, so in the previous lines of code you are saying: new_mask[i,j] = (mask[i,j] or mask[i,j-1] or mask[i-1,j])

Related

How can I use numpy array elements as indices to assign values for another numpy array

I have following problem, which I want to solve using numpy array elements.
The problem is:
Matrix = np.zeros((4*4), dtype = bool) which gives this 2D matrix.
Matrix = [[False, False, False, False],
[False, False, False, False],
[False, False, False, False],
[False, False, False, False]]
Les us suppose that we have an another array a = np.array([0,1], [2,1], [3,3])
a = [[0, 1],
[2, 1],
[3, 3]]
My question is: How to use the elements of the a array as indices to fill my matrix with True's. The output should seem like this
Matrix = [[False, True, False, False], # [0, 1]
[False, False, False, False],
[False, True, False, False], # [2, 1]
[False, False, False, True]] # [3, 3]
import numpy as np
Matrix = np.zeros((4*4), dtype = bool).reshape(4,4)
a = [[0, 1],
[2, 1],
[3, 3]]
Unroll them into a proper pair of indexing arrays for a 2d array
a = ([x[0] for x in a], [x[1] for x in a])
Matrix[a] = True
>>> Matrix
array([[False, True, False, False],
[False, False, False, False],
[False, True, False, False],
[False, False, False, True]])
Simple way to make the (4,4) bool array:
In [390]: arr = np.zeros((4,4), dtype = bool)
In [391]: arr
Out[391]:
array([[False, False, False, False],
[False, False, False, False],
[False, False, False, False],
[False, False, False, False]])
Proper syntax for making a:
In [392]: a = np.array([[0,1], [2,1], [3,3]])
In [393]: a
Out[393]:
array([[0, 1],
[2, 1],
[3, 3]])
Use the 2 columns of a as indices for the 2 dimensions of arr:
In [394]: arr[a[:,0],a[:,1]]=True
In [395]: arr
Out[395]:
array([[False, True, False, False],
[False, False, False, False],
[False, True, False, False],
[False, False, False, True]])

Pythonically compare indices of two arrays with permuted rows in numpy [duplicate]

This question already has an answer here:
How can I efficiently map each pixel of a three channel image to one channel?
(1 answer)
Closed 4 years ago.
I have two identically-sized numpy ndarrays with permuted rows:
import numpy as np
a = np.ndarray([[1,2,3],
[4,5,6],
[7,8,9],
[10,11,12]])
b = np.ndarray([[7,8,9],
[10,11,12],
[1,2,3],
[4,5,6]])
I want a function that returns the indices of each row in first array, relative to the second array. For example:
compare_row_indices(a,b)
would return
[2,3,0,1] # 0-based indexing
What is the most pythonic way to implement this function?
Maybe not the best possible way, but this seems to work (breaking it down to multiple steps for easier visualization):
>>> cmp = a[:, None] == b
>>> cmp
array([[[False, False, False],
[False, False, False],
[ True, True, True],
[False, False, False]],
[[False, False, False],
[False, False, False],
[False, False, False],
[ True, True, True]],
[[ True, True, True],
[False, False, False],
[False, False, False],
[False, False, False]],
[[False, False, False],
[ True, True, True],
[False, False, False],
[False, False, False]]])
>>> eq = np.all(cmp, axis=-1)
>>> eq
array([[False, False, True, False],
[False, False, False, True],
[ True, False, False, False],
[False, True, False, False]])
>>> np.argwhere(eq)
array([[0, 2],
[1, 3],
[2, 0],
[3, 1]])
>>> np.argwhere(eq)[:, 1]
array([2, 3, 0, 1])

Vectorized approach for masking individual slices per column

I have a numpy array:
>>> a = np.arange(20).reshape(5, -1)
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15],
[16, 17, 18, 19]])
I have an array of regions going in order of columns, that I would like to create a boolean mask for:
idx = np.array([[0,2], [1,3], [2,4], [1,4]])
My desired mask for this set of indices is:
array([[ True, False, False, False],
[ True, True, False, True],
[False, True, True, True],
[False, False, True, True],
[False, False, False, False]])
So column 0 has 0:2 masked, column 1 has 1:3 masked, etc. My current approach works, but I am looking for something vectorized:
def foo(a, idx):
out = np.zeros(a, dtype=np.bool8)
for (i, j), k in zip(idx, np.arange(a[1])):
out[i:j, k] = True
return out
In action:
foo(a.shape, idx)
array([[ True, False, False, False],
[ True, True, False, True],
[False, True, True, True],
[False, False, True, True],
[False, False, False, False]])
Using broadcasting -
In [434]: r = np.arange(a.shape[0])[:,None]
In [435]: (idx[:,0] <= r) & (idx[:,1] > r)
Out[435]:
array([[ True, False, False, False],
[ True, True, False, True],
[False, True, True, True],
[False, False, True, True],
[False, False, False, False]])

Built-in function in numpy to interpret an integer to an array of boolean values in a bitwise manner?

I'm wondering if there is a simple, built-in function in Python / Numpy for converting an integer datatype to an array/list of booleans, corresponding to a bitwise interpretation of the number please?
e.g:
x = 5 # i.e. 101 in binary
print FUNCTION(x)
and then I'd like returned:
[True, False, True]
or ideally, with padding to always return 8 boolean values (i.e. one full byte):
[False, False, False, False, False, True, False, True]
Thanks
You can use numpy's unpackbits.
From the docs (http://docs.scipy.org/doc/numpy/reference/generated/numpy.unpackbits.html)
>>> a = np.array([[2], [7], [23]], dtype=np.uint8)
>>> a
array([[ 2],
[ 7],
[23]], dtype=uint8)
>>> b = np.unpackbits(a, axis=1)
>>> b
array([[0, 0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 1, 1, 1],
[0, 0, 0, 1, 0, 1, 1, 1]], dtype=uint8)
To get to a bool array:
In [49]: np.unpackbits(np.array([1],dtype="uint8")).astype("bool")
Out[49]: array([False, False, False, False, False, False, False, True], dtype=bool)
Not a built in method, but something to get you going (and fun to write)
>>> def int_to_binary_bool(num):
return [bool(int(i)) for i in "{0:08b}".format(num)]
>>> int_to_binary_bool(5)
[False, False, False, False, False, True, False, True]

How to make this kind of equality array fast (in numpy)?

I have two numpy array (2 dimensional) e.g.
a1 = array([["a","b"],["a","c"],["b","b"],["a","b"]])
a2 = array([["a","b"],["b","b"],["c","a"],["a","c"]])
What is the most elegant way of getting a matrix like this:
array([[1,0,0,0],
[0,0,0,1],
[0,1,0,0],
[1,0,0,0]])
Where element (i,j) is 1 if all(a1[i,:] == a2[j,:]) and otherwise 0
(everything involving two for loops I don't consider elegant)
>>> (a1[:,numpy.newaxis] == a2).all(axis=2)
array([[ True, False, False, False],
[False, False, False, True],
[False, True, False, False],
[ True, False, False, False]], dtype=bool)
If you really need integers, convert to int as last step:
>>> (a1[:,numpy.newaxis] == a2).all(axis=2).astype(int)
array([[1, 0, 0, 0],
[0, 0, 0, 1],
[0, 1, 0, 0],
[1, 0, 0, 0]])

Categories

Resources