comparison S3segmenter.py @ 0:37acf42a824b draft

"planemo upload for repository https://github.com/ohsu-comp-bio/S3segmenter commit d89a61efd4c465a1e6bf5b99b0f78fb19be5bdea-dirty"
author perssond
date Fri, 12 Mar 2021 00:18:40 +0000
parents
children 41e8efe8df43
comparison
equal deleted inserted replaced
-1:000000000000 0:37acf42a824b
1 import matplotlib.pyplot as plt
2 import tifffile
3 import os
4 import numpy as np
5 from skimage import io as skio
6 from scipy.ndimage import *
7 import scipy.ndimage as ndi
8 from skimage.morphology import *
9 from skimage.morphology import extrema
10 from skimage import morphology
11 from skimage.measure import regionprops
12 from skimage.transform import resize
13 from skimage.filters import gaussian, threshold_otsu, threshold_local
14 from skimage.feature import peak_local_max
15 from skimage.color import label2rgb
16 from skimage.io import imsave,imread
17 from skimage.segmentation import clear_border, watershed, find_boundaries
18 from scipy.ndimage.filters import uniform_filter
19 from os.path import *
20 from os import listdir, makedirs, remove
21 import pickle
22 import shutil
23 import fnmatch
24 import cv2
25 import sys
26 import argparse
27 import re
28 import copy
29 import datetime
30 from joblib import Parallel, delayed
31 from rowit import WindowView, crop_with_padding_mask
32
33
34 def imshowpair(A,B):
35 plt.imshow(A,cmap='Purples')
36 plt.imshow(B,cmap='Greens',alpha=0.5)
37 plt.show()
38
39
40 def imshow(A):
41 plt.imshow(A)
42 plt.show()
43
44 def overlayOutline(outline,img):
45 img2 = img.copy()
46 stacked_img = np.stack((img2,)*3, axis=-1)
47 stacked_img[outline > 0] = [65535, 0, 0]
48 imshowpair(img2,stacked_img)
49
50 def normI(I):
51 Irs=resize(I,(I.shape[0]//10,I.shape[1]//10) );
52 p1 = np.percentile(Irs,10);
53 J = I-p1;
54 p99 = np.percentile(Irs,99.99);
55 J = J/(p99-p1);
56 return J
57
58 def contour_pm_watershed(
59 contour_pm, sigma=2, h=0, tissue_mask=None,
60 padding_mask=None, min_area=None, max_area=None
61 ):
62 if tissue_mask is None:
63 tissue_mask = np.ones_like(contour_pm)
64 padded = None
65 if padding_mask is not None and np.any(padding_mask == 0):
66 contour_pm, padded = crop_with_padding_mask(
67 contour_pm, padding_mask, return_mask=True
68 )
69 tissue_mask = crop_with_padding_mask(
70 tissue_mask, padding_mask
71 )
72
73 maxima = peak_local_max(
74 extrema.h_maxima(
75 ndi.gaussian_filter(np.invert(contour_pm), sigma=sigma),
76 h=h
77 ),
78 indices=False,
79 footprint=np.ones((3, 3))
80 )
81 maxima = label(maxima).astype(np.int32)
82
83 # Passing mask into the watershed function will exclude seeds outside
84 # of the mask, which gives fewer and more accurate segments
85 maxima = watershed(
86 contour_pm, maxima, watershed_line=True, mask=tissue_mask
87 ) > 0
88
89 if min_area is not None and max_area is not None:
90 maxima = label(maxima, connectivity=1).astype(np.int32)
91 areas = np.bincount(maxima.ravel())
92 size_passed = np.arange(areas.size)[
93 np.logical_and(areas > min_area, areas < max_area)
94 ]
95 maxima *= np.isin(maxima, size_passed)
96 np.greater(maxima, 0, out=maxima)
97
98 if padded is None:
99 return maxima.astype(np.bool)
100 else:
101 padded[padded == 1] = maxima.flatten()
102 return padded.astype(np.bool)
103
104 def S3AreaSegmenter(nucleiPM, images, TMAmask, threshold,outputPath):
105 nucleiCenters = nucleiPM[:,:,0]
106 TMAmask= (nucleiCenters>np.amax(nucleiCenters)*0.8)*TMAmask
107 area = []
108 area.append(np.sum(np.sum(TMAmask)))
109 for iChan in range(len(images)):
110 image_gauss = gaussian(resize(images[iChan,:,:],(int(0.25*images.shape[1]),int(0.25*images.shape[2]))),1)
111 if threshold ==-1:
112 threshold = threshold_otsu(image_gauss)
113 mask=resize(image_gauss>threshold,(images.shape[1],images.shape[2]),order = 0)*TMAmask
114 area.append(np.sum(np.sum(mask)))
115 np.savetxt(outputPath + os.path.sep + 'area.csv',(np.transpose(np.asarray(area))),fmt='%10.5f')
116 return TMAmask
117
118
119 def S3NucleiSegmentationWatershed(nucleiPM,nucleiImage,logSigma,TMAmask,nucleiFilter,nucleiRegion):
120 nucleiContours = nucleiPM[:,:,1]
121 nucleiCenters = nucleiPM[:,:,0]
122
123 mask = resize(TMAmask,(nucleiImage.shape[0],nucleiImage.shape[1]),order = 0)>0
124
125 if nucleiRegion == 'localThreshold':
126 Imax = peak_local_max(extrema.h_maxima(255-nucleiContours,logSigma[0]),indices=False)
127 Imax = label(Imax).astype(np.int32)
128 foregroundMask = watershed(nucleiContours, Imax, watershed_line=True)
129 P = regionprops(foregroundMask, np.amax(nucleiCenters) - nucleiCenters - nucleiContours)
130 prop_keys = ['mean_intensity', 'label','area']
131 def props_of_keys(prop, keys):
132 return [prop[k] for k in keys]
133
134 mean_ints, labels, areas = np.array(Parallel(n_jobs=6)(delayed(props_of_keys)(prop, prop_keys)
135 for prop in P
136 )
137 ).T
138 del P
139 maxArea = (logSigma[1]**2)*3/4
140 minArea = (logSigma[0]**2)*3/4
141 passed = np.logical_and.reduce((
142 np.logical_and(areas > minArea, areas < maxArea),
143 np.less(mean_ints, 50)
144 ))
145
146 foregroundMask *= np.isin(foregroundMask, labels[passed])
147 np.greater(foregroundMask, 0, out=foregroundMask)
148 foregroundMask = label(foregroundMask, connectivity=1).astype(np.int32)
149 elif nucleiRegion =='bypass':
150 foregroundMask = nucleiPM[:,:,0]
151 P = regionprops(foregroundMask, nucleiImage)
152 prop_keys = ['mean_intensity', 'label','area']
153 def props_of_keys(prop, keys):
154 return [prop[k] for k in keys]
155
156 mean_ints, labels, areas = np.array(Parallel(n_jobs=6)(delayed(props_of_keys)(prop, prop_keys)
157 for prop in P
158 )
159 ).T
160 del P
161 maxArea = (logSigma[1]**2)*3/4
162 minArea = (logSigma[0]**2)*3/4
163 passed = np.logical_and(areas > minArea, areas < maxArea)
164
165 foregroundMask *= np.isin(foregroundMask, labels[passed])
166 np.greater(foregroundMask, 0, out=foregroundMask)
167 foregroundMask = label(foregroundMask, connectivity=1).astype(np.int32)
168 else:
169
170 if len(logSigma)==1:
171 nucleiDiameter = [logSigma*0.5, logSigma*1.5]
172 else:
173 nucleiDiameter = logSigma
174 logMask = nucleiCenters > 150
175
176 win_view_setting = WindowView(nucleiContours.shape, 2000, 500)
177
178 nucleiContours = win_view_setting.window_view_list(nucleiContours)
179 padding_mask = win_view_setting.padding_mask()
180 mask = win_view_setting.window_view_list(mask)
181
182 maxArea = (logSigma[1]**2)*3/4
183 minArea = (logSigma[0]**2)*3/4
184
185 foregroundMask = np.array(
186 Parallel(n_jobs=6)(delayed(contour_pm_watershed)(
187 img, sigma=logSigma[1]/30, h=logSigma[1]/30, tissue_mask=tm,
188 padding_mask=m, min_area=minArea, max_area=maxArea
189 ) for img, tm, m in zip(nucleiContours, mask, padding_mask))
190 )
191
192 del nucleiContours, mask
193
194 foregroundMask = win_view_setting.reconstruct(foregroundMask)
195 foregroundMask = label(foregroundMask, connectivity=1).astype(np.int32)
196
197 if nucleiFilter == 'IntPM':
198 int_img = nucleiCenters
199 elif nucleiFilter == 'Int':
200 int_img = nucleiImage
201
202 print(' ', datetime.datetime.now(), 'regionprops')
203 P = regionprops(foregroundMask, int_img)
204
205 def props_of_keys(prop, keys):
206 return [prop[k] for k in keys]
207
208 prop_keys = ['mean_intensity', 'area', 'solidity', 'label']
209 mean_ints, areas, solidities, labels = np.array(
210 Parallel(n_jobs=6)(delayed(props_of_keys)(prop, prop_keys)
211 for prop in P
212 )
213 ).T
214 del P
215
216 MITh = threshold_otsu(mean_ints)
217
218 minSolidity = 0.8
219
220 passed = np.logical_and.reduce((
221 np.greater(mean_ints, MITh),
222 np.logical_and(areas > minArea, areas < maxArea),
223 np.greater(solidities, minSolidity)
224 ))
225
226 # set failed mask label to zero
227 foregroundMask *= np.isin(foregroundMask, labels[passed])
228
229 np.greater(foregroundMask, 0, out=foregroundMask)
230 foregroundMask = label(foregroundMask, connectivity=1).astype(np.int32)
231
232 return foregroundMask
233
234 def bwmorph(mask,radius):
235 mask = np.array(mask,dtype=np.uint8)
236 #labels = label(mask)
237 background = nucleiMask == 0
238 distances, (i, j) = distance_transform_edt(background, return_indices=True)
239 cellMask = nucleiMask.copy()
240 finalmask = background & (distances <= radius)
241 cellMask[finalmask] = nucleiMask[i[finalmask], j[finalmask]]
242
243 # imshowpair(cellMask,mask)
244 return cellMask
245 # imshow(fg)
246 # fg = cv2.dilate(mask,ndimage.generate_binary_structure(2, 2))
247 # bg = 1-fg-mask
248 # imshowpair(bg,mask)
249
250 def S3CytoplasmSegmentation(nucleiMask,cyto,mask,cytoMethod='distanceTransform',radius = 5):
251 mask = (nucleiMask + resize(mask,(nucleiMask.shape[0],nucleiMask.shape[1]),order=0))>0
252 gdist = distance_transform_edt(1-(nucleiMask>0))
253 if cytoMethod == 'distanceTransform':
254 mask = np.array(mask,dtype=np.uint32)
255 markers= nucleiMask
256 elif cytoMethod == 'hybrid':
257 cytoBlur = gaussian(cyto,2)
258 c1 = uniform_filter(cytoBlur, 3, mode='reflect')
259 c2 = uniform_filter(cytoBlur*cytoBlur, 3, mode='reflect')
260 grad = np.sqrt(c2 - c1*c1)*np.sqrt(9./8)
261 grad[np.isnan(grad)]=0
262 gdist= np.sqrt(np.square(grad) + 0.000001*np.amax(grad)/np.amax(gdist)*np.square(gdist))
263 bg = binary_erosion(np.invert(mask),morphology.selem.disk(radius, np.uint8))
264 markers=nucleiMask.copy()
265 markers[bg==1] = np.amax(nucleiMask)+1
266 markers = label(markers>0,connectivity=1)
267 mask = np.ones(nucleiMask.shape)
268 del bg
269 elif cytoMethod == 'ring':
270 # mask =np.array(bwmorph(nucleiMask,radius)*mask,dtype=np.uint32)>0
271 mask =np.array(bwmorph(nucleiMask,radius),dtype=np.uint32)>0
272 markers= nucleiMask
273
274 cellMask =clear_border(watershed(gdist,markers,watershed_line=True))
275 del gdist, markers, cyto
276 cellMask = np.array(cellMask*mask,dtype=np.uint32)
277
278 finalCellMask = np.zeros(cellMask.shape,dtype=np.uint32)
279 P = regionprops(label(cellMask>0,connectivity=1),nucleiMask>0,cache=False)
280 count=0
281 for props in P:
282 if props.max_intensity>0 :
283 count += 1
284 yi = props.coords[:, 0]
285 xi = props.coords[:, 1]
286 finalCellMask[yi, xi] = count
287 nucleiMask = np.array(nucleiMask>0,dtype=np.uint32)
288 nucleiMask = finalCellMask*nucleiMask
289 cytoplasmMask = np.subtract(finalCellMask,nucleiMask)
290 return cytoplasmMask,nucleiMask,finalCellMask
291
292 def exportMasks(mask,image,outputPath,filePrefix,fileName,saveFig=True,saveMasks = True):
293 outputPath =outputPath + os.path.sep + filePrefix
294 if not os.path.exists(outputPath):
295 os.makedirs(outputPath)
296 if saveMasks ==True:
297 kwargs={}
298 kwargs['bigtiff'] = True
299 kwargs['photometric'] = 'minisblack'
300 resolution = np.round(1)
301 kwargs['resolution'] = (resolution, resolution, 'cm')
302 kwargs['metadata'] = None
303 kwargs['description'] = '!!xml!!'
304 imsave(outputPath + os.path.sep + fileName + 'Mask.tif',mask, plugin="tifffile")
305
306 if saveFig== True:
307 mask=np.uint8(mask>0)
308 edges = find_boundaries(mask,mode = 'outer')
309 stacked_img=np.stack((np.uint16(edges)*np.amax(image),image),axis=0)
310 tifffile.imsave(outputPath + os.path.sep + fileName + 'Outlines.tif',stacked_img)
311
312 def S3punctaDetection(spotChan,mask,sigma,SD):
313 Ilog = -gaussian_laplace(np.float32(spotChan),sigma)
314 fgm=peak_local_max(Ilog, indices=False,footprint=np.ones((3, 3)))
315 test=Ilog[fgm==1]
316 med = np.median(test)
317 mad = np.median(np.absolute(test - med))
318 thresh = med + 1.4826*SD*mad
319 return (Ilog>thresh)*fgm*(mask>0)
320
321 # stacked_img=np.stack((spots*4095,nucleiCrop),axis=0)
322 # tifffile.imsave('D:/Seidman/ZeissTest Sets/registration/spottest.tif',stacked_img)
323
324
325 # assign nan to tissue mask
326
327
328 if __name__ == '__main__':
329 parser=argparse.ArgumentParser()
330 parser.add_argument("--imagePath")
331 parser.add_argument("--contoursClassProbPath",default ='')
332 parser.add_argument("--nucleiClassProbPath",default ='')
333 parser.add_argument("--stackProbPath",default ='')
334 parser.add_argument("--outputPath")
335 parser.add_argument("--dearrayPath")
336 parser.add_argument("--maskPath")
337 parser.add_argument("--probMapChan",type = int, default = -1)
338 parser.add_argument("--mask",choices=['TMA', 'tissue','none'],default = 'tissue')
339 parser.add_argument("--crop",choices=['interactiveCrop','autoCrop','noCrop','dearray','plate'], default = 'noCrop')
340 parser.add_argument("--cytoMethod",choices=['hybrid','distanceTransform','bwdistanceTransform','ring'],default = 'distanceTransform')
341 parser.add_argument("--nucleiFilter",choices=['IntPM','LoG','Int','none'],default = 'IntPM')
342 parser.add_argument("--nucleiRegion",choices=['watershedContourDist','watershedContourInt','watershedBWDist','dilation','localThreshold','bypass','pixellevel'], default = 'watershedContourInt')
343 parser.add_argument("--pixelThreshold",type = float, default = -1)
344 parser.add_argument("--segmentCytoplasm",choices = ['segmentCytoplasm','ignoreCytoplasm'],default = 'ignoreCytoplasm')
345 parser.add_argument("--cytoDilation",type = int, default = 5)
346 parser.add_argument("--logSigma",type = int, nargs = '+', default = [3, 60])
347 parser.add_argument("--CytoMaskChan",type=int, nargs = '+', default=[1])
348 parser.add_argument("--pixelMaskChan",type=int, nargs = '+', default=[1])
349 parser.add_argument("--TissueMaskChan",type=int, nargs = '+', default=-1)
350 parser.add_argument("--detectPuncta",type=int, nargs = '+', default=[-1])
351 parser.add_argument("--punctaSigma", nargs = '+', type=float, default=[1])
352 parser.add_argument("--punctaSD", nargs = '+', type=float, default=[4])
353 parser.add_argument("--saveMask",action='store_false')
354 parser.add_argument("--saveFig",action='store_false')
355 args = parser.parse_args()
356
357 # gather filename information
358 #exemplar001
359 # imagePath = 'D:/LSP/cycif/testsets/exemplar-001/registration/exemplar-001small.ome.tif'
360 # outputPath = 'D:/LSP/cycif/testsets/exemplar-001/segmentation'
361 ## nucleiClassProbPath = 'D:/LSP/cycif/testsets/exemplar-001/probability_maps/exemplar-001_NucleiPM_0.tif'
362 ## contoursClassProbPath = 'D:/LSP/cycif/testsets/exemplar-001/probability_maps/exemplar-001_ContoursPM_0.tif'
363 # contoursClassProbPath =''
364 # stackProbPath = 'D:/LSP/cycif/testsets/exemplar-001_Probabilities_0.tif'
365 # maskPath = 'D:/LSP/cycif/testsets/exemplar-001/dearray/masks/A1_mask.tif'
366 # args.cytoMethod = 'hybrid'
367 # args.nucleiRegion = 'localThreshold'
368 # args.segmentCytoplasm = 'segmentCytoplasm'
369
370 # exemplar002
371 # imagePath = 'D:/LSP/cycif/testsets/exemplar-002/dearray/1.tif'
372 # outputPath = 'D:/LSP/cycif/testsets/exemplar-002/segmentation'
373 # nucleiClassProbPath = ''#'D:/LSP/cycif/testsets/exemplar-002/prob_map/1_NucleiPM_1.tif'
374 # contoursClassProbPath = ''#'D:/LSP/cycif/testsets/exemplar-002/prob_map/1_ContoursPM_1.tif'
375 # stackProbPath = 'D:/LSP/cycif/testsets/exemplar-002/probability-maps/unmicst_1new_Probabilities_1.tif'
376 # maskPath = 'D:/LSP/cycif/testsets/exemplar-002/dearrayPython/masks/1_mask.tif'
377 # args.probMapChan =1
378 # args.cytoMethod = 'hybrid'
379 # args.mask = 'TMA'
380 # args.crop = 'dearray'
381 # args.crop = 'autoCrop'
382 # args.segmentCytoplasm = 'segmentCytoplasm'
383 #PTCL
384 # imagePath = 'D:/LSP/cycif/testsets/PTCL/dearrayPython/1.tif'
385 # outputPath = 'D:/LSP/cycif/testsets/PTCL/dearrayPython/segmentation'
386 # nucleiClassProbPath = ''#'D:/LSP/cycif/testsets/exemplar-002/prob_map/1_NucleiPM_1.tif'
387 # contoursClassProbPath = ''#'D:/LSP/cycif/testsets/exemplar-002/prob_map/1_ContoursPM_1.tif'
388 # stackProbPath = 'D:/LSP/cycif/testsets/PTCL/prob_maps/1_Probabilities_40.tif'
389 # maskPath = 'D:/LSP/cycif/testsets/exemplar-002/dearrayPython/masks/1_mask.tif'
390 # args.crop = 'dearray'
391 # args.segmentCytoplasm = 'segmentCytoplasm'
392 #
393 #punctatest
394 # imagePath = 'Z:/IDAC/Clarence/Seidman/ZeissMouseTestSet/31082020_XXWT_Txnip550_Ddx3x647_WGA488_40x_1.tif'
395 # outputPath = 'Z:/IDAC/Clarence/Seidman/ZeissMouseTestSet/segmentation'
396 ## nucleiClassProbPath = 'Z:/IDAC/Clarence/Seidman/ZeissMouseTestSet/probability-maps/test_NucleiPM_1.tif'
397 ## contoursClassProbPath = 'Z:/IDAC/Clarence/Seidman/DanMouse/probability-maps/test_ContoursPM_1.tif'
398 # contoursClassProbPath =''
399 # stackProbPath = 'Z:/IDAC/Clarence/Seidman/ZeissMouseTestSet/probability-maps/31082020_XXWT_Txnip550_Ddx3x647_WGA488_40x_1_Probabilities_2.tif'
400 # maskPath = 'D:/Seidman/ZeissTest Sets/segmentation/13042020_15AP_FAP488_LINC550_DCN647_WGA_40x_1/cellMask.tif'
401 # args.nucleiRegion = 'localThreshold'
402 # args.logSigma = [45, 300]
403 # args.segmentCytoplasm = 'ignoreCytoplasm'
404 # args.detectPuncta = [1]
405 # args.punctaSigma = [1]
406 # args.punctaSD = [3]
407
408
409 #plate
410 # imagePath = 'Y:/sorger/data/computation/Jeremy/caitlin-ddd-cycif-registered/Plate1/E3_fld_1/registration/E3_fld_1.ome.tif'
411 # outputPath = 'Y:/sorger/data/computation/Jeremy/caitlin-ddd-cycif-registered/Plate1/E3_fld_1/segmentation'
412 # nucleiClassProbPath = 'Y:/sorger/data/computation/Jeremy/caitlin-ddd-cycif-registered/Plate1/E3_fld_1/prob_maps/E3_fld_1_NucleiPM_1.tif'
413 # contoursClassProbPath = 'Y:/sorger/data/computation/Jeremy/caitlin-ddd-cycif-registered/Plate1/E3_fld_1/prob_maps/E3_fld_1_ContoursPM_1.tif'
414 # maskPath = 'D:/LSP/cycif/testsets/exemplar-001/dearray/masks/A1_mask.tif'
415 # args.crop = 'plate'
416 # args.cytoMethod ='hybrid'
417
418 #large tissue
419 # imagePath = 'D:/WD-76845-097.ome.tif'
420 # outputPath = 'D:/'
421 ## nucleiClassProbPath = 'D:/WD-76845-097_NucleiPM_28.tif'
422 # contoursClassProbPath = ""#'D:/WD-76845-097_ContoursPM_28.tif'
423 # stackProbPath = 'D:/ilastik/WD-76845-097_Probabilities_0.tif'
424 # maskPath = 'D:/LSP/cycif/testsets/exemplar-001/dearray/masks/A1_mask.tif'
425 # args.nucleiRegion = 'localThreshold'
426 # args.crop = 'autoCrop'
427 # args.TissueMaskChan =[0]
428
429 #maskRCNN
430 # imagePath = 'D:/Seidman/s3segtest/registration/1.tif'
431 # outputPath = 'D:/Seidman/s3segtest/segmentation'
432 # stackProbPath = 'D:/Seidman/s3segtest/1_Probabilities_0.tif'
433 # contoursClassProbPath = ''
434 # maskPath = 'D:/LSP/cycif/testsets/exemplar-001/dearray/masks/A1_mask.tif'
435 # args.nucleiRegion = 'bypass'
436 # args.crop = 'noCrop'
437 # args.TissueMaskChan =[0]
438 # args.logSigma = [45,300]
439
440 # #pixellevel
441 # imagePath = 'D:/Olesja/D2107_spleen_DAPI-EdU_01/Layer0/D2107_spleen_DAPI-EdU_01.btf'
442 # outputPath = 'D:/Olesja/D2107_spleen_DAPI-EdU_01/segmentation'
443 # stackProbPath = 'D:/Seidman/s3segtest/1_Probabilities_0.tif'
444 # contoursClassProbPath = 'D:/Olesja/D2107_spleen_DAPI-EdU_01/prob_maps3Class/D2107_spleen_DAPI-EdU_01_ContoursPM_0.tif'
445 # nucleiClassProbPath = 'D:/Olesja/D2107_spleen_DAPI-EdU_01/prob_maps3Class/D2107_spleen_DAPI-EdU_01_NucleiPM_0.tif'
446 # maskPath = 'D:/LSP/cycif/testsets/exemplar-001/dearray/masks/A1_mask.tif'
447 # args.nucleiRegion = 'pixellevel'
448 # args.crop = 'noCrop'
449 # args.TissueMaskChan =[0]
450 # args.pixelThreshold = 0.06
451
452 imagePath = args.imagePath
453 outputPath = args.outputPath
454 nucleiClassProbPath = args.nucleiClassProbPath
455 contoursClassProbPath = args.contoursClassProbPath
456 stackProbPath = args.stackProbPath
457 maskPath = args.maskPath
458
459 fileName = os.path.basename(imagePath)
460 filePrefix = fileName[0:fileName.index('.')]
461
462 if not os.path.exists(outputPath):
463 os.makedirs(outputPath)
464
465 # get channel used for nuclei segmentation
466
467 if len(contoursClassProbPath)>0:
468 legacyMode = 1
469 probPrefix = os.path.basename(contoursClassProbPath)
470 nucMaskChan = int(probPrefix.split('ContoursPM_')[1].split('.')[0])
471 elif len(stackProbPath)>0:
472 legacyMode = 0
473 probPrefix = os.path.basename(stackProbPath)
474 index = re.search('%s(.*)%s' % ('Probabilities', '.tif'), stackProbPath).group(1)
475 if len(index)==0:
476 nucMaskChan = args.probMapChan
477 else:
478 nucMaskChan = int(re.sub("\D", "", index))
479 else:
480 print('NO PROBABILITY MAP PROVIDED')
481 if args.probMapChan ==-1:
482 if nucMaskChan ==-1:
483 sys.exit('INVALID NUCLEI CHANNEL SELECTION. SELECT CHANNEL USING --probMapChan')
484 else:
485 print('extracting nuclei channel from filename')
486 else:
487 nucMaskChan = args.probMapChan
488
489 if args.TissueMaskChan==-1:
490 TissueMaskChan = copy.copy(args.CytoMaskChan)
491 TissueMaskChan.append(nucMaskChan)
492 else:
493 TissueMaskChan = args.TissueMaskChan[:]
494 TissueMaskChan.append(nucMaskChan)
495
496 #crop images if needed
497 if args.crop == 'interactiveCrop':
498 nucleiCrop = tifffile.imread(imagePath,key = nucMaskChan)
499 r=cv2.selectROI(resize(nucleiCrop,(nucleiCrop.shape[0] // 30, nucleiCrop.shape[1] // 30)))
500 cv2.destroyWindow('select')
501 rect=np.transpose(r)*30
502 PMrect= [rect[1], rect[0], rect[3], rect[2]]
503 nucleiCrop = nucleiCrop[int(rect[1]):int(rect[1]+rect[3]), int(rect[0]):int(rect[0]+rect[2])]
504 elif args.crop == 'noCrop' or args.crop == 'dearray' or args.crop == 'plate':
505 nucleiCrop = tifffile.imread(imagePath,key = nucMaskChan)
506 rect = [0, 0, nucleiCrop.shape[0], nucleiCrop.shape[1]]
507 PMrect= rect
508 elif args.crop == 'autoCrop':
509 nucleiCrop = tifffile.imread(imagePath,key = nucMaskChan)
510 rect = [np.round(nucleiCrop.shape[0]/3), np.round(nucleiCrop.shape[1]/3),np.round(nucleiCrop.shape[0]/3), np.round(nucleiCrop.shape[1]/3)]
511 PMrect= rect
512 nucleiCrop = nucleiCrop[int(rect[0]):int(rect[0]+rect[2]), int(rect[1]):int(rect[1]+rect[3])]
513
514 if legacyMode ==1:
515 nucleiProbMaps = tifffile.imread(nucleiClassProbPath,key=0)
516 nucleiPM = nucleiProbMaps[int(PMrect[0]):int(PMrect[0]+PMrect[2]), int(PMrect[1]):int(PMrect[1]+PMrect[3])]
517 nucleiProbMaps = tifffile.imread(contoursClassProbPath,key=0)
518 PMSize = nucleiProbMaps.shape
519 nucleiPM = np.dstack((nucleiPM,nucleiProbMaps[int(PMrect[0]):int(PMrect[0]+PMrect[2]), int(PMrect[1]):int(PMrect[1]+PMrect[3])]))
520 else:
521 nucleiProbMaps = imread(stackProbPath)
522 nucleiPM = nucleiProbMaps[int(PMrect[0]):int(PMrect[0]+PMrect[2]), int(PMrect[1]):int(PMrect[1]+PMrect[3]),0:2]
523 PMSize = nucleiProbMaps.shape
524
525 # mask the core/tissue
526 if args.crop == 'dearray':
527 TMAmask = tifffile.imread(maskPath)
528 elif args.crop =='plate':
529 TMAmask = np.ones(nucleiCrop.shape)
530
531 else:
532 tissue = np.empty((len(TissueMaskChan),nucleiCrop.shape[0],nucleiCrop.shape[1]),dtype=np.uint16)
533 count=0
534 if args.crop == 'noCrop':
535 for iChan in TissueMaskChan:
536 tissueCrop =tifffile.imread(imagePath,key=iChan)
537 tissue_gauss = gaussian(tissueCrop,1)
538 #tissue_gauss[tissue_gauss==0]=np.nan
539 tissue[count,:,:] =np.log2(tissue_gauss+1)>threshold_otsu(np.log2(tissue_gauss+1))
540 count+=1
541 else:
542 for iChan in TissueMaskChan:
543 tissueCrop = tifffile.imread(imagePath,key=iChan)
544 tissue_gauss = gaussian(tissueCrop[int(PMrect[0]):int(PMrect[0]+PMrect[2]), int(PMrect[1]):int(PMrect[1]+PMrect[3])],1)
545 tissue[count,:,:] = np.log2(tissue_gauss+1)>threshold_otsu(np.log2(tissue_gauss+1))
546 count+=1
547 TMAmask = np.max(tissue,axis = 0)
548
549 # tissue_gauss = tissueCrop
550 # tissue_gauss1 = tissue_gauss.astype(float)
551 # tissue_gauss1[tissue_gauss>np.percentile(tissue_gauss,99)]=np.nan
552 # TMAmask = np.log2(tissue_gauss+1)>threshold_otsu(np.log2(tissue_gauss+1))
553 #imshow(TMAmask)
554 del tissue_gauss, tissue
555
556 # nuclei segmentation
557 if args.nucleiRegion == 'pixellevel':
558 pixelTissue = np.empty((len(args.pixelMaskChan),nucleiCrop.shape[0],nucleiCrop.shape[1]),dtype=np.uint16)
559 count=0
560 for iChan in args.pixelMaskChan:
561 pixelCrop = tifffile.imread(imagePath,key=iChan)
562 pixelTissue[count,:,:] = pixelCrop[int(PMrect[0]):int(PMrect[0]+PMrect[2]), int(PMrect[1]):int(PMrect[1]+PMrect[3])]
563 count+=1
564 nucleiMask = S3AreaSegmenter(nucleiPM, pixelTissue, TMAmask,args.pixelThreshold,outputPath)
565 else:
566 nucleiMask = S3NucleiSegmentationWatershed(nucleiPM,nucleiCrop,args.logSigma,TMAmask,args.nucleiFilter,args.nucleiRegion)
567 del nucleiPM
568 # cytoplasm segmentation
569 if args.segmentCytoplasm == 'segmentCytoplasm':
570 count =0
571 if args.crop == 'noCrop' or args.crop == 'dearray' or args.crop == 'plate':
572 cyto=np.empty((len(args.CytoMaskChan),nucleiCrop.shape[0],nucleiCrop.shape[1]),dtype=np.uint16)
573 for iChan in args.CytoMaskChan:
574 cyto[count,:,:] = tifffile.imread(imagePath, key=iChan)
575 count+=1
576 elif args.crop =='autoCrop':
577 cyto=np.empty((len(args.CytoMaskChan),int(rect[2]),int(rect[3])),dtype=np.int16)
578 for iChan in args.CytoMaskChan:
579 cytoFull= tifffile.imread(imagePath, key=iChan)
580 cyto[count,:,:] = cytoFull[int(PMrect[0]):int(PMrect[0]+PMrect[2]), int(PMrect[1]):int(PMrect[1]+PMrect[3])]
581 count+=1
582 else:
583 cyto=np.empty((len(args.CytoMaskChan),rect[3],rect[2]),dtype=np.int16)
584 for iChan in args.CytoMaskChan:
585 cytoFull= tifffile.imread(imagePath, key=iChan)
586 cyto[count,:,:] = cytoFull[int(PMrect[0]):int(PMrect[0]+PMrect[2]), int(PMrect[1]):int(PMrect[1]+PMrect[3])]
587 count+=1
588 cyto = np.amax(cyto,axis=0)
589 cytoplasmMask,nucleiMaskTemp,cellMask = S3CytoplasmSegmentation(nucleiMask,cyto,TMAmask,args.cytoMethod,args.cytoDilation)
590 exportMasks(nucleiMaskTemp,nucleiCrop,outputPath,filePrefix,'nuclei',args.saveFig,args.saveMask)
591 exportMasks(cytoplasmMask,cyto,outputPath,filePrefix,'cyto',args.saveFig,args.saveMask)
592 exportMasks(cellMask,cyto,outputPath,filePrefix,'cell',args.saveFig,args.saveMask)
593
594 cytoplasmMask,nucleiMaskTemp,cellMask = S3CytoplasmSegmentation(nucleiMask,cyto,TMAmask,'ring',args.cytoDilation)
595 exportMasks(nucleiMaskTemp,nucleiCrop,outputPath,filePrefix,'nucleiRing',args.saveFig,args.saveMask)
596 exportMasks(cytoplasmMask,cyto,outputPath,filePrefix,'cytoRing',args.saveFig,args.saveMask)
597 exportMasks(cellMask,cyto,outputPath,filePrefix,'cellRing',args.saveFig,args.saveMask)
598
599 elif args.segmentCytoplasm == 'ignoreCytoplasm':
600 exportMasks(nucleiMask,nucleiCrop,outputPath,filePrefix,'nuclei')
601 cellMask = nucleiMask
602 exportMasks(nucleiMask,nucleiCrop,outputPath,filePrefix,'cell')
603 cytoplasmMask = nucleiMask
604
605
606 if (np.min(args.detectPuncta)>-1):
607 if len(args.detectPuncta) != len(args.punctaSigma):
608 args.punctaSigma = args.punctaSigma[0] * np.ones(len(args.detectPuncta))
609
610
611 if len(args.detectPuncta) != len(args.punctaSD):
612 args.punctaSD = args.punctaSD[0] * np.ones(len(args.detectPuncta))
613
614 counter=0
615 for iPunctaChan in args.detectPuncta:
616 punctaChan = tifffile.imread(imagePath,key = iPunctaChan)
617 punctaChan = punctaChan[int(PMrect[0]):int(PMrect[0]+PMrect[2]), int(PMrect[1]):int(PMrect[1]+PMrect[3])]
618 spots=S3punctaDetection(punctaChan,cellMask,args.punctaSigma[counter],args.punctaSD[counter])
619 cellspotmask = nucleiMask#tifffile.imread(maskPath) #REMOVE THIS LATER
620 P = regionprops(cellspotmask,intensity_image = spots ,cache=False)
621 numSpots = []
622 for prop in P:
623 numSpots.append(np.uint16(np.round(prop.mean_intensity * prop.area)))
624 np.savetxt(outputPath + os.path.sep + 'numSpots_chan' + str(iPunctaChan) +'.csv',(np.transpose(np.asarray(numSpots))),fmt='%10.5f')
625 edges = 1-(cellMask>0)
626 stacked_img=np.stack((np.uint16((spots+edges)>0)*np.amax(punctaChan),punctaChan),axis=0)
627 tifffile.imsave(outputPath + os.path.sep + filePrefix + os.path.sep + 'punctaChan'+str(iPunctaChan) + 'Outlines.tif',stacked_img)
628 counter=counter+1
629 #fix bwdistance watershed