1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
|
"""
Annotate segmentation with text
===============================
Perform a segmentation and annotate the results with
bounding boxes and text.
This example is fully explained in the following tutorial:
https://napari.org/stable/tutorials/segmentation/annotate_segmentation.html
.. tags:: analysis
"""
import numpy as np
from skimage import data
from skimage.filters import threshold_otsu
from skimage.measure import label, regionprops_table
from skimage.morphology import closing, remove_small_objects, square
from skimage.segmentation import clear_border
import napari
def segment(image):
"""Segment an image using an intensity threshold determined via
Otsu's method.
Parameters
----------
image : np.ndarray
The image to be segmented
Returns
-------
label_image : np.ndarray
The resulting image where each detected object labeled with a unique integer.
"""
# apply threshold
thresh = threshold_otsu(image)
bw = closing(image > thresh, square(4))
# remove artifacts connected to image border
cleared = remove_small_objects(clear_border(bw), 20)
# label image regions
label_image = label(cleared)
return label_image
def make_bbox(bbox_extents):
"""Get the coordinates of the corners of a
bounding box from the extents
Parameters
----------
bbox_extents : list (4xN)
List of the extents of the bounding boxes for each of the N regions.
Should be ordered: [min_row, min_column, max_row, max_column]
Returns
-------
bbox_rect : np.ndarray
The corners of the bounding box. Can be input directly into a
napari Shapes layer.
"""
minr = bbox_extents[0]
minc = bbox_extents[1]
maxr = bbox_extents[2]
maxc = bbox_extents[3]
bbox_rect = np.array(
[[minr, minc], [maxr, minc], [maxr, maxc], [minr, maxc]]
)
bbox_rect = np.moveaxis(bbox_rect, 2, 0)
return bbox_rect
def circularity(perimeter, area):
"""Calculate the circularity of the region
Parameters
----------
perimeter : float
the perimeter of the region
area : float
the area of the region
Returns
-------
circularity : float
The circularity of the region as defined by 4*pi*area / perimeter^2
"""
circularity = 4 * np.pi * area / (perimeter ** 2)
return circularity
# load the image and segment it
image = data.coins()[50:-50, 50:-50]
label_image = segment(image)
# create the features dictionary
features = regionprops_table(
label_image, properties=('label', 'bbox', 'perimeter', 'area')
)
features['circularity'] = circularity(
features['perimeter'], features['area']
)
# create the bounding box rectangles
bbox_rects = make_bbox([features[f'bbox-{i}'] for i in range(4)])
# specify the display parameters for the text
text_parameters = {
'string': 'label: {label}\ncirc: {circularity:.2f}',
'size': 12,
'color': 'green',
'anchor': 'upper_left',
'translation': [-3, 0],
}
# initialise viewer with coins image
viewer = napari.Viewer()
layer = viewer.add_image(image, name='coins', rgb=False)
# add the labels
label_layer = viewer.add_labels(label_image, name='segmentation')
shapes_layer = viewer.add_shapes(
bbox_rects,
face_color='transparent',
edge_color='green',
features=features,
text=text_parameters,
name='bounding box',
)
if __name__ == '__main__':
napari.run()
|