morphology
¶skimage.morphology.
ball
(radius, dtype=<class 'numpy.uint8'>)[source]¶Generates a ballshaped structuring element.
This is the 3D equivalent of a disk. A pixel is within the neighborhood if the euclidean distance between it and the origin is no greater than radius.
Parameters:  radius : int


Returns:  selem : ndarray

Other Parameters:  
dtype : datatype

skimage.morphology.
binary_closing
(image, selem=None, out=None)[source]¶Return fast binary morphological closing of an image.
This function returns the same result as greyscale closing but performs faster for binary images.
The morphological closing on an image is defined as a dilation followed by an erosion. Closing can remove small dark spots (i.e. “pepper”) and connect small bright cracks. This tends to “close” up (dark) gaps between (bright) features.
Parameters:  image : ndarray
selem : ndarray, optional
out : ndarray of bool, optional


Returns:  closing : ndarray of bool

skimage.morphology.
binary_dilation
(image, selem=None, out=None)[source]¶Return fast binary morphological dilation of an image.
This function returns the same result as greyscale dilation but performs faster for binary images.
Morphological dilation sets a pixel at (i,j)
to the maximum over all
pixels in the neighborhood centered at (i,j)
. Dilation enlarges bright
regions and shrinks dark regions.
Parameters:  image : ndarray
selem : ndarray, optional
out : ndarray of bool, optional


Returns:  dilated : ndarray of bool or uint

skimage.morphology.
binary_erosion
(image, selem=None, out=None)[source]¶Return fast binary morphological erosion of an image.
This function returns the same result as greyscale erosion but performs faster for binary images.
Morphological erosion sets a pixel at (i,j)
to the minimum over all
pixels in the neighborhood centered at (i,j)
. Erosion shrinks bright
regions and enlarges dark regions.
Parameters:  image : ndarray
selem : ndarray, optional
out : ndarray of bool, optional


Returns:  eroded : ndarray of bool or uint

skimage.morphology.
binary_opening
(image, selem=None, out=None)[source]¶Return fast binary morphological opening of an image.
This function returns the same result as greyscale opening but performs faster for binary images.
The morphological opening on an image is defined as an erosion followed by a dilation. Opening can remove small bright spots (i.e. “salt”) and connect small dark cracks. This tends to “open” up (dark) gaps between (bright) features.
Parameters:  image : ndarray
selem : ndarray, optional
out : ndarray of bool, optional


Returns:  opening : ndarray of bool

skimage.morphology.
black_tophat
(image, selem=None, out=None)[source]¶Return black top hat of an image.
The black top hat of an image is defined as its morphological closing minus the original image. This operation returns the dark spots of the image that are smaller than the structuring element. Note that dark spots in the original image are bright spots after the black top hat.
Parameters:  image : ndarray
selem : ndarray, optional
out : ndarray, optional


Returns:  opening : array, same shape and type as image

Examples
>>> # Change dark peak to bright peak and subtract background
>>> import numpy as np
>>> from skimage.morphology import square
>>> dark_on_grey = np.array([[7, 6, 6, 6, 7],
... [6, 5, 4, 5, 6],
... [6, 4, 0, 4, 6],
... [6, 5, 4, 5, 6],
... [7, 6, 6, 6, 7]], dtype=np.uint8)
>>> black_tophat(dark_on_grey, square(3))
array([[0, 0, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 1, 5, 1, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 0]], dtype=uint8)
skimage.morphology.
closing
(image, selem=None, out=None)[source]¶Return greyscale morphological closing of an image.
The morphological closing on an image is defined as a dilation followed by an erosion. Closing can remove small dark spots (i.e. “pepper”) and connect small bright cracks. This tends to “close” up (dark) gaps between (bright) features.
Parameters:  image : ndarray
selem : ndarray, optional
out : ndarray, optional


Returns:  closing : array, same shape and type as image

