mirror of
https://github.com/wassname/scikit-image.git
synced 2026-07-02 07:55:57 +08:00
DOC: Remove peak detection tutorial.
The tutorial needs a lot of work and isn't a crucial part of this PR. Note: tutorial saved in a separate branch.
This commit is contained in:
@@ -1,231 +0,0 @@
|
||||
"""
|
||||
==============
|
||||
Peak detection
|
||||
==============
|
||||
|
||||
Peak detection (a.k.a. spot detection or particle detection) is a common
|
||||
image analysis step. For example, it's used to detect tracer particles in a
|
||||
flow for particle image velocimetry (i.e. PIV) and to identify features in
|
||||
the Hough transform.
|
||||
|
||||
To simplify plotting code, let's define a simple function that creates a new
|
||||
figure on each call, and removes tick labels.
|
||||
"""
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
plt.rcParams['axes.titlesize'] = 10
|
||||
plt.rcParams['font.size'] = 10
|
||||
def imshow(image, **kwargs):
|
||||
plt.figure(figsize=(2.5, 2.5))
|
||||
plt.imshow(image, **kwargs)
|
||||
plt.axis('off')
|
||||
|
||||
"""
|
||||
To explore different peak detection techniques, we use an image of circles with
|
||||
added noise:
|
||||
"""
|
||||
|
||||
from skimage import data
|
||||
img = data.load('noisy_circles.jpg')
|
||||
imshow(img)
|
||||
|
||||
"""
|
||||
|
||||
.. image:: PLOT2RST.current_figure
|
||||
|
||||
This image is noisy and has uneven background illumination. The peaks in the
|
||||
image, while readily identified by eye, can be tricky to find algorithmically.
|
||||
The first thing we need to do is remove the high-frequency noise; this can
|
||||
be done with a simple Gaussian filter.
|
||||
"""
|
||||
|
||||
import scipy.ndimage as ndimg
|
||||
img_smooth = ndimg.gaussian_filter(img, 3)
|
||||
|
||||
imshow(img_smooth)
|
||||
|
||||
"""
|
||||
|
||||
.. image:: PLOT2RST.current_figure
|
||||
|
||||
Thresholding
|
||||
============
|
||||
|
||||
One way to extract the background is to threshold the image.
|
||||
"""
|
||||
|
||||
thresh_value = 100
|
||||
background = img_smooth.copy()
|
||||
background[img_smooth > thresh_value] = 0
|
||||
peaks = img_smooth - background
|
||||
|
||||
"""
|
||||
Here, all pixels values below the threshold value are subtracted from the
|
||||
image. The resulting background image and the extracted peaks are shown below.
|
||||
"""
|
||||
|
||||
imshow(background, vmin=0, vmax=255)
|
||||
plt.title("background image (thresholding)")
|
||||
|
||||
"""
|
||||
.. image:: PLOT2RST.current_figure
|
||||
"""
|
||||
|
||||
imshow(peaks, vmin=0, vmax=255)
|
||||
plt.title("peaks (thresholding)")
|
||||
|
||||
"""
|
||||
.. image:: PLOT2RST.current_figure
|
||||
|
||||
Because of uneven illumination, peaks on the right bleed into each other.
|
||||
Increasing the threshold will fix this problem, but it will also cause some
|
||||
peaks on the left to go undetected.
|
||||
|
||||
Morphological reconstruction
|
||||
============================
|
||||
|
||||
Morphological reconstruction uses two images: a seed image and a mask image.
|
||||
Initially, all values of the reconstructed image start off pixel at the values
|
||||
of the seed image. A seed pixels of high intensity spread outwards until it
|
||||
hits the mask image (i.e. the mask value for a pixel is lower than the
|
||||
high-intensity value). Note that the mask is a gray-scale image that limits the
|
||||
maximum intensity at a pixel. This algorithm is clearer with pictures, which
|
||||
we generate below.
|
||||
|
||||
One common case uses mask and seed images derived from the same image but
|
||||
shifted in intensity. Note: be careful when shifting images integer values,
|
||||
since this can lead to under/overflow of values. To prevent the uint8 image we
|
||||
started with from underflowing during subtraction, we first convert to float:
|
||||
"""
|
||||
|
||||
from skimage import img_as_float
|
||||
img_r = img_as_float(img_smooth)
|
||||
|
||||
import skimage.morphology as morph
|
||||
h = 0.1
|
||||
rec = morph.reconstruction(img_r-h, img_r)
|
||||
|
||||
imshow(img_r, vmin=0, vmax=1)
|
||||
plt.title("original (smoothed) image")
|
||||
|
||||
"""
|
||||
.. image:: PLOT2RST.current_figure
|
||||
"""
|
||||
|
||||
imshow(rec, vmin=0, vmax=1)
|
||||
plt.title("background image (reconstruction)")
|
||||
|
||||
"""
|
||||
.. image:: PLOT2RST.current_figure
|
||||
|
||||
This reconstructed image looks pretty much like the original, except that the
|
||||
peaks in the image are truncated. The reconstructed image can then be
|
||||
subtracted from the original image to reveal the peaks of the image.
|
||||
"""
|
||||
|
||||
imshow(img_r-rec)
|
||||
plt.title("h-dome of image")
|
||||
|
||||
"""
|
||||
.. image:: PLOT2RST.current_figure
|
||||
|
||||
The result is known as the h-dome transformation [2]_, which extracts peaks of
|
||||
height `h` from the original image. To better understand what's going on,
|
||||
let's take a 1D slice along the middle of the image (cutting through peaks in
|
||||
the image).
|
||||
"""
|
||||
|
||||
img_slice = img_r[99:100, :]
|
||||
rec_slice = morph.reconstruction(img_slice-h, img_slice)
|
||||
|
||||
"""
|
||||
Plotting the reconstructed image (slice) next to the original image and the
|
||||
seed image shed light on the reconstruction process
|
||||
"""
|
||||
plt.figure(figsize=(4, 3))
|
||||
plt.plot(img_slice[0], 'k', label='original image')
|
||||
plt.plot(img_slice[0]-h, '0.5', label='seed image')
|
||||
plt.plot(rec_slice[0], 'r', label='reconstructed')
|
||||
plt.title("image slice")
|
||||
plt.xlabel('x')
|
||||
plt.ylabel('intensity')
|
||||
plt.legend()
|
||||
|
||||
"""
|
||||
.. image:: PLOT2RST.current_figure
|
||||
|
||||
Here, you see that morphological reconstruction dilates the seed image (i.e.
|
||||
the `h`-shifted image) until it intersects the mask (original image). Note that
|
||||
the peaks in the original image have very different intensity values (e.g. the
|
||||
peak at x=200 and x=100 differ by about 80). Subtracting the reconstructed
|
||||
image from the original image gives peaks of roughly equal intensity. Thus, the
|
||||
h-dome transformation is quiet effective at removing uneven, dark backgrounds
|
||||
from bright features. The inverse operation---the h-basin
|
||||
transformation---should be used when removing bright backgrounds from dark
|
||||
features.
|
||||
|
||||
|
||||
White tophat
|
||||
============
|
||||
"""
|
||||
|
||||
selem = morph.disk(10)
|
||||
opening = morph.opening(img_smooth, selem)
|
||||
top_hat = img_smooth - opening
|
||||
|
||||
imshow(opening, vmin=0, vmax=255)
|
||||
plt.title("Greyscale opening of image")
|
||||
|
||||
"""
|
||||
.. image:: PLOT2RST.current_figure
|
||||
"""
|
||||
|
||||
|
||||
imshow(top_hat)
|
||||
plt.title("Tophat with disk of r = 10")
|
||||
|
||||
"""
|
||||
.. image:: PLOT2RST.current_figure
|
||||
"""
|
||||
|
||||
selem = morph.disk(5)
|
||||
top_hat = morph.white_tophat(img_smooth, selem)
|
||||
|
||||
imshow(top_hat)
|
||||
plt.title("Tophat with disk of r = 5")
|
||||
|
||||
"""
|
||||
.. image:: PLOT2RST.current_figure
|
||||
"""
|
||||
|
||||
selem = morph.square(20)
|
||||
opening = morph.opening(img_smooth, selem)
|
||||
# scikit's top hat filter uses uint8 and doesn't check for over(under)flow.
|
||||
mask = opening > img_smooth
|
||||
opening[mask] = img_smooth[mask]
|
||||
top_hat = img_smooth - opening
|
||||
|
||||
imshow(opening, vmin=0, vmax=255)
|
||||
plt.title("Greyscale opening of image")
|
||||
|
||||
"""
|
||||
.. image:: PLOT2RST.current_figure
|
||||
"""
|
||||
|
||||
imshow(top_hat)
|
||||
plt.title("Tophat with square of w = 10")
|
||||
|
||||
plt.show()
|
||||
|
||||
"""
|
||||
.. image:: PLOT2RST.current_figure
|
||||
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] Crocker and Grier, Journal of Colloid and Interface Science (1996)
|
||||
.. [2] Vincent, L., IEEE Transactions on Image Processing (1993)
|
||||
|
||||
"""
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 26 KiB |
Reference in New Issue
Block a user