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 !
CodePudding user response:
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
CodePudding user response:
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])