Examples
>>> # Close a gap between two bright lines
>>> import numpy as np
>>> from skimage.morphology import square
>>> broken_line = np.array([[0, 0, 0, 0, 0],
... [0, 0, 0, 0, 0],
... [1, 1, 0, 1, 1],
... [0, 0, 0, 0, 0],
... [0, 0, 0, 0, 0]], dtype=np.uint8)
>>> closing(broken_line, square(3))
array([[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[1, 1, 1, 1, 1],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]], dtype=uint8)
skimage.morphology.
convex_hull_image
(image)[source]¶Compute the convex hull image of a binary image.
The convex hull is the set of pixels included in the smallest convex polygon that surround all white pixels in the input image.
Parameters:  image : ndarray


Returns:  hull : ndarray of bool

References
[R146]  http://blogs.mathworks.com/steve/2011/10/04/binaryimageconvexhullalgorithmnotes/ 
skimage.morphology.
convex_hull_object
(image, neighbors=8)[source]¶Compute the convex hull image of individual objects in a binary image.
The convex hull is the set of pixels included in the smallest convex polygon that surround all white pixels in the input image.
Parameters:  image : ndarray
neighbors : {4, 8}, int


Returns:  hull : ndarray of bool

Notes
This function uses skimage.morphology.label to define unique objects, finds the convex hull of each using convex_hull_image, and combines these regions with logical OR. Be aware the convex hulls of unconnected objects may overlap in the result. If this is suspected, consider using convex_hull_image separately on each object.
skimage.morphology.
cube
(width, dtype=<class 'numpy.uint8'>)[source]¶Generates a cubeshaped structuring element.
This is the 3D equivalent of a square. Every pixel along the perimeter has a chessboard distance no greater than radius (radius=floor(width/2)) pixels.
Parameters:  width : int


Returns:  selem : ndarray

Other Parameters:  
dtype : datatype

skimage.morphology.
diamond
(radius, dtype=<class 'numpy.uint8'>)[source]¶Generates a flat, diamondshaped structuring element.
A pixel is part of the neighborhood (i.e. labeled 1) if the city block/manhattan distance between it and the center of the neighborhood is no greater than radius.
Parameters:  radius : int


Returns:  selem : ndarray

Other Parameters:  
dtype : datatype

skimage.morphology.
dilation
(image, selem=None, out=None, shift_x=False, shift_y=False)[source]¶Return greyscale morphological dilation of an image.
Morphological dilation sets a pixel at (i,j) to the maximum over all pixels in the neighborhood centered at (i,j). Dilation enlarges bright regions and shrinks dark regions.
Parameters:  image : ndarray
selem : ndarray, optional
out : ndarray, optional
shift_x, shift_y : bool, optional


Returns:  dilated : uint8 array, same shape and type as image

Notes
For uint8 (and uint16 up to a certain bitdepth) data, the lower algorithm complexity makes the skimage.filter.rank.maximum function more efficient for larger images and structuring elements.
Examples
>>> # Dilation enlarges bright regions
>>> import numpy as np
>>> from skimage.morphology import square
>>> bright_pixel = np.array([[0, 0, 0, 0, 0],
... [0, 0, 0, 0, 0],
... [0, 0, 1, 0, 0],
... [0, 0, 0, 0, 0],
... [0, 0, 0, 0, 0]], dtype=np.uint8)
>>> dilation(bright_pixel, square(3))
array([[0, 0, 0, 0, 0],
[0, 1, 1, 1, 0],
[0, 1, 1, 1, 0],
[0, 1, 1, 1, 0],
[0, 0, 0, 0, 0]], dtype=uint8)
skimage.morphology.
disk
(radius, dtype=<class 'numpy.uint8'>)[source]¶Generates a flat, diskshaped structuring element.
A pixel is within the neighborhood if the euclidean distance between it and the origin is no greater than radius.
Parameters:  radius : int


Returns:  selem : ndarray

Other Parameters:  
dtype : datatype

skimage.morphology.
erosion
(image, selem=None, out=None, shift_x=False, shift_y=False)[source]¶Return greyscale morphological erosion of an image.
Morphological erosion sets a pixel at (i,j) to the minimum over all pixels in the neighborhood centered at (i,j). Erosion shrinks bright regions and enlarges dark regions.
Parameters:  image : ndarray
selem : ndarray, optional
out : ndarrays, optional
shift_x, shift_y : bool, optional


Returns:  eroded : array, same shape as image

Notes
For uint8
(and uint16
up to a certain bitdepth) data, the
lower algorithm complexity makes the skimage.filter.rank.minimum
function more efficient for larger images and structuring elements.
Examples
>>> # Erosion shrinks bright regions
>>> import numpy as np
>>> from skimage.morphology import square
>>> bright_square = np.array([[0, 0, 0, 0, 0],
... [0, 1, 1, 1, 0],
... [0, 1, 1, 1, 0],
... [0, 1, 1, 1, 0],
... [0, 0, 0, 0, 0]], dtype=np.uint8)
>>> erosion(bright_square, square(3))
array([[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]], dtype=uint8)
skimage.morphology.
label
(input, neighbors=None, background=None, return_num=False, connectivity=None)[source]¶Deprecated function. Use skimage.measure.label
instead.
Label connected regions of an integer array.
Two pixels are connected when they are neighbors and have the same value. In 2D, they can be neighbors either in a 1 or 2connected sense. The value refers to the maximum number of orthogonal hops to consider a pixel/voxel a neighbor:
1connectivity 2connectivity diagonal connection closeup
[ ] [ ] [ ] [ ] [ ]
 \  /  < hop 2
[ ][x][ ] [ ][x][ ] [x][ ]
 /  \ hop 1
[ ] [ ] [ ] [ ]
Parameters:  input : ndarray of dtype int
neighbors : {4, 8}, int, optional
background : int, optional
return_num : bool, optional
connectivity : int, optional


Returns:  labels : ndarray of dtype int
num : int, optional

Examples
>>> import numpy as np
>>> x = np.eye(3).astype(int)
>>> print(x)
[[1 0 0]
[0 1 0]
[0 0 1]]
>>> from skimage.measure import label
>>> print(label(x, connectivity=1))
[[0 1 1]
[2 3 1]
[2 2 4]]
>>> print(label(x, connectivity=2))
[[0 1 1]
[1 0 1]
[1 1 0]]
>>> x = np.array([[1, 0, 0],
... [1, 1, 5],
... [0, 0, 0]])
>>> print(label(x, background=0))
[[ 0 1 1]
[ 0 0 1]
[1 1 1]]
skimage.morphology.
medial_axis
(image, mask=None, return_distance=False)[source]¶Compute the medial axis transform of a binary image
Parameters:  image : binary ndarray, shape (M, N)
mask : binary ndarray, shape (M, N), optional
return_distance : bool, optional


Returns:  out : ndarray of bools
dist : ndarray of ints, optional

See also
Notes
This algorithm computes the medial axis transform of an image as the ridges of its distance transform.
Examples
>>> square = np.zeros((7, 7), dtype=np.uint8)
>>> square[1:1, 2:2] = 1
>>> square
array([[0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 1, 1, 0, 0],
[0, 0, 1, 1, 1, 0, 0],
[0, 0, 1, 1, 1, 0, 0],
[0, 0, 1, 1, 1, 0, 0],
[0, 0, 1, 1, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0]], dtype=uint8)
>>> medial_axis(square).astype(np.uint8)
array([[0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 1, 0, 0],
[0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0],
[0, 0, 1, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0]], dtype=uint8)
skimage.morphology.
octagon
(m, n, dtype=<class 'numpy.uint8'>)[source]¶Generates an octagon shaped structuring element.
For a given size of (m) horizontal and vertical sides and a given (n) height or width of slanted sides octagon is generated. The slanted sides are 45 or 135 degrees to the horizontal axis and hence the widths and heights are equal.
Parameters:  m : int
n : int


Returns:  selem : ndarray

Other Parameters:  
dtype : datatype

skimage.morphology.
octahedron
(radius, dtype=<class 'numpy.uint8'>)[source]¶Generates a octahedronshaped structuring element.
This is the 3D equivalent of a diamond. A pixel is part of the neighborhood (i.e. labeled 1) if the city block/manhattan distance between it and the center of the neighborhood is no greater than radius.
Parameters:  radius : int


