Skip to content

Commit eab8481

Browse files
mkcorlagru
andauthored
Include border when generating basin markers for watershed. (scikit-image#7362)
Updated the Segment human cells in mitosis (link to stable): - removed the very last figure, which doesn't add much value; - added a few words about the watershed segmentation step; - fixed the way markers are computed, so that basins touching the image border are included. You can see the difference especially if you look at the RHS vertical border of the image. Co-authored-by: Lars Grüter <[email protected]>
1 parent 8cc2c24 commit eab8481

File tree

1 file changed

+32
-26
lines changed

1 file changed

+32
-26
lines changed

doc/examples/applications/plot_human_mitosis.py

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,9 @@
2121
import numpy as np
2222
from scipy import ndimage as ndi
2323

24-
from skimage import color, feature, filters, measure, morphology, segmentation, util
25-
from skimage.data import human_mitosis
24+
import skimage as ski
2625

27-
image = human_mitosis()
26+
image = ski.data.human_mitosis()
2827

2928
fig, ax = plt.subplots()
3029
ax.imshow(image, cmap='gray')
@@ -70,7 +69,7 @@
7069
# To separate these three different classes of pixels, we
7170
# resort to :ref:`sphx_glr_auto_examples_segmentation_plot_multiotsu.py`.
7271

73-
thresholds = filters.threshold_multiotsu(image, classes=3)
72+
thresholds = ski.filters.threshold_multiotsu(image, classes=3)
7473
regions = np.digitize(image, bins=thresholds)
7574

7675
fig, ax = plt.subplots(ncols=2, figsize=(10, 5))
@@ -90,8 +89,8 @@
9089

9190
cells = image > thresholds[0]
9291
dividing = image > thresholds[1]
93-
labeled_cells = measure.label(cells)
94-
labeled_dividing = measure.label(dividing)
92+
labeled_cells = ski.measure.label(cells)
93+
labeled_dividing = ski.measure.label(dividing)
9594
naive_mi = labeled_dividing.max() / labeled_cells.max()
9695
print(naive_mi)
9796

@@ -112,12 +111,12 @@
112111
ax[0].imshow(image)
113112
ax[0].set_title('Original')
114113
ax[0].set_axis_off()
115-
ax[2].imshow(cells)
116-
ax[2].set_title('All nuclei?')
117-
ax[2].set_axis_off()
118114
ax[1].imshow(dividing)
119115
ax[1].set_title('Dividing nuclei?')
120116
ax[1].set_axis_off()
117+
ax[2].imshow(cells)
118+
ax[2].set_title('All nuclei?')
119+
ax[2].set_axis_off()
121120
plt.show()
122121

123122
#####################################################################
@@ -140,7 +139,9 @@
140139
higher_threshold = 125
141140
dividing = image > higher_threshold
142141

143-
smoother_dividing = filters.rank.mean(util.img_as_ubyte(dividing), morphology.disk(4))
142+
smoother_dividing = ski.filters.rank.mean(
143+
ski.util.img_as_ubyte(dividing), ski.morphology.disk(4)
144+
)
144145

145146
binary_smoother_dividing = smoother_dividing > 20
146147

@@ -152,7 +153,7 @@
152153

153154
#####################################################################
154155
# We are left with
155-
cleaned_dividing = measure.label(binary_smoother_dividing)
156+
cleaned_dividing = ski.measure.label(binary_smoother_dividing)
156157
print(cleaned_dividing.max())
157158

158159
#####################################################################
@@ -163,38 +164,43 @@
163164
# ==============
164165
# To separate overlapping nuclei, we resort to
165166
# :ref:`sphx_glr_auto_examples_segmentation_plot_watershed.py`.
166-
# To visualize the segmentation conveniently, we colour-code the labelled
167-
# regions using the `color.label2rgb` function, specifying the background
168-
# label with argument `bg_label=0`.
167+
# The idea of the algorithm is to find watershed basins as if flooded from
168+
# a set of `markers`. We generate these markers as the local maxima of the
169+
# distance function to the background. Given the typical size of the nuclei,
170+
# we pass ``min_distance=7`` so that local maxima and, hence, markers will lie
171+
# at least 7 pixels away from one another.
172+
# We also use ``exclude_border=False`` so that all nuclei touching the image
173+
# border will be included.
169174

170175
distance = ndi.distance_transform_edt(cells)
171176

172-
local_max_coords = feature.peak_local_max(distance, min_distance=7)
177+
local_max_coords = ski.feature.peak_local_max(
178+
distance, min_distance=7, exclude_border=False
179+
)
173180
local_max_mask = np.zeros(distance.shape, dtype=bool)
174181
local_max_mask[tuple(local_max_coords.T)] = True
175-
markers = measure.label(local_max_mask)
182+
markers = ski.measure.label(local_max_mask)
176183

177-
segmented_cells = segmentation.watershed(-distance, markers, mask=cells)
184+
segmented_cells = ski.segmentation.watershed(-distance, markers, mask=cells)
185+
186+
#####################################################################
187+
# To visualize the segmentation conveniently, we colour-code the labelled
188+
# regions using the `color.label2rgb` function, specifying the background
189+
# label with argument `bg_label=0`.
178190

179191
fig, ax = plt.subplots(ncols=2, figsize=(10, 5))
180192
ax[0].imshow(cells, cmap='gray')
181193
ax[0].set_title('Overlapping nuclei')
182194
ax[0].set_axis_off()
183-
ax[1].imshow(color.label2rgb(segmented_cells, bg_label=0))
195+
ax[1].imshow(ski.color.label2rgb(segmented_cells, bg_label=0))
184196
ax[1].set_title('Segmented nuclei')
185197
ax[1].set_axis_off()
186198
plt.show()
187199

188200
#####################################################################
189-
# Additionally, we may use function `color.label2rgb` to overlay the original
190-
# image with the segmentation result, using transparency (alpha parameter).
191-
192-
color_labels = color.label2rgb(segmented_cells, image, alpha=0.4, bg_label=0)
201+
# Make sure that the watershed algorithm has led to identifying more nuclei:
193202

194-
fig, ax = plt.subplots(figsize=(5, 5))
195-
ax.imshow(color_labels)
196-
ax.set_title('Segmentation result over raw image')
197-
plt.show()
203+
assert segmented_cells.max() > labeled_cells.max()
198204

199205
#####################################################################
200206
# Finally, we find a total number of

0 commit comments

Comments
 (0)