Extracting boundary of a numpy array
One trick to get the contour would be to use binary dilation with 3x3 ones array as the kernel on the negated mask and look for the common ones between it and input. For 4-connected
boundary, it would be all ones array and for 8-connected
a plus-shaped ones array -
from scipy.ndimage.morphology import binary_dilationk = np.ones((3,3),dtype=int) # for 4-connectedk = np.zeros((3,3),dtype=int); k[1] = 1; k[:,1] = 1 # for 8-connectedout = binary_dilation(a==0, k) & a
Sample run -
Input array :
In [384]: aOut[384]: array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1, 0, 0, 0, 0], [0, 0, 1, 1, 1, 0, 0, 0, 0, 0], [0, 1, 1, 1, 1, 0, 0, 0, 0, 0], [0, 1, 1, 1, 0, 0, 0, 0, 0, 0], [0, 1, 1, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])In [385]: from scipy.ndimage.morphology import binary_dilation
Solve for 4-connected :
In [386]: k = np.ones((3,3),dtype=int)In [390]: binary_dilation(a==0, k) & aOut[390]: array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 0, 0, 0, 0], [0, 0, 1, 1, 0, 1, 0, 0, 0, 0], [0, 0, 1, 0, 1, 1, 0, 0, 0, 0], [0, 0, 1, 0, 1, 0, 0, 0, 0, 0], [0, 1, 1, 1, 1, 0, 0, 0, 0, 0], [0, 1, 0, 1, 0, 0, 0, 0, 0, 0], [0, 1, 1, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
Solve for 8-connected :
In [411]: k = np.zeros((3,3),dtype=int); k[1] = 1; k[:,1] = 1In [412]: kOut[412]: array([[0, 1, 0], [1, 1, 1], [0, 1, 0]])In [413]: binary_dilation(a==0, k) & aOut[413]: array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 0, 0, 0, 0], [0, 0, 1, 0, 0, 1, 0, 0, 0, 0], [0, 0, 1, 0, 0, 1, 0, 0, 0, 0], [0, 0, 1, 0, 1, 0, 0, 0, 0, 0], [0, 1, 0, 0, 1, 0, 0, 0, 0, 0], [0, 1, 0, 1, 0, 0, 0, 0, 0, 0], [0, 1, 1, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
We could also use binary_erosion
:
from scipy.ndimage.morphology import binary_erosionout = a-binary_erosion(a,k)