Returns:  selem : ndarray

Other Parameters:  
dtype : datatype

skimage.morphology.
opening
(image, selem=None, out=None)[source]¶Return greyscale morphological opening of an image.
The morphological opening on an image is defined as an erosion followed by a dilation. Opening can remove small bright spots (i.e. “salt”) and connect small dark cracks. This tends to “open” up (dark) gaps between (bright) features.
Parameters:  image : ndarray
selem : ndarray, optional
out : ndarray, optional


Returns:  opening : array, same shape and type as image

Examples
>>> # Open up gap between two bright regions (but also shrink regions)
>>> import numpy as np
>>> from skimage.morphology import square
>>> bad_connection = np.array([[1, 0, 0, 0, 1],
... [1, 1, 0, 1, 1],
... [1, 1, 1, 1, 1],
... [1, 1, 0, 1, 1],
... [1, 0, 0, 0, 1]], dtype=np.uint8)
>>> opening(bad_connection, square(3))
array([[0, 0, 0, 0, 0],
[1, 1, 0, 1, 1],
[1, 1, 0, 1, 1],
[1, 1, 0, 1, 1],
[0, 0, 0, 0, 0]], dtype=uint8)
skimage.morphology.
reconstruction
(seed, mask, method='dilation', selem=None, offset=None)[source]¶Perform a morphological reconstruction of an image.
Morphological reconstruction by dilation is similar to basic morphological dilation: highintensity values will replace nearby lowintensity values. The basic dilation operator, however, uses a structuring element to determine how far a value in the input image can spread. In contrast, reconstruction uses two images: a “seed” image, which specifies the values that spread, and a “mask” image, which gives the maximum allowed value at each pixel. The mask image, like the structuring element, limits the spread of highintensity values. Reconstruction by erosion is simply the inverse: lowintensity values spread from the seed image and are limited by the mask image, which represents the minimum allowed value.
Alternatively, you can think of reconstruction as a way to isolate the connected regions of an image. For dilation, reconstruction connects regions marked by local maxima in the seed image: neighboring pixels lessthanorequalto those seeds are connected to the seeded region. Local maxima with values larger than the seed image will get truncated to the seed value.
Parameters:  seed : ndarray
mask : ndarray
method : {‘dilation’’erosion’}
selem : ndarray


Returns:  reconstructed : ndarray

Notes
The algorithm is taken from [R147]. Applications for greyscale reconstruction are discussed in [R148] and [R149].
References
[R147]  (1, 2) Robinson, “Efficient morphological reconstruction: a downhill filter”, Pattern Recognition Letters 25 (2004) 17591767. 
[R148]  (1, 2) Vincent, L., “Morphological Grayscale Reconstruction in Image Analysis: Applications and Efficient Algorithms”, IEEE Transactions on Image Processing (1993) 
[R149]  (1, 2) Soille, P., “Morphological Image Analysis: Principles and Applications”, Chapter 6, 2nd edition (2003), ISBN 3540429883. 
Examples
>>> import numpy as np
>>> from skimage.morphology import reconstruction
First, we create a sinusoidal mask image with peaks at middle and ends.
>>> x = np.linspace(0, 4 * np.pi)
>>> y_mask = np.cos(x)
Then, we create a seed image initialized to the minimum mask value (for reconstruction by dilation, minintensity values don’t spread) and add “seeds” to the left and right peak, but at a fraction of peak value (1).
>>> y_seed = y_mask.min() * np.ones_like(x)
>>> y_seed[0] = 0.5
>>> y_seed[1] = 0
>>> y_rec = reconstruction(y_seed, y_mask)
The reconstructed image (or curve, in this case) is exactly the same as the mask image, except that the peaks are truncated to 0.5 and 0. The middle peak disappears completely: Since there were no seed values in this peak region, its reconstructed value is truncated to the surrounding value (1).
As a more practical example, we try to extract the bright features of an image by subtracting a background image created by reconstruction.
>>> y, x = np.mgrid[:20:0.5, :20:0.5]
>>> bumps = np.sin(x) + np.sin(y)
To create the background image, set the mask image to the original image, and the seed image to the original image with an intensity offset, h.
>>> h = 0.3
>>> seed = bumps  h
>>> background = reconstruction(seed, bumps)
The resulting reconstructed image looks exactly like the original image, but with the peaks of the bumps cut off. Subtracting this reconstructed image from the original image leaves just the peaks of the bumps
>>> hdome = bumps  background
This operation is known as the hdome of the image and leaves features of height h in the subtracted image.
skimage.morphology.
rectangle
(width, height, dtype=<class 'numpy.uint8'>)[source]¶Generates a flat, rectangularshaped structuring element.
Every pixel in the rectangle generated for a given width and given height belongs to the neighboorhood.
Parameters:  width : int
height : int


