Skip to content
Snippets Groups Projects
Commit 69b08b1b authored by guiwitz's avatar guiwitz
Browse files

use images from master

parent 9be1512d
No related branches found
No related tags found
No related merge requests found
Source diff could not be displayed: it is too large. Options to address this: view the blob.
Source diff could not be displayed: it is too large. Options to address this: view the blob.
Source diff could not be displayed: it is too large. Options to address this: view the blob.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
# 10. Morphological operations # 10. Morphological operations
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
After the thresholding operation, one has a binary mask which is usually imperfect: object might have rough boundaries, holes etc. After the thresholding operation, one has a binary mask which is usually imperfect: object might have rough boundaries, holes etc.
Morphological operations are very commonly used to correct such masks. We focus here in particular on binary operations, i.e. operations acting on black and white images. Morphological operations are very commonly used to correct such masks. We focus here in particular on binary operations, i.e. operations acting on black and white images.
Let's import packages and quickly recreate a mask to work on. **Notice that we have to specifically import the morphology module from skimage which is not included by default** Let's import packages and quickly recreate a mask to work on. **Notice that we have to specifically import the morphology module from skimage which is not included by default**
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
import numpy as np import numpy as np
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import skimage import skimage
import skimage.io import skimage.io
import skimage.morphology import skimage.morphology
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
#image_stack = skimage.io.imread('images/46658_784_B12_1.tif') #image_stack = skimage.io.imread('images/46658_784_B12_1.tif')
image_stack = skimage.io.imread('https://github.com/guiwitz/PyImageCourse_beginner/raw/cellatlas/images/46658_784_B12_1.tif') image_stack = skimage.io.imread('https://github.com/guiwitz/PyImageCourse_beginner/raw/master/images/46658_784_B12_1.tif')
image_nuclei = image_stack[:,:,2] image_nuclei = image_stack[:,:,2]
my_otsu_threshold = skimage.filters.threshold_otsu(image_nuclei) my_otsu_threshold = skimage.filters.threshold_otsu(image_nuclei)
mask_otsu = image_nuclei > my_otsu_threshold mask_otsu = image_nuclei > my_otsu_threshold
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
And let's focus on a smaller region: And let's focus on a smaller region:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
cropped_mask = mask_otsu[750:1250,1400:1900].copy() cropped_mask = mask_otsu[750:1250,1400:1900].copy()
cropped_image = image_nuclei[750:1250,1400:1900].copy() cropped_image = image_nuclei[750:1250,1400:1900].copy()
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
plt.imshow(cropped_mask, cmap = 'gray'); plt.imshow(cropped_mask, cmap = 'gray');
``` ```
%% Output %% Output
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## 10.3 Erosion ## 10.3 Erosion
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
help(skimage.morphology.binary_erosion) help(skimage.morphology.binary_erosion)
``` ```
%% Output %% Output
Help on function binary_erosion in module skimage.morphology.binary: Help on function binary_erosion in module skimage.morphology.binary:
binary_erosion(image, selem=None, out=None) binary_erosion(image, selem=None, out=None)
Return fast binary morphological erosion of an image. Return fast binary morphological erosion of an image.
This function returns the same result as greyscale erosion but performs This function returns the same result as greyscale erosion but performs
faster for binary images. faster for binary images.
Morphological erosion sets a pixel at ``(i,j)`` to the minimum over all Morphological erosion sets a pixel at ``(i,j)`` to the minimum over all
pixels in the neighborhood centered at ``(i,j)``. Erosion shrinks bright pixels in the neighborhood centered at ``(i,j)``. Erosion shrinks bright
regions and enlarges dark regions. regions and enlarges dark regions.
Parameters Parameters
---------- ----------
image : ndarray image : ndarray
Binary input image. Binary input image.
selem : ndarray, optional selem : ndarray, optional
The neighborhood expressed as a 2-D array of 1's and 0's. The neighborhood expressed as a 2-D array of 1's and 0's.
If None, use a cross-shaped structuring element (connectivity=1). If None, use a cross-shaped structuring element (connectivity=1).
out : ndarray of bool, optional out : ndarray of bool, optional
The array to store the result of the morphology. If None is The array to store the result of the morphology. If None is
passed, a new array will be allocated. passed, a new array will be allocated.
Returns Returns
------- -------
eroded : ndarray of bool or uint eroded : ndarray of bool or uint
The result of the morphological erosion taking values in The result of the morphological erosion taking values in
``[False, True]``. ``[False, True]``.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
Erosion does what one expects: it shrinks the white regions. But how does it work ? Each pixel is visited. If it is white, one asks if any pixel in the neighborhood is black. If yes that pixel turns black. Of course this will only happen to pixels on the edges, as pixels in the middle of the nuclei are surrounded by white pixels. Erosion does what one expects: it shrinks the white regions. But how does it work ? Each pixel is visited. If it is white, one asks if any pixel in the neighborhood is black. If yes that pixel turns black. Of course this will only happen to pixels on the edges, as pixels in the middle of the nuclei are surrounded by white pixels.
We mentioned that the neighborhood is checked. The size of this neighborhood can be set by the user. For example we can observe a circular region around each pixel. The way to specify this neighborhood is give an image of it. Luckily, skimage has already implemented for us various shapes. For example a disk: We mentioned that the neighborhood is checked. The size of this neighborhood can be set by the user. For example we can observe a circular region around each pixel. The way to specify this neighborhood is give an image of it. Luckily, skimage has already implemented for us various shapes. For example a disk:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
help(skimage.morphology.disk) help(skimage.morphology.disk)
``` ```
%% Output %% Output
Help on function disk in module skimage.morphology.selem: Help on function disk in module skimage.morphology.selem:
disk(radius, dtype=<class 'numpy.uint8'>) disk(radius, dtype=<class 'numpy.uint8'>)
Generates a flat, disk-shaped structuring element. Generates a flat, disk-shaped structuring element.
A pixel is within the neighborhood if the Euclidean distance between A pixel is within the neighborhood if the Euclidean distance between
it and the origin is no greater than radius. it and the origin is no greater than radius.
Parameters Parameters
---------- ----------
radius : int radius : int
The radius of the disk-shaped structuring element. The radius of the disk-shaped structuring element.
Other Parameters Other Parameters
---------------- ----------------
dtype : data-type dtype : data-type
The data type of the structuring element. The data type of the structuring element.
Returns Returns
------- -------
selem : ndarray selem : ndarray
The structuring element where elements of the neighborhood The structuring element where elements of the neighborhood
are 1 and 0 otherwise. are 1 and 0 otherwise.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
my_disk = skimage.morphology.disk(3) my_disk = skimage.morphology.disk(3)
plt.imshow(my_disk,cmap = 'gray'); plt.imshow(my_disk,cmap = 'gray');
``` ```
%% Output %% Output
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
Let's try to use this disk to erode our image: Let's try to use this disk to erode our image:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
my_eroded = skimage.morphology.binary_erosion(cropped_mask, selem=my_disk) my_eroded = skimage.morphology.binary_erosion(cropped_mask, selem=my_disk)
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
plt.imshow(my_eroded, cmap = 'gray'); plt.imshow(my_eroded, cmap = 'gray');
``` ```
%% Output %% Output
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
To see what happened we can subtract the original and the eroded images: To see what happened we can subtract the original and the eroded images:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
plt.imshow(cropped_mask.astype(int) - my_eroded.astype(int), cmap = 'gray'); plt.imshow(cropped_mask.astype(int) - my_eroded.astype(int), cmap = 'gray');
``` ```
%% Output %% Output
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
What happends if we take an even larger neighborhood? What happends if we take an even larger neighborhood?
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
my_disk = skimage.morphology.disk(5) my_disk = skimage.morphology.disk(5)
my_eroded = skimage.morphology.binary_erosion(cropped_mask, selem=my_disk) my_eroded = skimage.morphology.binary_erosion(cropped_mask, selem=my_disk)
plt.imshow(my_eroded, cmap = 'gray'); plt.imshow(my_eroded, cmap = 'gray');
``` ```
%% Output %% Output
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
We lost one of the nuclei, which was so small that none of its pixels was "far enough" from a black pixel. We lost one of the nuclei, which was so small that none of its pixels was "far enough" from a black pixel.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## 10.4 Dilation ## 10.4 Dilation
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
Logically, dilation does the opposite of erosion: it visits every black pixel and verifies whether it has any white pixel in its neighborhood, and if yes turns it into white. Let's see an example: Logically, dilation does the opposite of erosion: it visits every black pixel and verifies whether it has any white pixel in its neighborhood, and if yes turns it into white. Let's see an example:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
my_disk = skimage.morphology.disk(3) my_disk = skimage.morphology.disk(3)
my_dilation = skimage.morphology.binary_dilation(cropped_mask, selem=my_disk) my_dilation = skimage.morphology.binary_dilation(cropped_mask, selem=my_disk)
plt.imshow(my_dilation, cmap = 'gray'); plt.imshow(my_dilation, cmap = 'gray');
``` ```
%% Output %% Output
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## 10.5 Combining operations ## 10.5 Combining operations
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
An efficient way to "clean-up" an image is to apply a series of such operations. Let's imagine that we for example want to remove very small nuclei. We can successively erode and dilate the image to remove object smaller than some threshold: An efficient way to "clean-up" an image is to apply a series of such operations. Let's imagine that we for example want to remove very small nuclei. We can successively erode and dilate the image to remove object smaller than some threshold:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
#1. Create neighborhood region #1. Create neighborhood region
my_disk = skimage.morphology.disk(5) my_disk = skimage.morphology.disk(5)
#2. Erode the image to suppress small elements #2. Erode the image to suppress small elements
my_cleanimage = skimage.morphology.binary_erosion(cropped_mask, selem=my_disk) my_cleanimage = skimage.morphology.binary_erosion(cropped_mask, selem=my_disk)
#3. Dilate the eroded image to recover objects of the right size #3. Dilate the eroded image to recover objects of the right size
my_cleanimage = skimage.morphology.binary_dilation(my_cleanimage, selem=my_disk) my_cleanimage = skimage.morphology.binary_dilation(my_cleanimage, selem=my_disk)
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
plt.imshow(my_cleanimage, cmap = 'gray'); plt.imshow(my_cleanimage, cmap = 'gray');
``` ```
%% Output %% Output
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
plt.imshow(cropped_mask, cmap = 'gray'); plt.imshow(cropped_mask, cmap = 'gray');
``` ```
%% Output %% Output
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
Combining erosion and dilation is very common, so there exist specific operations for that: erosion followed by dilation is ```skimage.morphology.binary_opening``` while dilation followed by erosion is ```skimage.morphology.binary_closing```. The latter is useful for us to "close holes": Combining erosion and dilation is very common, so there exist specific operations for that: erosion followed by dilation is ```skimage.morphology.binary_opening``` while dilation followed by erosion is ```skimage.morphology.binary_closing```. The latter is useful for us to "close holes":
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
image_closing = skimage.morphology.binary_closing(cropped_mask, selem=skimage.morphology.disk(7)) image_closing = skimage.morphology.binary_closing(cropped_mask, selem=skimage.morphology.disk(7))
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
plt.imshow(image_closing, cmap = 'gray'); plt.imshow(image_closing, cmap = 'gray');
``` ```
%% Output %% Output
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
``` ```
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment