Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download

📚 The CoCalc Library - books, templates and other resources

132929 views
License: OTHER
1
import matplotlib.pyplot as plt
2
import numpy as np
3
4
from ipywidgets import interact
5
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
6
from skimage import exposure, io, measure
7
8
9
def show_plane(axis, plane, cmap="gray", title=None):
10
"""Shows a specific plane within 3D data.
11
"""
12
axis.imshow(plane, cmap=cmap)
13
axis.set_xticks([])
14
axis.set_yticks([])
15
16
if title:
17
axis.set_title(title)
18
19
return None
20
21
22
def slice_in_3d(axis, shape, plane):
23
"""Draws a cube in a 3D plot.
24
25
Parameters
26
----------
27
axis : matplotlib.Axes
28
A matplotlib axis to be drawn.
29
shape : tuple or array (1, 3)
30
Shape of the input data.
31
plane : int
32
Number of the plane to be drawn.
33
34
Notes
35
-----
36
Originally from:
37
https://stackoverflow.com/questions/44881885/python-draw-parallelepiped
38
"""
39
Z = np.array([[0, 0, 0],
40
[1, 0, 0],
41
[1, 1, 0],
42
[0, 1, 0],
43
[0, 0, 1],
44
[1, 0, 1],
45
[1, 1, 1],
46
[0, 1, 1]])
47
48
Z = Z * shape
49
50
r = [-1, 1]
51
52
X, Y = np.meshgrid(r, r)
53
54
# plotting vertices
55
axis.scatter3D(Z[:, 0], Z[:, 1], Z[:, 2])
56
57
# list of sides' polygons of figure
58
verts = [[Z[0], Z[1], Z[2], Z[3]],
59
[Z[4], Z[5], Z[6], Z[7]],
60
[Z[0], Z[1], Z[5], Z[4]],
61
[Z[2], Z[3], Z[7], Z[6]],
62
[Z[1], Z[2], Z[6], Z[5]],
63
[Z[4], Z[7], Z[3], Z[0]],
64
[Z[2], Z[3], Z[7], Z[6]]]
65
66
# plotting sides
67
axis.add_collection3d(
68
Poly3DCollection(verts,
69
facecolors=(0, 1, 1, 0.25),
70
linewidths=1,
71
edgecolors='darkblue')
72
)
73
74
verts = np.array([[[0, 0, 0],
75
[0, 0, 1],
76
[0, 1, 1],
77
[0, 1, 0]]])
78
verts = verts * shape
79
verts += [plane, 0, 0]
80
81
axis.add_collection3d(
82
Poly3DCollection(verts,
83
facecolors='magenta',
84
linewidths=1,
85
edgecolors='black')
86
)
87
88
axis.set_xlabel('plane')
89
axis.set_ylabel('col')
90
axis.set_zlabel('row')
91
92
# auto-scale plot axes
93
scaling = np.array([getattr(axis, 'get_{}lim'.format(dim))() for dim in 'xyz'])
94
axis.auto_scale_xyz(*[[np.min(scaling), np.max(scaling)]] * 3)
95
96
return None
97
98
99
def slice_explorer(data, cmap='gray'):
100
"""Allows to explore 2D slices in 3D data.
101
102
Parameters
103
----------
104
data : array (M, N, P)
105
3D interest image.
106
cmap : str (optional)
107
A string referring to one of matplotlib's colormaps.
108
"""
109
data_len = len(data)
110
111
@interact(plane=(0, data_len-1), continuous_update=False)
112
def display_slice(plane=data_len/2):
113
fig, axis = plt.subplots(figsize=(20, 7))
114
axis_3d = fig.add_subplot(133, projection='3d')
115
show_plane(axis, data[plane], title='Plane {}'.format(plane), cmap=cmap)
116
slice_in_3d(axis=axis_3d, shape=data.shape, plane=plane)
117
plt.show()
118
119
return display_slice
120
121
122
def display(data, cmap="gray", step=2):
123
_, axes = plt.subplots(nrows=5, ncols=6, figsize=(16, 14))
124
125
# getting data min and max to plot limits
126
vmin, vmax = data.min(), data.max()
127
128
for axis, image in zip(axes.flatten(), data[::step]):
129
axis.imshow(image, cmap=cmap, vmin=vmin, vmax=vmax)
130
axis.set_xticks([])
131
axis.set_yticks([])
132
133
return None
134
135
136
def plot_hist(axis, data, title=None):
137
"""Helper function for plotting histograms.
138
"""
139
axis.hist(data.ravel(), bins=256)
140
axis.ticklabel_format(axis='y', style='scientific', scilimits=(0, 0))
141
142
if title:
143
axis.set_title(title)
144
145
return None
146
147
148
def plot_3d_surface(data, labels, region=3, spacing=(1.0, 1.0, 1.0)):
149
"""Generates a 3D surface plot for the specified region.
150
151
Parameters
152
----------
153
data : array (M, N, P)
154
3D interest image.
155
labels : array (M, N, P)
156
Labels corresponding to data, obtained by measure.label.
157
region : int, optional
158
The region of interest to be plotted.
159
spacing : array (1, 3)
160
Spacing information, set distances between pixels.
161
162
Notes
163
-----
164
The volume is visualized using the mesh vertexes and faces.
165
"""
166
properties = measure.regionprops(labels, intensity_image=data)
167
# skimage.measure.marching_cubes expects ordering (row, col, plane).
168
# We need to transpose the data:
169
volume = (labels == properties[region].label).transpose(1, 2, 0)
170
171
verts_px, faces_px, _, _ = measure.marching_cubes_lewiner(volume, level=0, spacing=(1.0, 1.0, 1.0))
172
surface_area_pixels = measure.mesh_surface_area(verts_px, faces_px)
173
174
verts_actual, faces_actual, _, _ = measure.marching_cubes_lewiner(volume, level=0, spacing=tuple(spacing))
175
surface_area_actual = measure.mesh_surface_area(verts_actual, faces_actual)
176
177
print('Surface area\n')
178
print(' * Total pixels: {:0.2f}'.format(surface_area_pixels))
179
print(' * Actual: {:0.2f}'.format(surface_area_actual))
180
181
fig = plt.figure(figsize=(10, 10))
182
ax = fig.add_subplot(111, projection='3d')
183
184
mesh = Poly3DCollection(verts_px[faces_px])
185
mesh.set_edgecolor('black')
186
ax.add_collection3d(mesh)
187
188
ax.set_xlabel('col')
189
ax.set_ylabel('row')
190
ax.set_zlabel('plane')
191
192
min_pln, min_row, min_col, max_pln, max_row, max_col = properties[region].bbox
193
194
ax.set_xlim(min_row, max_row)
195
ax.set_ylim(min_col, max_col)
196
ax.set_zlim(min_pln, max_pln)
197
198
plt.tight_layout()
199
plt.show()
200
201
return None
202
203
204
def results_from_part_1():
205
206
data = io.imread("images/cells.tif")
207
208
vmin, vmax = np.percentile(data, q=(0.5, 99.5))
209
rescaled = exposure.rescale_intensity(
210
data,
211
in_range=(vmin, vmax),
212
out_range=np.float32
213
)
214
215
equalized = exposure.equalize_hist(data)
216
217
return data, rescaled, equalized
218
219