Returns:  selem : ndarray

Other Parameters:  
dtype : datatype

skimage.morphology.
remove_small_objects
(ar, min_size=64, connectivity=1, in_place=False)[source]¶Remove connected components smaller than the specified size.
Parameters:  ar : ndarray (arbitrary shape, int or bool type)
min_size : int, optional (default: 64)
connectivity : int, {1, 2, ..., ar.ndim}, optional (default: 1)
in_place : bool, optional (default: False)


Returns:  out : ndarray, same shape and type as input ar

Raises:  TypeError
ValueError

Examples
>>> from skimage import morphology
>>> a = np.array([[0, 0, 0, 1, 0],
... [1, 1, 1, 0, 0],
... [1, 1, 1, 0, 1]], bool)
>>> b = morphology.remove_small_objects(a, 6)
>>> b
array([[False, False, False, False, False],
[ True, True, True, False, False],
[ True, True, True, False, False]], dtype=bool)
>>> c = morphology.remove_small_objects(a, 7, connectivity=2)
>>> c
array([[False, False, False, True, False],
[ True, True, True, False, False],
[ True, True, True, False, False]], dtype=bool)
>>> d = morphology.remove_small_objects(a, 6, in_place=True)
>>> d is a
True
skimage.morphology.
skeletonize
(image)[source]¶Return the skeleton of a binary image.
Thinning is used to reduce each connected component in a binary image to a singlepixel wide skeleton.
Parameters:  image : numpy.ndarray


Returns:  skeleton : ndarray

