cell-data-loader 0.0.8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
cell_data_loader/util.py
ADDED
|
@@ -0,0 +1,892 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
|
|
3
|
+
import os,sys,json,csv,cv2,glob,random,re
|
|
4
|
+
import numpy as np
|
|
5
|
+
from numpy.random import choice,shuffle
|
|
6
|
+
from math import floor,ceil,sqrt
|
|
7
|
+
from PIL import Image,ImageEnhance
|
|
8
|
+
from scipy import ndimage
|
|
9
|
+
from scipy.ndimage.interpolation import map_coordinates
|
|
10
|
+
from scipy.ndimage.filters import gaussian_filter
|
|
11
|
+
from .base_dataset import BaseDataset
|
|
12
|
+
import torch,torchvision
|
|
13
|
+
from contextlib import contextmanager
|
|
14
|
+
import warnings
|
|
15
|
+
#from random import shuffle
|
|
16
|
+
try:
|
|
17
|
+
from cellpose import models, io
|
|
18
|
+
except:
|
|
19
|
+
warnings.warn("Working Cellpose not installed -- cell segmentation not"+\
|
|
20
|
+
" possible")
|
|
21
|
+
|
|
22
|
+
import skimage
|
|
23
|
+
# DEFINE CELLPOSE MODEL
|
|
24
|
+
|
|
25
|
+
@contextmanager
|
|
26
|
+
def suppress_stdout():
|
|
27
|
+
with open(os.devnull, "w") as devnull:
|
|
28
|
+
old_stdout = sys.stdout
|
|
29
|
+
sys.stdout = devnull
|
|
30
|
+
try:
|
|
31
|
+
yield
|
|
32
|
+
finally:
|
|
33
|
+
sys.stdout = old_stdout
|
|
34
|
+
|
|
35
|
+
# Function to distort image, stolen shamelessly from
|
|
36
|
+
# https://www.kaggle.com/bguberfain/elastic-transform-for-data-augmentation
|
|
37
|
+
def elastic_transform(im, alpha, sigma, alph_af, rand_s=None):
|
|
38
|
+
"""Elastic deformation of images as described in [Simard2003]_
|
|
39
|
+
(with modifications).
|
|
40
|
+
.. [Simard2003] Simard, Steinkraus and Platt, "Best Practices for
|
|
41
|
+
Convolutional Neural Networks applied to Visual Document
|
|
42
|
+
Analysis", in Proc. of the International Conference on
|
|
43
|
+
Document Analysis and Recognition, 2003.
|
|
44
|
+
|
|
45
|
+
Based on https://gist.github.com/erniejunior/601cdf56d2b424757de5
|
|
46
|
+
"""
|
|
47
|
+
if rand_s is None:
|
|
48
|
+
rand_s = np.random.RandomState(None)
|
|
49
|
+
|
|
50
|
+
shape = im.shape
|
|
51
|
+
shape_size = shape[:2]
|
|
52
|
+
|
|
53
|
+
# Random affine
|
|
54
|
+
cent_squ = np.float32(shape_size) // 2
|
|
55
|
+
squ_siz = min(shape_size) // 3
|
|
56
|
+
pts1 = np.float32([cent_squ + squ_siz,
|
|
57
|
+
[cent_squ[0]+squ_siz, cent_squ[1]-squ_siz], cent_squ - squ_siz])
|
|
58
|
+
pts2 = pts1 + rand_s.uniform(-alph_af,
|
|
59
|
+
alph_af, size=pts1.shape).astype(np.float32)
|
|
60
|
+
M = cv2.getAffineTransform(pts1, pts2)
|
|
61
|
+
im = cv2.warpAffine(im, M, shape_size[::-1],
|
|
62
|
+
borderMode=cv2.BORDER_REFLECT_101)
|
|
63
|
+
|
|
64
|
+
dx = gaussian_filter((rand_s.rand(*shape) * 2 - 1), sigma) * alpha
|
|
65
|
+
dy = gaussian_filter((rand_s.rand(*shape) * 2 - 1), sigma) * alpha
|
|
66
|
+
dz = np.zeros_like(dx)
|
|
67
|
+
|
|
68
|
+
x, y, z = np.meshgrid(np.arange(shape[1]),\
|
|
69
|
+
np.arange(shape[0]),\
|
|
70
|
+
np.arange(shape[2]))
|
|
71
|
+
indices = np.reshape(y+dy, (-1, 1)),\
|
|
72
|
+
np.reshape(x+dx, (-1, 1)),\
|
|
73
|
+
np.reshape(z, (-1, 1))
|
|
74
|
+
|
|
75
|
+
return map_coordinates(im,indices,order=1,mode='reflect').reshape(shape)
|
|
76
|
+
|
|
77
|
+
def slice_and_augment(im,x,y,l,w,
|
|
78
|
+
trans = None,
|
|
79
|
+
out_size = None,
|
|
80
|
+
rotation=0,
|
|
81
|
+
x_shift = 0.0,
|
|
82
|
+
y_shift = 0.0,
|
|
83
|
+
size_shift = 0.0):
|
|
84
|
+
"""
|
|
85
|
+
Slices out and augments a particular cell from a larger image, given
|
|
86
|
+
the box coordinates (x,y,l <length>, w <width>). The transformation array
|
|
87
|
+
can be added to augment images as well. The rotation and shifts are applied
|
|
88
|
+
separately since they may need to consider outside images for the corners.
|
|
89
|
+
"""
|
|
90
|
+
if isinstance(im,np.ndarray):
|
|
91
|
+
dtype = "numpy"
|
|
92
|
+
imsize = im.shape
|
|
93
|
+
elif torch.is_tensor(im):
|
|
94
|
+
dtype = "torch"
|
|
95
|
+
imsize = im.size()
|
|
96
|
+
else:
|
|
97
|
+
raise Exception("Unimplemented type in slice_and_augment")
|
|
98
|
+
# Random horizontal and vertical shifts
|
|
99
|
+
x = x + round(max(l,w) * x_shift)
|
|
100
|
+
y = y + round(max(l,w) * y_shift)
|
|
101
|
+
|
|
102
|
+
# Random size shifts
|
|
103
|
+
|
|
104
|
+
y = int(y - 0.5*(size_shift * w))
|
|
105
|
+
x = int(x - 0.5*(size_shift * l))
|
|
106
|
+
l = int(l * (size_shift + 1))
|
|
107
|
+
w = int(w * (size_shift + 1))
|
|
108
|
+
|
|
109
|
+
# Arbitrary, continuous rotations
|
|
110
|
+
e = 2 # sqrt(2)
|
|
111
|
+
lw = max(w,l)
|
|
112
|
+
rr = range(floor((y + 0.5 * w) - e * lw),ceil((y + 0.5 * w) + e * lw))
|
|
113
|
+
rr = [_ % imsize[0] for _ in rr]
|
|
114
|
+
rr2 = range(floor((x + 0.5 * l) - e * lw),ceil((x + 0.5 * l) + e * lw))
|
|
115
|
+
rr2 = [_ % imsize[1] for _ in rr2]
|
|
116
|
+
|
|
117
|
+
if dtype == "torch":
|
|
118
|
+
imslice = torch.index_select(im,0,torch.LongTensor(rr))
|
|
119
|
+
imslice = torch.index_select(imslice,1,torch.LongTensor(rr2))
|
|
120
|
+
elif dtype == "numpy":
|
|
121
|
+
imslice = im.take(rr,axis=0)#,mode='wrap')
|
|
122
|
+
imslice = imslice.take(rr2,axis=1)#,mode='wrap')
|
|
123
|
+
else:
|
|
124
|
+
raise Exception("Unimplemented dtype: %s" % dtype)
|
|
125
|
+
|
|
126
|
+
if dtype == "torch":
|
|
127
|
+
imshap = imslice.size()
|
|
128
|
+
elif dtype == "numpy":
|
|
129
|
+
imshap = imslice.shape
|
|
130
|
+
else:
|
|
131
|
+
raise Exception("Unimplemented dtype: %s" % dtype)
|
|
132
|
+
|
|
133
|
+
if dtype == "torch":
|
|
134
|
+
imslice = torchvision.transforms.functional.rotate(imslice,rotation)
|
|
135
|
+
elif dtype == "numpy":
|
|
136
|
+
imslice = ndimage.rotate(imslice,rotation)
|
|
137
|
+
else:
|
|
138
|
+
raise Exception("Unimplemented dtype: %s" % dtype)
|
|
139
|
+
|
|
140
|
+
# Applies elastic distortion; see above
|
|
141
|
+
rr = range(int(0.5 * imshap[0] - lw/2.0),int(0.5 * imshap[0] + lw/2.0))
|
|
142
|
+
rr = [_ % imshap[0] for _ in rr]
|
|
143
|
+
rr2 = range(int(0.5 * imshap[1] - lw/2.0),int(0.5 * imshap[1] + lw/2.0))
|
|
144
|
+
rr2 = [_ % imshap[1] for _ in rr2]
|
|
145
|
+
|
|
146
|
+
if dtype == "torch":
|
|
147
|
+
imslice = torch.index_select(imslice,0,torch.LongTensor(rr))
|
|
148
|
+
imslice = torch.index_select(imslice,1,torch.LongTensor(rr2))
|
|
149
|
+
elif dtype == "numpy":
|
|
150
|
+
imslice = imslice.take(rr,axis=0)#,mode='wrap')
|
|
151
|
+
imslice = imslice.take(rr2,axis=1)#,mode='wrap')
|
|
152
|
+
|
|
153
|
+
#imslice = Image.fromarray(imslice)
|
|
154
|
+
if trans is not None: imslice = trans(imslice)
|
|
155
|
+
|
|
156
|
+
#imslice = PIL.ImageEnhance.Color(imslice).enhance(color_shift)
|
|
157
|
+
|
|
158
|
+
#increasing the contrast
|
|
159
|
+
#new_image = PIL.ImageEnhance.Contrast(image).enhance(1.2)
|
|
160
|
+
if out_size is not None:
|
|
161
|
+
if dtype == "torch":
|
|
162
|
+
imslice = torch.permute(torchvision.transforms.Resize(
|
|
163
|
+
out_size)(torch.permute(imslice,(2,0,1))),(1,2,0))
|
|
164
|
+
elif dtype == "numpy":
|
|
165
|
+
imslice = cv2.resize(imslice,out_size[::-1])
|
|
166
|
+
return imslice
|
|
167
|
+
|
|
168
|
+
def get_augmented_image(im,x,y,l,w,output_im_size = (70,70),augment = False,
|
|
169
|
+
soft_augment = False,c_shift_amt = 0.05,blur_amt = 0.2,
|
|
170
|
+
spatial_shift_amt = 0.02,elastic_distort = True,size_shift = 0.05,
|
|
171
|
+
rotate=True,reflect=True,js_params = None,contrast = 0.2,brightness=0.2):
|
|
172
|
+
|
|
173
|
+
if js_params is not None:
|
|
174
|
+
for k in js_params:
|
|
175
|
+
p = js_params[k]
|
|
176
|
+
if k == "blur_amt":
|
|
177
|
+
blur_amt = int(p)
|
|
178
|
+
elif k == "spatial_shift_amt":
|
|
179
|
+
spatial_shift_amt = float(p)
|
|
180
|
+
elif k == "elastic_distort":
|
|
181
|
+
elastic_distort = bool(int(p))
|
|
182
|
+
elif k == "rotate":
|
|
183
|
+
rotate = bool(int(p))
|
|
184
|
+
elif k == "reflect":
|
|
185
|
+
reflect = bool(int(p))
|
|
186
|
+
elif k == "c_shift_amt":
|
|
187
|
+
c_shift_amt = bool(int(p))
|
|
188
|
+
elif k == "size_shift":
|
|
189
|
+
size_shift = float(p)
|
|
190
|
+
else:
|
|
191
|
+
raise Exception("Invalid input parameter %s" %k)
|
|
192
|
+
|
|
193
|
+
c_shift_arr = np.random.rand(3,3)
|
|
194
|
+
c_shift_arr = c_shift_arr / np.sum(c_shift_arr,axis=1)
|
|
195
|
+
c_shift_arr = (np.eye(3) * (1-c_shift_amt) + c_shift_arr * c_shift_amt)
|
|
196
|
+
|
|
197
|
+
if augment:
|
|
198
|
+
imslice = slice_and_augment(im,x,y,l,w,
|
|
199
|
+
rotation= 0 if not rotate else 360 * np.random.random(),
|
|
200
|
+
reflection=False if not reflect else choice([True,False]),
|
|
201
|
+
color_shift = c_shift_arr,
|
|
202
|
+
blur = 1 + (0.5 - np.random.random()) * 2 * blur_amt,
|
|
203
|
+
contrast = 1 + (0.5 - np.random.random()) * 2 * contrast,
|
|
204
|
+
brightness = 1 + (0.5 - np.random.random()) * 2 * brightness,
|
|
205
|
+
x_shift = (0.5 - np.random.random()) * 2 *spatial_shift_amt,
|
|
206
|
+
y_shift = (0.5 - np.random.random()) * 2 *spatial_shift_amt,
|
|
207
|
+
size_shift = size_shift * (np.random.rand() - 0.5),
|
|
208
|
+
distort = elastic_distort)
|
|
209
|
+
elif soft_augment:
|
|
210
|
+
imslice = slice_and_augment(im,x,y,l,w,
|
|
211
|
+
rotation= 0 if not rotate else 360 * np.random.random(),
|
|
212
|
+
reflection=False if not reflect else choice([True,False]))
|
|
213
|
+
else:
|
|
214
|
+
imslice = slice_and_augment(im,x,y,l,w)
|
|
215
|
+
if not type(imslice) == Image.Image:
|
|
216
|
+
imslice = Image.fromarray(imslice)
|
|
217
|
+
imslice = imslice.resize((output_im_size[0],output_im_size[1]))
|
|
218
|
+
return imslice
|
|
219
|
+
|
|
220
|
+
def read_image_file(imfile,out_format = "torch"):
|
|
221
|
+
basename,ext = os.path.splitext(imfile)
|
|
222
|
+
if ext.lower() == ".jpg":
|
|
223
|
+
return
|
|
224
|
+
elif ext.lower() == ".cz":
|
|
225
|
+
return
|
|
226
|
+
elif ext.lower() == ".svz":
|
|
227
|
+
return
|
|
228
|
+
return
|
|
229
|
+
|
|
230
|
+
def read_label_file(label_file):
|
|
231
|
+
return
|
|
232
|
+
|
|
233
|
+
def is_image_file(filename):
|
|
234
|
+
basename,ext = os.path.splitext(filename)
|
|
235
|
+
return ext.lower() in [".jpg",".png",".jpeg",".czi",".svs",".tiff",".tif"]
|
|
236
|
+
|
|
237
|
+
def is_label_file(filename):
|
|
238
|
+
return True
|
|
239
|
+
|
|
240
|
+
def get_verify(X,Y):
|
|
241
|
+
h = int(X.shape[1] / 2)
|
|
242
|
+
w = int(X.shape[2] / 2)
|
|
243
|
+
q1 = np.expand_dims(np.mean(X[:,:h,:w,:],axis=(1,2,3)),axis=1) / 255.0
|
|
244
|
+
q2 = np.expand_dims(np.mean(X[:,h:,:w,:],axis=(1,2,3)),axis=1) / 255.0
|
|
245
|
+
q3 = np.expand_dims(np.mean(X[:,:h,w:,:],axis=(1,2,3)),axis=1) / 255.0
|
|
246
|
+
q4 = np.expand_dims(np.mean(X[:,h:,w:,:],axis=(1,2,3)),axis=1) / 255.0
|
|
247
|
+
c1 = np.expand_dims(np.mean(X[:,:,:,0],axis=(1,2)),axis=1) / 255.0
|
|
248
|
+
c2 = np.expand_dims(np.mean(X[:,:,:,1],axis=(1,2)),axis=1) / 255.0
|
|
249
|
+
c3 = np.expand_dims(np.mean(X[:,:,:,2],axis=(1,2)),axis=1) / 255.0
|
|
250
|
+
s = np.expand_dims(np.std(X,axis=(1,2,3)),axis=1) / 255.0
|
|
251
|
+
Y_ = np.concatenate((Y,q1,q2,q3,q4,c1,c2,c3,s),axis=1)
|
|
252
|
+
|
|
253
|
+
return Y_
|
|
254
|
+
|
|
255
|
+
def tile_image(im,autoencoder,a_dims=(600,600)):
|
|
256
|
+
for i in range(0,im.shape[0],a_dims[0]):
|
|
257
|
+
for j in range(0,im.shape[1],a_dims[1]):
|
|
258
|
+
if i+a_dims[0] > im.shape[0]:
|
|
259
|
+
i = im.shape[0] - a_dims[0] - 1
|
|
260
|
+
if j+a_dims[1] > im.shape[1]:
|
|
261
|
+
j = im.shape[1] - a_dims[1] - 1
|
|
262
|
+
input_im = torch.from_numpy(im[i:i+a_dims[0],
|
|
263
|
+
j:j+a_dims[1],:]).permute(2,1,0).unsqueeze(0).float()/255.0
|
|
264
|
+
input_im = autoencoder(input_im)
|
|
265
|
+
input_im = input_im.squeeze().permute(1,2,0).detach().numpy() * 255.0
|
|
266
|
+
im[i:i+a_dims[0],j:j+a_dims[1],:] = input_im
|
|
267
|
+
return im
|
|
268
|
+
|
|
269
|
+
def get_all_perimeters(mask):
|
|
270
|
+
perims = {}
|
|
271
|
+
if len(mask.shape) == 2:
|
|
272
|
+
for i in np.unique(mask.flatten()):
|
|
273
|
+
perims[i] = 0
|
|
274
|
+
for i in range(mask.shape[0]-1):
|
|
275
|
+
for j in range(mask.shape[1]-1):
|
|
276
|
+
if mask[i,j] != mask[i+1,j]:
|
|
277
|
+
perims[mask[i,j]] += 1
|
|
278
|
+
perims[mask[i+1,j]] += 1
|
|
279
|
+
if mask[i,j] != mask[i,j+1]:
|
|
280
|
+
perims[mask[i,j]] += 1
|
|
281
|
+
perims[mask[i,j+1]] += 1
|
|
282
|
+
elif len(mask.shape) == 3:
|
|
283
|
+
for i in range(mask.shape[2]):
|
|
284
|
+
perims[i] = 0
|
|
285
|
+
return perims
|
|
286
|
+
|
|
287
|
+
def get_perimeter(mask):
|
|
288
|
+
p = 0
|
|
289
|
+
for i in range(mask.shape[0]-1):
|
|
290
|
+
for j in range(mask.shape[1]-1):
|
|
291
|
+
if mask[i,j] != mask[i+1,j]:
|
|
292
|
+
p += 1
|
|
293
|
+
if mask[i,j] != mask[i,j+1]:
|
|
294
|
+
p += 1
|
|
295
|
+
return p
|
|
296
|
+
|
|
297
|
+
def get_smoothness(mask,mean_area = None):
|
|
298
|
+
area = np.sum(mask)
|
|
299
|
+
#return np.abs(area - mean_area)
|
|
300
|
+
return float(skimage.measure.perimeter(mask,neighbourhood=4) ** 2)/area
|
|
301
|
+
|
|
302
|
+
def crop2(dat, clp=True):
|
|
303
|
+
if clp: np.clip( dat, 0, 1, out=dat )
|
|
304
|
+
for i in range(dat.ndim):
|
|
305
|
+
dat = np.swapaxes(dat, 0, i) # send i-th axis to front
|
|
306
|
+
while np.all( dat[0]==0 ):
|
|
307
|
+
dat = dat[1:]
|
|
308
|
+
while np.all( dat[-1]==0 ):
|
|
309
|
+
dat = dat[:-1]
|
|
310
|
+
dat = np.swapaxes(dat, 0, i) # send i-th axis to its original position
|
|
311
|
+
return dat
|
|
312
|
+
|
|
313
|
+
def remove_unsmooth(mask,thresh=25):
|
|
314
|
+
smoothnesses = np.zeros((len(np.unique(mask))-1,))
|
|
315
|
+
if len(mask.shape) == 2:
|
|
316
|
+
for z in np.unique(mask.flatten()):
|
|
317
|
+
if z > 0:
|
|
318
|
+
z_mask = crop2(mask == z)
|
|
319
|
+
smoothnesses[int(z)-1] = get_smoothness(z_mask)
|
|
320
|
+
elif len(mask.shape) == 3:
|
|
321
|
+
for z in range(mask.shape[2]):
|
|
322
|
+
smoothnesses[z] = get_smoothness(crop2(np.squeeze(mask[:,:,z])))
|
|
323
|
+
max_smoothness = smoothnesses.max()
|
|
324
|
+
min_smoothness = smoothnesses.min()
|
|
325
|
+
for i in range(mask.max()):
|
|
326
|
+
if smoothnesses[i] > thresh:
|
|
327
|
+
mask[mask == i+1] = 0
|
|
328
|
+
mask = renumber_masks(mask)
|
|
329
|
+
return mask
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
def get_box_intersection_area(bb1,bb2):
|
|
333
|
+
"""
|
|
334
|
+
Calculate the Intersection over Union (IoU) of two bounding boxes.
|
|
335
|
+
|
|
336
|
+
Parameters
|
|
337
|
+
----------
|
|
338
|
+
bb1 : dict
|
|
339
|
+
Keys: {'x1', 'x2', 'y1', 'y2'}
|
|
340
|
+
The (x1, y1) position is at the top left corner,
|
|
341
|
+
the (x2, y2) position is at the bottom right corner
|
|
342
|
+
bb2 : dict
|
|
343
|
+
Keys: {'x1', 'x2', 'y1', 'y2'}
|
|
344
|
+
The (x, y) position is at the top left corner,
|
|
345
|
+
the (x2, y2) position is at the bottom right corner
|
|
346
|
+
|
|
347
|
+
Returns
|
|
348
|
+
-------
|
|
349
|
+
float
|
|
350
|
+
in [0, 1]
|
|
351
|
+
-----
|
|
352
|
+
Adapted from https://stackoverflow.com/questions/25349178/
|
|
353
|
+
calculating-percentage-of-bounding-box-overlap-for-image-detector-evaluation
|
|
354
|
+
"""
|
|
355
|
+
# determine the coordinates of the intersection rectangle
|
|
356
|
+
bb1_x1 = bb1[1]
|
|
357
|
+
bb1_x2 = bb1[1] + bb1[3]
|
|
358
|
+
bb1_y1 = bb1[0]
|
|
359
|
+
bb1_y2 = bb1[0] + bb1[2]
|
|
360
|
+
|
|
361
|
+
bb2_x1 = bb2[1]
|
|
362
|
+
bb2_x2 = bb2[1] + bb2[3]
|
|
363
|
+
bb2_y1 = bb2[0]
|
|
364
|
+
bb2_y2 = bb2[0] + bb2[2]
|
|
365
|
+
|
|
366
|
+
x_left = max(bb1_x1, bb2_x1)
|
|
367
|
+
y_top = max(bb1_y1, bb2_y1)
|
|
368
|
+
x_right = min(bb1_x2, bb2_x2)
|
|
369
|
+
y_bottom = min(bb1_y2, bb2_y2)
|
|
370
|
+
|
|
371
|
+
if x_right < x_left or y_bottom < y_top:
|
|
372
|
+
return 0.0
|
|
373
|
+
|
|
374
|
+
# The intersection of two axis-aligned bounding boxes is always an
|
|
375
|
+
# axis-aligned bounding box
|
|
376
|
+
intersection_area = (x_right - x_left) * (y_bottom - y_top)
|
|
377
|
+
|
|
378
|
+
# compute the area of both AABBs
|
|
379
|
+
bb1_area = bb1[3] * bb1[2]
|
|
380
|
+
bb2_area = bb2[3] * bb2[2]
|
|
381
|
+
|
|
382
|
+
# compute the intersection over union by taking the intersection
|
|
383
|
+
# area and dividing it by the sum of prediction + ground-truth
|
|
384
|
+
# areas - the interesection area
|
|
385
|
+
iou = intersection_area / float(bb1_area + bb2_area - intersection_area)
|
|
386
|
+
assert iou >= 0.0
|
|
387
|
+
assert iou <= 1.0
|
|
388
|
+
return iou
|
|
389
|
+
|
|
390
|
+
def find_box_intersections(annotated_boxes,predicted_boxes,min_dice=0.5):
|
|
391
|
+
assert(min_dice >= 0.0)
|
|
392
|
+
assert(min_dice <= 1.0)
|
|
393
|
+
final_boxes = []
|
|
394
|
+
for i in range(predicted_boxes.shape[0]):
|
|
395
|
+
append = True
|
|
396
|
+
for j in range(annotated_boxes.shape[0]):
|
|
397
|
+
bb1 = predicted_boxes[i,:]
|
|
398
|
+
bb2 = annotated_boxes[j,:]
|
|
399
|
+
dice = get_box_intersection_area(bb1,bb2)
|
|
400
|
+
if dice > min_dice:
|
|
401
|
+
append = False
|
|
402
|
+
if append:
|
|
403
|
+
final_boxes.append(predicted_boxes[i,:])
|
|
404
|
+
return np.array(final_boxes)
|
|
405
|
+
|
|
406
|
+
def merge_predicted_and_annotated(annotated_boxes,predicted_boxes,min_dice=0.5):
|
|
407
|
+
intersected_boxes = find_box_intersections(annotated_boxes,predicted_boxes,
|
|
408
|
+
min_dice=min_dice)
|
|
409
|
+
if intersected_boxes.shape[1] == 4:
|
|
410
|
+
neg_labels = np.array(["negative" for _ in range(intersected_boxes.shape[0])])
|
|
411
|
+
neg_labels = np.expand_dims(neg_labels,axis=1)
|
|
412
|
+
neg_labels = neg_labels.astype(object)
|
|
413
|
+
intersected_boxes = intersected_boxes.astype(object)
|
|
414
|
+
intersected_boxes = np.concatenate((intersected_boxes,neg_labels),axis=1)
|
|
415
|
+
return np.concatenate((annotated_boxes,intersected_boxes),axis=0)
|
|
416
|
+
|
|
417
|
+
def get_average_mask_size(mask):
|
|
418
|
+
return np.sum(mask.flatten() > 0) / mask.max()
|
|
419
|
+
|
|
420
|
+
def renumber_masks(mask):
|
|
421
|
+
unique_m = np.sort(np.unique(mask))
|
|
422
|
+
assert(unique_m[0] == 0)
|
|
423
|
+
if unique_m[-1] == len(unique_m) - 1:
|
|
424
|
+
return mask
|
|
425
|
+
for i in range(1,len(unique_m)):
|
|
426
|
+
mask[mask == unique_m[i]] = i
|
|
427
|
+
return mask
|
|
428
|
+
|
|
429
|
+
def remove_edges(mask,min_edge_size=0.5):
|
|
430
|
+
avg_mask_size = get_average_mask_size(mask)
|
|
431
|
+
exclude_i = {}
|
|
432
|
+
for i in range(mask.shape[0]):
|
|
433
|
+
for j in [0,-1]:
|
|
434
|
+
val = mask[i,j]
|
|
435
|
+
if val > 0 and val not in exclude_i:
|
|
436
|
+
exclude_i[val] = True
|
|
437
|
+
if np.sum(mask.flatten() == val) < min_edge_size * avg_mask_size:
|
|
438
|
+
mask[mask == val] = 0
|
|
439
|
+
for i in range(mask.shape[1]):
|
|
440
|
+
for j in [0,-1]:
|
|
441
|
+
val = mask[j,i]
|
|
442
|
+
if val > 0 and val not in exclude_i:
|
|
443
|
+
exclude_i[val] = True
|
|
444
|
+
if np.sum(mask.flatten() == val) < min_edge_size * avg_mask_size:
|
|
445
|
+
mask[mask == val] = 0
|
|
446
|
+
mask = renumber_masks(mask)
|
|
447
|
+
return mask
|
|
448
|
+
|
|
449
|
+
def remove_smalls(mask,avg_fraction_thresh = 0.5):
|
|
450
|
+
avg_mask_size = get_average_mask_size(mask)
|
|
451
|
+
for i in range(1,mask.max() + 1):
|
|
452
|
+
area = np.sum(mask == i)
|
|
453
|
+
if area < avg_fraction_thresh * avg_mask_size:
|
|
454
|
+
mask[mask == i] = 0
|
|
455
|
+
mask = renumber_masks(mask)
|
|
456
|
+
return mask
|
|
457
|
+
|
|
458
|
+
def masks_to_boxes(masks):
|
|
459
|
+
if len(masks.shape) == 2:
|
|
460
|
+
num_masks = len(np.unique(masks)) - 1
|
|
461
|
+
elif len(masks.shape) == 3:
|
|
462
|
+
num_masks = masks.shape[2]
|
|
463
|
+
else:
|
|
464
|
+
raise Exception("Invalid mask length: %d" % len(masks.shape))
|
|
465
|
+
boxes = np.zeros((num_masks,4),dtype=int)
|
|
466
|
+
for i in range(num_masks):
|
|
467
|
+
if len(masks.shape) == 2:
|
|
468
|
+
y_bar = np.max(masks == i+1,axis=0)
|
|
469
|
+
x_bar = np.max(masks == i+1,axis=1)
|
|
470
|
+
elif len(masks.shape) == 3:
|
|
471
|
+
m = np.squeeze(masks[:,:,i])
|
|
472
|
+
y_bar = np.max(m,axis=0)
|
|
473
|
+
x_bar = np.max(m,axis=1)
|
|
474
|
+
x_min = np.argmax(x_bar)
|
|
475
|
+
y_min = np.argmax(y_bar)
|
|
476
|
+
x_max = len(x_bar) - np.argmax(x_bar[::-1]) - 1
|
|
477
|
+
y_max = len(y_bar) - np.argmax(y_bar[::-1]) - 1
|
|
478
|
+
boxes[i,0] = y_min
|
|
479
|
+
boxes[i,1] = x_min
|
|
480
|
+
boxes[i,2] = y_max - y_min
|
|
481
|
+
boxes[i,3] = x_max - x_min
|
|
482
|
+
if i == 1 and False:
|
|
483
|
+
print(boxes[i,:])
|
|
484
|
+
return boxes
|
|
485
|
+
|
|
486
|
+
def get_im(im):
|
|
487
|
+
if isinstance(im,str) and os.path.isfile(im):
|
|
488
|
+
return np.array(Image.open(im))
|
|
489
|
+
elif torch.is_tensor(im):
|
|
490
|
+
return im.numpy()
|
|
491
|
+
elif isinstance(im,np.ndarray):
|
|
492
|
+
return im
|
|
493
|
+
else:
|
|
494
|
+
raise Exception("Unsupported type %s" % str(type(im)))
|
|
495
|
+
|
|
496
|
+
def get_cell_segmentation_mask(imagename,model = None, modelname = "cellpose",gpu=True):
|
|
497
|
+
if isinstance(imagename,str):
|
|
498
|
+
save_mask_name = "%s_mask.npy" % os.path.splitext(imagename)[0]
|
|
499
|
+
if os.path.isfile(save_mask_name):
|
|
500
|
+
print("Loading mask %s" % save_mask_name)
|
|
501
|
+
return np.load(save_mask_name)
|
|
502
|
+
img = get_im(imagename)#img = io.imread(imagename)
|
|
503
|
+
if model == None:
|
|
504
|
+
if modelname == "cellpose":
|
|
505
|
+
try:
|
|
506
|
+
model = models.Cellpose(gpu=gpu, model_type='cyto')
|
|
507
|
+
except:
|
|
508
|
+
raise Exception("""Attempt to instantiate cellpose model
|
|
509
|
+
did not work. Please check cellpose dependency""")
|
|
510
|
+
if modelname == "cellpose":
|
|
511
|
+
try:
|
|
512
|
+
masks, flows, styles, diams = model.eval(img, diameter=None,channels=[0,0])
|
|
513
|
+
except RuntimeError:
|
|
514
|
+
model = models.Cellpose(gpu=False, model_type='cyto')
|
|
515
|
+
masks, flows, styles, diams = model.eval(img, diameter=None,channels=[0,0])
|
|
516
|
+
elif modelname == "deepcell":
|
|
517
|
+
model = CytoplasmSegmentation()
|
|
518
|
+
masks = model.predict(img, image_mpp=0.65)
|
|
519
|
+
if isinstance(imagename,str):
|
|
520
|
+
print("Saving mask %s" % save_mask_name)
|
|
521
|
+
np.save(save_mask_name,masks)
|
|
522
|
+
return masks
|
|
523
|
+
|
|
524
|
+
|
|
525
|
+
def get_touch_matrix(unique_vals,mask):
|
|
526
|
+
unique_vals = list(unique_vals)
|
|
527
|
+
touch_matrix = np.zeros((len(unique_vals),len(unique_vals))).astype(bool)
|
|
528
|
+
for i in range(touch_matrix.shape[0]-1):
|
|
529
|
+
for j in range(touch_matrix.shape[1]-1):
|
|
530
|
+
if i == j:
|
|
531
|
+
touch_matrix[i,j] = True
|
|
532
|
+
touch_matrix[i+1,j+1] = True
|
|
533
|
+
if mask[i,j] > 0:
|
|
534
|
+
u1 = unique_vals.index(mask[i,j])
|
|
535
|
+
for k in [(i,j+1),(i+1,j),(i+1,j+1)]:
|
|
536
|
+
if mask[k[0],k[1]] > 0:
|
|
537
|
+
u2 = unique_vals.index(mask[k[0],k[1]])
|
|
538
|
+
touch_matrix[u1,u2] = True
|
|
539
|
+
touch_matrix[u2,u1] = True
|
|
540
|
+
return touch_matrix
|
|
541
|
+
|
|
542
|
+
def get_all_combos(l,include=None):
|
|
543
|
+
if include is not None:
|
|
544
|
+
l2 = list(l.copy())
|
|
545
|
+
l2.remove(include)
|
|
546
|
+
l = np.array(l2)
|
|
547
|
+
all_combinations = []
|
|
548
|
+
for r in [0,1]:#range(len(l) + 1):
|
|
549
|
+
combinations_object = itertools.combinations(l, r)
|
|
550
|
+
combinations_list = [cc for cc in list(combinations_object)]
|
|
551
|
+
all_combinations += combinations_list
|
|
552
|
+
if include is not None:
|
|
553
|
+
all_combinations = [list(l) + [include] for l in all_combinations]
|
|
554
|
+
return all_combinations
|
|
555
|
+
|
|
556
|
+
def do_function(mask,mean_area=None):
|
|
557
|
+
unique_vals = np.unique(mask)
|
|
558
|
+
unique_vals_list = list(unique_vals)
|
|
559
|
+
if 0 in unique_vals_list:
|
|
560
|
+
unique_vals_list.remove(0)
|
|
561
|
+
else:
|
|
562
|
+
print("0 not in unique vals")
|
|
563
|
+
unique_vals = np.array(unique_vals_list)
|
|
564
|
+
if len(unique_vals) > 10:
|
|
565
|
+
tm = get_touch_matrix(unique_vals_list,mask)
|
|
566
|
+
else:
|
|
567
|
+
tm = None
|
|
568
|
+
island_mapping = {}
|
|
569
|
+
for u in unique_vals:
|
|
570
|
+
if tm is None:
|
|
571
|
+
all_combo_w_u = get_all_combos(unique_vals,include=u)
|
|
572
|
+
else:
|
|
573
|
+
#print(tm)
|
|
574
|
+
#print(tm[:,unique_vals_list.index(u)].astype(bool))
|
|
575
|
+
#print(unique_vals)
|
|
576
|
+
assert(len(unique_vals) == tm.shape[0])
|
|
577
|
+
combolist = unique_vals[tm[:,unique_vals_list.index(u)]]
|
|
578
|
+
#print(combolist)
|
|
579
|
+
if len(combolist) == 1:
|
|
580
|
+
all_combo_w_u = [[u]]
|
|
581
|
+
else:
|
|
582
|
+
all_combo_w_u = get_all_combos(combolist,include=u)
|
|
583
|
+
print(all_combo_w_u)
|
|
584
|
+
for c in all_combo_w_u:
|
|
585
|
+
smoothness = get_smoothness(mask,c,mean_area=mean_area)
|
|
586
|
+
if u not in island_mapping or island_mapping[u][1] > smoothness:
|
|
587
|
+
island_mapping[u] = (c,smoothness)
|
|
588
|
+
ims = [island_mapping[u][0] for u in island_mapping]
|
|
589
|
+
print("len(ims) %d" % len(ims))
|
|
590
|
+
ims_nodups = []
|
|
591
|
+
lolx = {}
|
|
592
|
+
for im in ims:
|
|
593
|
+
i_sort = sorted(im)
|
|
594
|
+
ss = str(i_sort)
|
|
595
|
+
if ss not in lolx:
|
|
596
|
+
lolx[ss] = True
|
|
597
|
+
ims_nodups.append(i_sort)
|
|
598
|
+
print(ims_nodups)
|
|
599
|
+
return ims_nodups
|
|
600
|
+
|
|
601
|
+
def resolve_intersections(masks):
|
|
602
|
+
mean_area = np.mean([np.sum(masks == i) for i in range(1,masks.max()+1)])
|
|
603
|
+
labeled_array, num_features = ndimage.label(masks != 0, np.ones((3,3)))
|
|
604
|
+
all_pairs = []
|
|
605
|
+
for i in np.unique(labeled_array):
|
|
606
|
+
mask_copy = masks.copy()
|
|
607
|
+
mask_copy[labeled_array != i] = 0
|
|
608
|
+
mask_copy = mask_copy[~np.all(mask_copy == 0,axis=1),:]
|
|
609
|
+
mask_copy = mask_copy[:,~np.all(mask_copy == 0,axis=0)]
|
|
610
|
+
print(mask_copy)
|
|
611
|
+
pairs = do_function(mask_copy,mean_area=mean_area)
|
|
612
|
+
all_pairs += pairs
|
|
613
|
+
masks_3D = np.zeros((masks.shape[0],masks.shape[1],len(all_pairs))).astype(bool)
|
|
614
|
+
print("masks_3D.shape: %s"%str(masks_3D.shape))
|
|
615
|
+
print("all_pairs len %d" % len(all_pairs))
|
|
616
|
+
for i in range(len(all_pairs)):
|
|
617
|
+
pair = all_pairs[i]
|
|
618
|
+
for p in pair:
|
|
619
|
+
masks_3D[:,:,i] = np.logical_or(masks_3D[:,:,i],masks == p)
|
|
620
|
+
print("masks_3D.shape: %s"%str(masks_3D.shape))
|
|
621
|
+
return masks_3D
|
|
622
|
+
|
|
623
|
+
def get_cell_boxes_from_image(imagename,model=None,gpu=True,
|
|
624
|
+
remove_edge_cells=True,return_model=False,verbose=False,
|
|
625
|
+
do_resolve_intersections=False,do_remove_smalls = True,
|
|
626
|
+
do_remove_unsmooth=False):
|
|
627
|
+
#temp = "temp.npy"
|
|
628
|
+
#if not os.path.isfile(temp) and False:
|
|
629
|
+
if verbose:
|
|
630
|
+
masks = get_cell_segmentation_mask(imagename,gpu=gpu,model=model)
|
|
631
|
+
else:
|
|
632
|
+
with suppress_stdout():
|
|
633
|
+
masks = get_cell_segmentation_mask(imagename,gpu=gpu,model=model)
|
|
634
|
+
if remove_edge_cells:
|
|
635
|
+
max_m = masks.max()
|
|
636
|
+
masks = remove_edges(masks,min_edge_size=np.inf)
|
|
637
|
+
if verbose: print("Removing %d cells from edges" % (max_m - masks.max()))
|
|
638
|
+
# np.save(temp,masks)
|
|
639
|
+
#else:
|
|
640
|
+
# masks = np.load(temp)
|
|
641
|
+
if do_remove_smalls:
|
|
642
|
+
masks = remove_smalls(masks)
|
|
643
|
+
# This gave some errors
|
|
644
|
+
#if do_remove_unsmooth:
|
|
645
|
+
# masks = remove_unsmooth(masks)
|
|
646
|
+
if do_resolve_intersections:
|
|
647
|
+
print("masks.shape: %s" % str(masks.shape))
|
|
648
|
+
print("unique_vals len - 1: %d" % (len(np.unique(masks))-1))
|
|
649
|
+
masks = resolve_intersections(masks)
|
|
650
|
+
boxes = masks_to_boxes(masks)
|
|
651
|
+
if return_model:
|
|
652
|
+
return boxes,masks,model
|
|
653
|
+
else:
|
|
654
|
+
return boxes,masks
|
|
655
|
+
|
|
656
|
+
def get_image_array(imagename,boxes,output_size = (64,64),
|
|
657
|
+
whole_im_autoencoder=None):
|
|
658
|
+
image = get_im(imagename)#np.array(Image.open(imagename))
|
|
659
|
+
if whole_im_autoencoder is not None:
|
|
660
|
+
image = tile_image(image,whole_im_autoencoder)
|
|
661
|
+
X = np.zeros((boxes.shape[0],output_size[0],output_size[1],3))
|
|
662
|
+
for i in range(boxes.shape[0]):
|
|
663
|
+
x = boxes[i,0]
|
|
664
|
+
y = boxes[i,1]
|
|
665
|
+
l = boxes[i,2]
|
|
666
|
+
w = boxes[i,3]
|
|
667
|
+
imslice = slice_and_augment(image,x,y,l,w)
|
|
668
|
+
if not type(imslice) == Image.Image:
|
|
669
|
+
imslice = Image.fromarray(imslice)
|
|
670
|
+
imslice = imslice.resize(output_size)
|
|
671
|
+
imarr = np.expand_dims(np.array(imslice),axis=0)
|
|
672
|
+
X[i,:,:,:] = imarr
|
|
673
|
+
return X
|
|
674
|
+
|
|
675
|
+
def get_predicted_labels(imagename,single_cell_pred_model_filepath='.',
|
|
676
|
+
gpu=True,remove_edge_cells = True,verbose=True,single_cell_pred_model=None,
|
|
677
|
+
lb=None,segmodel=None,just_segment = False,autoencoder=None,whole_im_autoencoder=None,
|
|
678
|
+
use_get_verify = False,num_dropout_tests = 1):
|
|
679
|
+
if not just_segment and single_cell_pred_model is None and lb is None:
|
|
680
|
+
single_cell_pred_model,lb = \
|
|
681
|
+
load_model_w_label_processor(output_folder = \
|
|
682
|
+
single_cell_pred_model_filepath,get_lb=True)
|
|
683
|
+
boxes,masks = get_cell_boxes_from_image(imagename,gpu=gpu,model=segmodel)
|
|
684
|
+
if just_segment:
|
|
685
|
+
return None,masks
|
|
686
|
+
X = get_image_array(imagename,boxes,whole_im_autoencoder=whole_im_autoencoder)
|
|
687
|
+
if autoencoder is not None:
|
|
688
|
+
X = autoencoder(X)
|
|
689
|
+
X = X - X.min()
|
|
690
|
+
X = X / X.max()
|
|
691
|
+
X = X * 255.0
|
|
692
|
+
if num_dropout_tests == 1:
|
|
693
|
+
Y = single_cell_pred_model.predict(X,batch_size=1)
|
|
694
|
+
else:
|
|
695
|
+
for layer in single_cell_pred_model.layers:
|
|
696
|
+
if "dropout" not in layer.name.lower():
|
|
697
|
+
layer.trainable = False
|
|
698
|
+
Y_many = np.array(
|
|
699
|
+
[single_cell_pred_model(X,training=True) for _ in range(num_dropout_tests)]
|
|
700
|
+
)
|
|
701
|
+
print(np.std(Y_many,axis=0))
|
|
702
|
+
Y = np.mean(Y_many,axis=0)
|
|
703
|
+
Ym = np.argmax(Y[:,:len(lb.classes_)],axis=1)
|
|
704
|
+
Y_uncertain = np.zeros((Y.shape[0]))
|
|
705
|
+
for i in range(Y.shape[0]):
|
|
706
|
+
if np.all(Y[i,:] > 0.0):
|
|
707
|
+
Y_uncertain[i] = 1
|
|
708
|
+
#assert(len(np.unique(Ym)) == 2)
|
|
709
|
+
assert(len(np.unique(masks)) == masks.max() + 1)
|
|
710
|
+
assert(masks.max() == len(Ym))
|
|
711
|
+
Ym = np.expand_dims(Ym,axis=1)
|
|
712
|
+
Yl = lb.inverse_transform(Ym)
|
|
713
|
+
Yl=np.expand_dims(Yl,axis=1)
|
|
714
|
+
for i in range(len(Ym)):
|
|
715
|
+
if Y_uncertain[i] == 1:
|
|
716
|
+
Yl[i] = "uncertain"
|
|
717
|
+
masks[masks == i + 1] = -1
|
|
718
|
+
else:
|
|
719
|
+
masks[masks == i + 1] = Ym[i] + 1
|
|
720
|
+
if not use_get_verify:
|
|
721
|
+
return np.concatenate((boxes,Yl,Y[:,:len(lb.classes_)]),axis=1),masks
|
|
722
|
+
else:
|
|
723
|
+
Y = get_verify(X,Y[:,:len(lb.classes_) + 8])
|
|
724
|
+
return np.concatenate((boxes,Yl,Y),axis=1),masks
|
|
725
|
+
|
|
726
|
+
def read_in_csv(labels):
|
|
727
|
+
if isinstance(labels,str) and os.path.isfile(labels):
|
|
728
|
+
foo = []
|
|
729
|
+
with open(labels,'r') as fileobj:
|
|
730
|
+
csvreader = csv.reader(fileobj)
|
|
731
|
+
for row in csvreader:
|
|
732
|
+
foo.append(row)
|
|
733
|
+
labels = foo
|
|
734
|
+
return labels
|
|
735
|
+
|
|
736
|
+
def get_classification_percent(labels,class_labels,get_total=False):
|
|
737
|
+
results = {}
|
|
738
|
+
total = 0
|
|
739
|
+
labels = read_in_csv(labels)
|
|
740
|
+
assert isinstance(labels,list)
|
|
741
|
+
for c in class_labels:
|
|
742
|
+
results[c] = 0
|
|
743
|
+
for row in labels:
|
|
744
|
+
total += 1
|
|
745
|
+
l = row[4]
|
|
746
|
+
results[l] += 1
|
|
747
|
+
#if results["ring"] > 20: results["ring"] = 0
|
|
748
|
+
if total == 0:
|
|
749
|
+
return results
|
|
750
|
+
if not get_total:
|
|
751
|
+
for r in results:
|
|
752
|
+
results[r] = results[r] / total
|
|
753
|
+
return results
|
|
754
|
+
|
|
755
|
+
def segment_folder(folderpath,modelpath='.',random_sample=None,
|
|
756
|
+
output_folderpath = None,model=None,lb=None,segmodel=None,autoencoder=None,
|
|
757
|
+
whole_im_autoencoder=None,skip_if_present=False,shuffle_order=False):
|
|
758
|
+
if output_folderpath == None:
|
|
759
|
+
output_folderpath = folderpath
|
|
760
|
+
imagenames = glob.glob(os.path.join(folderpath,'*.jpg'))
|
|
761
|
+
if random_sample is not None:
|
|
762
|
+
assert(isinstance(random_sample,int) and random_sample > 0)
|
|
763
|
+
imagenames = list(imagenames)
|
|
764
|
+
if shuffle_order:shuffle(imagenames)
|
|
765
|
+
imagenames = imagenames[:random_sample]
|
|
766
|
+
if not os.path.isdir(output_folderpath):
|
|
767
|
+
os.makedirs(output_folderpath)
|
|
768
|
+
for imagename in imagenames:
|
|
769
|
+
basename = os.path.splitext(os.path.basename(imagename))[0]
|
|
770
|
+
npy_save = os.path.join(output_folderpath,'%s_predicted.npy'%basename)
|
|
771
|
+
csv_save = os.path.join(output_folderpath,'%s_predicted.csv'%basename)
|
|
772
|
+
if os.path.isfile(npy_save) or os.path.isfile(csv_save) \
|
|
773
|
+
and skip_if_present:
|
|
774
|
+
continue
|
|
775
|
+
labels,masks = get_predicted_labels(imagename,
|
|
776
|
+
gpu=True,
|
|
777
|
+
single_cell_pred_model_filepath=modelpath,
|
|
778
|
+
single_cell_pred_model=model,
|
|
779
|
+
lb=lb,
|
|
780
|
+
segmodel=None,
|
|
781
|
+
autoencoder=autoencoder,
|
|
782
|
+
whole_im_autoencoder=whole_im_autoencoder,
|
|
783
|
+
use_get_verify = True,num_dropout_tests = 10)
|
|
784
|
+
#np.save(npy_save,masks)
|
|
785
|
+
try:
|
|
786
|
+
np.savetxt(csv_save,labels,delimiter=",",fmt='%s')
|
|
787
|
+
except:
|
|
788
|
+
print("Couldn't save the labels")
|
|
789
|
+
|
|
790
|
+
def get_labelnames_set(label_csv):
|
|
791
|
+
ll = read_in_csv(label_csv)
|
|
792
|
+
foo = []
|
|
793
|
+
for row in ll:
|
|
794
|
+
foo.append(row[4])
|
|
795
|
+
return set(foo)
|
|
796
|
+
|
|
797
|
+
def get_folder_classification(folderpath,get_total=False,get_everything = False):
|
|
798
|
+
labelnames = glob.glob(os.path.join(folderpath,'*.csv'))
|
|
799
|
+
class_labels = set([])
|
|
800
|
+
for labelname in labelnames:
|
|
801
|
+
class_labels = class_labels.union(get_labelnames_set(labelname))
|
|
802
|
+
class_labels = sorted(list(class_labels))
|
|
803
|
+
all_results = {}
|
|
804
|
+
for labelname in labelnames:
|
|
805
|
+
result = get_classification_percent(labelname,class_labels,
|
|
806
|
+
get_total=get_total)
|
|
807
|
+
if True:#result["ring"] < 16:
|
|
808
|
+
for r in result:
|
|
809
|
+
if r not in all_results:
|
|
810
|
+
all_results[r] = []
|
|
811
|
+
all_results[r].append(result[r])
|
|
812
|
+
if get_total and get_everything:
|
|
813
|
+
return all_results
|
|
814
|
+
for r in all_results:
|
|
815
|
+
all_results[r] = float(np.mean(all_results[r]))
|
|
816
|
+
return all_results
|
|
817
|
+
|
|
818
|
+
|
|
819
|
+
def get_file_list_from_str(obj):
|
|
820
|
+
assert(isinstance(obj, str))
|
|
821
|
+
if os.path.isfile(obj):
|
|
822
|
+
if is_image_file(obj):
|
|
823
|
+
return [obj]
|
|
824
|
+
else:
|
|
825
|
+
return []
|
|
826
|
+
elif os.path.isdir(obj):
|
|
827
|
+
all_filename_list = []
|
|
828
|
+
for root, dirs, files in os.walk(obj, topdown=False):
|
|
829
|
+
for name in files:
|
|
830
|
+
filename = os.path.join(root, name)
|
|
831
|
+
if is_image_file(filename):
|
|
832
|
+
all_filename_list.append(filename)
|
|
833
|
+
return all_filename_list
|
|
834
|
+
else:
|
|
835
|
+
raise Exception("Invalid string input: %s" % obj)
|
|
836
|
+
|
|
837
|
+
def get_file_list_from_list(obj,allow_list_of_list=True):
|
|
838
|
+
assert(isinstance(obj,list))
|
|
839
|
+
if np.all([isinstance(_,list) for _ in obj]):
|
|
840
|
+
if not allow_list_of_list:
|
|
841
|
+
raise Exception("Cannot have nested lists")
|
|
842
|
+
list_of_list = []
|
|
843
|
+
for l in obj:
|
|
844
|
+
list_of_list = list_of_list + get_file_list(l,
|
|
845
|
+
allow_list_of_list = False)
|
|
846
|
+
return list_of_list
|
|
847
|
+
elif np.all([isinstance(_,str) for _ in obj]):
|
|
848
|
+
list_of_str = []
|
|
849
|
+
for l in obj:
|
|
850
|
+
list_of_str = list_of_str + get_file_list_from_str(l)
|
|
851
|
+
return list_of_str
|
|
852
|
+
else:
|
|
853
|
+
raise Exception("""Inputs must be strings, lists of lists,
|
|
854
|
+
or lists of strings""")
|
|
855
|
+
|
|
856
|
+
def get_file_list(obj,allow_list_of_list=True):
|
|
857
|
+
if isinstance(obj,str):
|
|
858
|
+
obj = get_file_list_from_str(obj)
|
|
859
|
+
elif isinstance(obj,list):
|
|
860
|
+
obj = get_file_list_from_list(obj)
|
|
861
|
+
else:
|
|
862
|
+
raise Exception("Invalid path input")
|
|
863
|
+
assert(isinstance(obj,list))
|
|
864
|
+
assert(np.all([isinstance(_,str) for _ in obj]))
|
|
865
|
+
if np.all([len(_) == 0 for _ in obj]):
|
|
866
|
+
raise Exception("No valid files found")
|
|
867
|
+
elif np.any([len(_) == 0 for _ in obj]):
|
|
868
|
+
raise Exception("One without valid files")
|
|
869
|
+
return obj
|
|
870
|
+
|
|
871
|
+
if __name__ == '__main__':
|
|
872
|
+
imagename = sys.argv[1]
|
|
873
|
+
output_folder = os.path.join('.','image_segment_examples')
|
|
874
|
+
just_segment = False
|
|
875
|
+
if not os.path.isdir(os.path.join('.','models')):
|
|
876
|
+
just_segment = True
|
|
877
|
+
if not os.path.isdir(output_folder):
|
|
878
|
+
os.mkdir(output_folder)
|
|
879
|
+
foldername = "%s_%s" % (os.path.basename(os.path.dirname(imagename)),
|
|
880
|
+
os.path.splitext(os.path.basename(imagename))[0])
|
|
881
|
+
image_output_folder = os.path.join(output_folder,foldername)
|
|
882
|
+
if not os.path.isdir(image_output_folder):
|
|
883
|
+
os.mkdir(image_output_folder)
|
|
884
|
+
labels,masks = get_predicted_labels(imagename,gpu=True,just_segment=just_segment)
|
|
885
|
+
|
|
886
|
+
np.save(os.path.join(image_output_folder,'masks.npy'),masks)
|
|
887
|
+
if not just_segment:
|
|
888
|
+
np.save(os.path.join(image_output_folder,'masks_sum.npy'),masks)
|
|
889
|
+
np.savetxt(os.path.join(image_output_folder,'labels.csv'),labels,
|
|
890
|
+
delimiter=",",fmt='%s')
|
|
891
|
+
copyfile(imagename,os.path.join(image_output_folder,os.path.basename(imagename)))
|
|
892
|
+
print(imagename)
|