Diff of /10x/reference/batch.py [000000] .. [171cba]

Switch to unified view

a b/10x/reference/batch.py
1
# -*- coding: utf-8 -*-
2
# <nbformat>3.0</nbformat>
3
4
# <codecell>
5
6
import os
7
8
import numpy as np
9
10
import skimage as ski
11
from skimage import io, filter, color, exposure, morphology, feature, draw, measure, transform
12
13
from scipy.spatial import distance
14
from scipy import ndimage
15
16
import matplotlib
17
%matplotlib inline
18
import matplotlib.pyplot as plt
19
import seaborn
20
matplotlib.rcParams["figure.figsize"] = (16, 10)
21
22
# <codecell>
23
24
# Load filenames
25
dirq = "/Users/qcaudron/repositories/Quantitative-Histology/10x/data/"
26
files = []
27
for i in os.listdir(dirq) :
28
    if i.endswith(".jpg") :
29
        files.append(dirq + i)
30
        
31
32
offset = 1000
33
lengthscale = 301
34
A = io.imread(files[4])
35
36
37
# Things to measure for each image
38
in_count = []
39
out_count = []
40
in_size = []
41
out_size = []
42
in_area_density = []
43
out_area_density = []
44
in_point_density = []
45
out_point_density = []
46
var_point_density = []
47
cov_point_density = []
48
var_area_density = []
49
cov_area_density = []
50
fs_area = []
51
pairwise = []
52
53
54
image = exposure.equalize_adapthist(A)
55
io.imshow(image)
56
plt.grid(False)
57
58
# <codecell>
59
60
# Process for nuclei
61
62
binary = filter.threshold_adaptive(exposure.adjust_sigmoid(A[:, :, 0], cutoff=0.4, gain = 30), 301).astype(bool)
63
clean = morphology.binary_closing(binary, morphology.disk(3)).astype(bool)
64
clean = morphology.remove_small_objects(clean, 200)
65
clean = morphology.remove_small_objects( (1-clean).astype(bool), 200)
66
67
io.imshow(clean)
68
plt.grid(False)
69
70
# <codecell>
71
72
# Find contour of inflammatory zone
73
74
local_density = filter.gaussian_filter(clean, 61)
75
local_density -= local_density.min()
76
local_density /= local_density.max()
77
78
ent = filter.gaussian_filter(filter.rank.entropy(local_density, morphology.disk(3)), 75)
79
ent -= ent.min()
80
ent /= ent.max()
81
82
info = ent * (1 + local_density)
83
84
bw = (info) > filter.threshold_otsu(info)
85
86
C = measure.find_contours(bw, 0.5)
87
centroid = []
88
vals = []
89
90
for c in C :
91
    centroid.append(np.linalg.norm([c[:, 1].mean() - bw.shape[1] / 2, c[:, 0].mean() - bw.shape[0] / 2]))
92
    vals.append(local_density.T[c.astype(int)].sum())
93
94
cent = C[np.argmin(centroid / np.array(vals))]
95
path = matplotlib.path.Path(cent)
96
97
io.imshow(image)
98
plt.plot(cent[:, 1], cent[:, 0], lw=5, c="k", alpha = 0.7)
99
plt.grid(False)
100
101
# <codecell>
102
103
# Segmentation
104
105
distance = ndimage.distance_transform_edt(clean)
106
peaks = feature.peak_local_max(distance, indices=False, labels = clean)
107
markers = ndimage.label(peaks)[0]
108
labels = morphology.watershed(-distance, markers, mask=clean)
109
110
io.imshow(labels, interpolation = "nearest", cmap = plt.cm.spectral)
111
plt.grid(False)
112
113
# <codecell>
114
115
# Properties of each nucleus
116
nuclei = measure.regionprops(labels)
117
contour = matplotlib.path.Path(cent, closed=True)
118
119
incount = 0
120
outcount = 0
121
insize = []
122
outsize = []
123
outer_nuclei = []
124
125
# Number of nuclei, and their sizes, inside and outside the focus
126
for n in nuclei :
127
    if contour.contains_point(n.centroid) :
128
        incount += 1
129
        insize.append((labels == n.label).sum())
130
    else :
131
        outcount += 1
132
        outsize.append((labels == n.label).sum())
133
        outer_nuclei.append(n)
134
135
in_count.append(incount)
136
out_count.append(outcount)
137
in_size.append(np.mean(insize))
138
out_size.append(np.mean(outsize))
139
140
141
142
143
# Using the shoelace algorithm, compute the area of the focus
144
x = path.vertices[:, 0]
145
y = path.vertices[:, 1]
146
x = np.append(x, path.vertices[0, 0])
147
y = np.append(y, path.vertices[0, 1])
148
fsarea = np.abs(np.sum(x[:-1] * y[1:] - x[1:] * y[:-1])) / (2. * 3456 * 5184)
149
fs_area.append(fsarea)
150
151
# <codecell>
152
153
# Area densities inside and outside the focus
154
in_area_density.append(incount * np.mean(insize) / fsarea)
155
out_area_density.append(outcount * np.mean(outsize) / (1. - fsarea))
156
                        
157
# Point densities inside and outside the focus
158
in_point_density.append(incount / fsarea)
159
out_point_density.append(outcount / (1. - fsarea))
160
161
# <codecell>
162
163
# Variance and CoV of outside the focus
164
mask = np.zeros_like(clean)
165
for c in cent :
166
    mask[int(np.round(c[0])), int(np.round(c[1]))] = 1
167
mask = ndimage.binary_fill_holes(ndimage.maximum_filter(mask, 35))
168
169
areadensity = filter.gaussian_filter(clean, 51)
170
var_area_density.append(np.var(areadensity[mask == 0]))
171
cov_area_density.append(np.std(areadensity[mask == 0] / np.mean(areadensity[mask == 0])))
172
173
pointdensity = np.zeros_like(clean)
174
for n in nuclei :
175
    pointdensity[int(np.round(n.centroid[0])), int(np.round(n.centroid[1]))] = 1
176
pointdensity = filter.gaussian_filter(pointdensity, 51)
177
178
var_point_density.append(np.var(pointdensity[mask == 0]))
179
cov_point_density.append(np.std(pointdensity[mask == 0] / np.mean(pointdensity[mask == 0])))
180
181
# <codecell>
182
183
# Pairwise distances between nuclei outside the focal area 
184
distances = distance.squareform(distance.pdist([n.centroid for n in outer_nuclei]))
185
186
for i in range(len(distances)) :
187
    distances[i, i] = np.inf
188
    
189
pairwise.append(np.min(distances, axis=0).mean())
190
191
# <codecell>
192
193
print in_count
194
print out_count
195
print in_size
196
print out_size
197
print in_area_density
198
print out_area_density
199
print in_point_density
200
print out_point_density
201
print var_point_density
202
print cov_point_density
203
print var_area_density
204
print cov_area_density
205
print fs_area
206