See also
Notes
The algorithm [R150] works by making successive passes of the image, removing pixels on object borders. This continues until no more pixels can be removed. The image is correlated with a mask that assigns each pixel a number in the range [0...255] corresponding to each possible pattern of its 8 neighbouring pixels. A look up table is then used to assign the pixels a value of 0, 1, 2 or 3, which are selectively removed during the iterations.
Note that this algorithm will give different results than a medial axis transform, which is also often referred to as “skeletonization”.
References
[R150]  (1, 2) A fast parallel algorithm for thinning digital patterns, T. Y. Zhang and C. Y. Suen, Communications of the ACM, March 1984, Volume 27, Number 3. 
Examples
>>> X, Y = np.ogrid[0:9, 0:9]
>>> ellipse = (1./3 * (X  4)**2 + (Y  4)**2 < 3**2).astype(np.uint8)
>>> ellipse
array([[0, 0, 0, 1, 1, 1, 0, 0, 0],
[0, 0, 1, 1, 1, 1, 1, 0, 0],
[0, 0, 1, 1, 1, 1, 1, 0, 0],
[0, 0, 1, 1, 1, 1, 1, 0, 0],
[0, 0, 1, 1, 1, 1, 1, 0, 0],
[0, 0, 1, 1, 1, 1, 1, 0, 0],
[0, 0, 1, 1, 1, 1, 1, 0, 0],
[0, 0, 1, 1, 1, 1, 1, 0, 0],
[0, 0, 0, 1, 1, 1, 0, 0, 0]], dtype=uint8)
>>> skel = skeletonize(ellipse)
>>> skel.astype(np.uint8)
array([[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=uint8)
skimage.morphology.
square
(width, dtype=<class 'numpy.uint8'>)[source]¶Generates a flat, squareshaped structuring element.
Every pixel along the perimeter has a chessboard distance no greater than radius (radius=floor(width/2)) pixels.
Parameters:  width : int


Returns:  selem : ndarray

Other Parameters:  
dtype : datatype

skimage.morphology.
star
(a, dtype=<class 'numpy.uint8'>)[source]¶Generates a star shaped structuring element.
Start has 8 vertices and is an overlap of square of size 2*a + 1 with its 45 degree rotated version. The slanted sides are 45 or 135 degrees to the horizontal axis.
Parameters:  a : int


Returns:  selem : ndarray

Other Parameters:  
dtype : datatype

skimage.morphology.
watershed
(image, markers, connectivity=None, offset=None, mask=None)[source]¶Return a matrix labeled using the watershed segmentation algorithm
Parameters:  image: ndarray (2D, 3D, ...) of integers
markers: ndarray of the same shape as `image`
connectivity: ndarray, optional
offset: array_like of shape image.ndim, optional
mask: ndarray of bools or 0s and 1s, optional


Returns:  out: ndarray

See also
skimage.segmentation.random_walker
Notes
This function implements a watershed algorithm [R151]_that apportions pixels into marked basins. The algorithm uses a priority queue to hold the pixels with the metric for the priority queue being pixel value, then the time of entry into the queue  this settles ties in favor of the closest marker.
Some ideas taken from Soille, “Automated Basin Delineation from Digital Elevation Models Using Mathematical Morphology”, Signal Processing 20 (1990) 171182
The most important insight in the paper is that entry time onto the queue solves two problems: a pixel should be assigned to the neighbor with the largest gradient or, if there is no gradient, pixels on a plateau should be split between markers on opposite sides.
This implementation converts all arguments to specific, lowest common denominator types, then passes these to a C algorithm.
Markers can be determined manually, or automatically using for example the local minima of the gradient of the image, or the local maxima of the distance function to the background for separating overlapping objects (see example).
References
[R151]  http://en.wikipedia.org/wiki/Watershed_%28image_processing%29 
[R152]  http://cmm.ensmp.fr/~beucher/wtshed.html 
Examples
The watershed algorithm is very useful to separate overlapping objects
>>> # Generate an initial image with two overlapping circles
>>> x, y = np.indices((80, 80))
>>> x1, y1, x2, y2 = 28, 28, 44, 52
>>> r1, r2 = 16, 20
>>> mask_circle1 = (x  x1)**2 + (y  y1)**2 < r1**2
>>> mask_circle2 = (x  x2)**2 + (y  y2)**2 < r2**2
>>> image = np.logical_or(mask_circle1, mask_circle2)
>>> # Now we want to separate the two objects in image
>>> # Generate the markers as local maxima of the distance
>>> # to the background
>>> from scipy import ndimage as ndi
>>> distance = ndi.distance_transform_edt(image)
>>> from skimage.feature import peak_local_max
>>> local_maxi = peak_local_max(distance, labels=image,
... footprint=np.ones((3, 3)),
... indices=False)
>>> markers = ndi.label(local_maxi)[0]
>>> labels = watershed(distance, markers, mask=image)
The algorithm works also for 3D images, and can be used for example to separate overlapping spheres.
skimage.morphology.
white_tophat
(image, selem=None, out=None)[source]¶Return white top hat of an image.
The white top hat of an image is defined as the image minus its morphological opening. This operation returns the bright spots of the image that are smaller than the structuring element.
Parameters:  image : ndarray
selem : ndarray, optional
out : ndarray, optional


Returns:  out : array, same shape and type as image

Examples
>>> # Subtract grey background from bright peak
>>> import numpy as np
>>> from skimage.morphology import square
>>> bright_on_grey = np.array([[2, 3, 3, 3, 2],
... [3, 4, 5, 4, 3],
... [3, 5, 9, 5, 3],
... [3, 4, 5, 4, 3],
... [2, 3, 3, 3, 2]], dtype=np.uint8)
>>> white_tophat(bright_on_grey, square(3))
array([[0, 0, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 1, 5, 1, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 0]], dtype=uint8)