comparison S3segmenter.py @ 2:96d0d969ebc9 draft default tip

planemo upload for repository https://github.com/goeckslab/tools-mti/tree/main/tools/s3segmenter commit 0f4f17235c5961c2fd3d4c30180507f66214c11d
author goeckslab
date Fri, 16 Sep 2022 20:05:54 +0000
parents 41e8efe8df43
children
comparison
equal deleted inserted replaced
1:41e8efe8df43 2:96d0d969ebc9
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 from save_tifffile_pyramid import save_pyramid
33 import subprocess
34 import ome_types
35
36
37 def imshowpair(A,B):
38 plt.imshow(A,cmap='Purples')
39 plt.imshow(B,cmap='Greens',alpha=0.5)
40 plt.show()
41
42
43 def imshow(A):
44 plt.imshow(A)
45 plt.show()
46
47 def overlayOutline(outline,img):
48 img2 = img.copy()
49 stacked_img = np.stack((img2,)*3, axis=-1)
50 stacked_img[outline > 0] = [65535, 0, 0]
51 imshowpair(img2,stacked_img)
52
53 def normI(I):
54 Irs=resize(I,(I.shape[0]//10,I.shape[1]//10) );
55 p1 = np.percentile(Irs,10);
56 J = I-p1;
57 p99 = np.percentile(Irs,99.99);
58 J = J/(p99-p1);
59 return J
60
61 def contour_pm_watershed(
62 contour_pm, sigma=2, h=0, tissue_mask=None,
63 padding_mask=None, min_area=None, max_area=None
64 ):
65 if tissue_mask is None:
66 tissue_mask = np.ones_like(contour_pm)
67 padded = None
68 if padding_mask is not None and np.any(padding_mask == 0):
69 contour_pm, padded = crop_with_padding_mask(
70 contour_pm, padding_mask, return_mask=True
71 )
72 tissue_mask = crop_with_padding_mask(
73 tissue_mask, padding_mask
74 )
75
76 maxima = peak_local_max(
77 extrema.h_maxima(
78 ndi.gaussian_filter(np.invert(contour_pm), sigma=sigma),
79 h=h
80 ),
81 indices=False,
82 footprint=np.ones((3, 3))
83 )
84 maxima = label(maxima).astype(np.int32)
85
86 # Passing mask into the watershed function will exclude seeds outside
87 # of the mask, which gives fewer and more accurate segments
88 maxima = watershed(
89 contour_pm, maxima, watershed_line=True, mask=tissue_mask
90 ) > 0
91
92 if min_area is not None and max_area is not None:
93 maxima = label(maxima, connectivity=1).astype(np.int32)
94 areas = np.bincount(maxima.ravel())
95 size_passed = np.arange(areas.size)[
96 np.logical_and(areas > min_area, areas < max_area)
97 ]
98 maxima *= np.isin(maxima, size_passed)
99 np.greater(maxima, 0, out=maxima)
100
101 if padded is None:
102 return maxima.astype(np.bool)
103 else:
104 padded[padded == 1] = maxima.flatten()
105 return padded.astype(np.bool)
106
107 def S3AreaSegmenter(nucleiPM, images, TMAmask, threshold,fileprefix,outputPath):
108 nucleiCenters = nucleiPM[:,:,0]
109 TMAmask= (nucleiCenters>np.amax(nucleiCenters)*0.8)*TMAmask
110 area = []
111 area.append(np.sum(np.sum(TMAmask)))
112 for iChan in range(len(images)):
113 image_gauss = gaussian(resize(images[iChan,:,:],(int(0.25*images.shape[1]),int(0.25*images.shape[2]))),1)
114 if threshold ==-1:
115 threshold = threshold_otsu(image_gauss)
116 mask=resize(image_gauss>threshold,(images.shape[1],images.shape[2]),order = 0)*TMAmask
117 area.append(np.sum(np.sum(mask)))
118 os.mk
119 np.savetxt(outputPath + os.path.sep + fileprefix + '_area.csv',(np.transpose(np.asarray(area))),fmt='%10.5f')
120 return TMAmask
121
122 def getMetadata(path,commit):
123 with tifffile.TiffFile(path) as tif:
124 if not tif.ome_metadata:
125 try:
126 x_res_tag = tif.pages[0].tags['XResolution'].value
127 y_res_tag = tif.pages[0].tags['YResolution'].value
128 physical_size_x = x_res_tag[0] / x_res_tag[1]
129 physical_size_y = y_res_tag[0] / y_res_tag[1]
130 except KeyError:
131 physical_size_x = 1
132 physical_size_y = 1
133 metadata_args = dict(
134 pixel_sizes=(physical_size_y, physical_size_x),
135 pixel_size_units=('µm', 'µm'),
136 software= 's3segmenter v' + commit
137 )
138 else:
139 metadata=ome_types.from_xml(tif.ome_metadata)
140 metadata = metadata.images[0].pixels
141 metadata_args = dict(
142 pixel_sizes=(metadata.physical_size_y,metadata.physical_size_x),
143 pixel_size_units=('µm', 'µm'),
144 software= 's3segmenter v' + commit
145 )
146 return metadata_args
147
148 def S3NucleiBypass(nucleiPM,nucleiImage,logSigma,TMAmask,nucleiFilter,nucleiRegion):
149 foregroundMask = nucleiPM
150 P = regionprops(foregroundMask, nucleiImage)
151 prop_keys = ['mean_intensity', 'label','area']
152 def props_of_keys(prop, keys):
153 return [prop[k] for k in keys]
154
155 mean_ints, labels, areas = np.array(Parallel(n_jobs=6)(delayed(props_of_keys)(prop, prop_keys)
156 for prop in P
157 )
158 ).T
159 del P
160 maxArea = (logSigma[1]**2)*3/4
161 minArea = (logSigma[0]**2)*3/4
162 passed = np.logical_and(areas > minArea, areas < maxArea)
163
164 foregroundMask *= np.isin(foregroundMask, labels[passed])
165 np.greater(foregroundMask, 0, out=foregroundMask)
166 foregroundMask = label(foregroundMask, connectivity=1).astype(np.int32)
167 return foregroundMask
168
169 def S3NucleiSegmentationWatershed(nucleiPM,nucleiImage,logSigma,TMAmask,nucleiFilter,nucleiRegion):
170 nucleiContours = nucleiPM[:,:,1]
171 nucleiCenters = nucleiPM[:,:,0]
172 mask = resize(TMAmask,(nucleiImage.shape[0],nucleiImage.shape[1]),order = 0)>0
173 if nucleiRegion == 'localThreshold' or nucleiRegion == 'localMax':
174 Imax = peak_local_max(extrema.h_maxima(255-nucleiContours,logSigma[0]),indices=False)
175 Imax = label(Imax).astype(np.int32)
176 foregroundMask = watershed(nucleiContours, Imax, watershed_line=True)
177 P = regionprops(foregroundMask, np.amax(nucleiCenters) - nucleiCenters - nucleiContours)
178 prop_keys = ['mean_intensity', 'label','area']
179 def props_of_keys(prop, keys):
180 return [prop[k] for k in keys]
181
182 mean_ints, labels, areas = np.array(Parallel(n_jobs=6)(delayed(props_of_keys)(prop, prop_keys)
183 for prop in P
184 )
185 ).T
186 del P
187 maxArea = (logSigma[1]**2)*3/4
188 minArea = (logSigma[0]**2)*3/4
189 passed = np.logical_and.reduce((
190 np.logical_and(areas > minArea, areas < maxArea),
191 np.less(mean_ints, 50)
192 ))
193
194 foregroundMask *= np.isin(foregroundMask, labels[passed])
195 np.greater(foregroundMask, 0, out=foregroundMask)
196 foregroundMask = label(foregroundMask, connectivity=1).astype(np.int32)
197
198 else:
199 if len(logSigma)==1:
200 nucleiDiameter = [logSigma*0.5, logSigma*1.5]
201 else:
202 nucleiDiameter = logSigma
203 logMask = nucleiCenters > 150
204
205 win_view_setting = WindowView(nucleiContours.shape, 2000, 500)
206
207 nucleiContours = win_view_setting.window_view_list(nucleiContours)
208 padding_mask = win_view_setting.padding_mask()
209 mask = win_view_setting.window_view_list(mask)
210
211 maxArea = (logSigma[1]**2)*3/4
212 minArea = (logSigma[0]**2)*3/4
213
214 foregroundMask = np.array(
215 Parallel(n_jobs=6)(delayed(contour_pm_watershed)(
216 img, sigma=logSigma[1]/30, h=logSigma[1]/30, tissue_mask=tm,
217 padding_mask=m, min_area=minArea, max_area=maxArea
218 ) for img, tm, m in zip(nucleiContours, mask, padding_mask))
219 )
220
221 del nucleiContours, mask
222
223 foregroundMask = win_view_setting.reconstruct(foregroundMask)
224 foregroundMask = label(foregroundMask, connectivity=1).astype(np.int32)
225
226 if nucleiFilter == 'IntPM':
227 int_img = nucleiCenters
228 elif nucleiFilter == 'Int':
229 int_img = nucleiImage
230
231 print(' ', datetime.datetime.now(), 'regionprops')
232 P = regionprops(foregroundMask, int_img)
233
234 def props_of_keys(prop, keys):
235 return [prop[k] for k in keys]
236
237 prop_keys = ['mean_intensity', 'area', 'solidity', 'label']
238 mean_ints, areas, solidities, labels = np.array(
239 Parallel(n_jobs=6)(delayed(props_of_keys)(prop, prop_keys)
240 for prop in P
241 )
242 ).T
243 del P
244
245 MITh = threshold_otsu(mean_ints)
246
247 minSolidity = 0.8
248
249 passed = np.logical_and.reduce((
250 np.greater(mean_ints, MITh),
251 np.logical_and(areas > minArea, areas < maxArea),
252 np.greater(solidities, minSolidity)
253 ))
254
255 # set failed mask label to zero
256 foregroundMask *= np.isin(foregroundMask, labels[passed])
257
258 np.greater(foregroundMask, 0, out=foregroundMask)
259 foregroundMask = label(foregroundMask, connectivity=1).astype(np.int32)
260
261 return foregroundMask
262
263 def bwmorph(mask,radius):
264 mask = np.array(mask,dtype=np.uint8)
265 #labels = label(mask)
266 background = nucleiMask == 0
267 distances, (i, j) = distance_transform_edt(background, return_indices=True)
268 cellMask = nucleiMask.copy()
269 finalmask = background & (distances <= radius)
270 cellMask[finalmask] = nucleiMask[i[finalmask], j[finalmask]]
271
272 # imshowpair(cellMask,mask)
273 return cellMask
274 # imshow(fg)
275 # fg = cv2.dilate(mask,ndimage.generate_binary_structure(2, 2))
276 # bg = 1-fg-mask
277 # imshowpair(bg,mask)
278
279 def S3CytoplasmSegmentation(nucleiMask,cyto,mask,cytoMethod='distanceTransform',radius = 5):
280 mask = (nucleiMask + resize(mask,(nucleiMask.shape[0],nucleiMask.shape[1]),order=0))>0
281 gdist = distance_transform_edt(1-(nucleiMask>0))
282 if cytoMethod == 'distanceTransform':
283 mask = np.array(mask,dtype=np.uint32)
284 markers= nucleiMask
285 elif cytoMethod == 'hybrid':
286 cytoBlur = gaussian(cyto,2)
287 c1 = uniform_filter(cytoBlur, 3, mode='reflect')
288 c2 = uniform_filter(cytoBlur*cytoBlur, 3, mode='reflect')
289 grad = np.sqrt(c2 - c1*c1)*np.sqrt(9./8)
290 grad[np.isnan(grad)]=0
291 gdist= np.sqrt(np.square(grad) + 0.000001*np.amax(grad)/np.amax(gdist)*np.square(gdist))
292 bg = binary_erosion(np.invert(mask),morphology.selem.disk(radius, np.uint8))
293 markers=nucleiMask.copy()
294 markers[bg==1] = np.amax(nucleiMask)+1
295 markers = label(markers>0,connectivity=1)
296 mask = np.ones(nucleiMask.shape)
297 del bg
298 elif cytoMethod == 'ring':
299 # mask =np.array(bwmorph(nucleiMask,radius)*mask,dtype=np.uint32)>0
300 mask =np.array(bwmorph(nucleiMask,radius),dtype=np.uint32)>0
301 markers= nucleiMask
302
303 cellMask =clear_border(watershed(gdist,markers,watershed_line=True))
304 del gdist, markers, cyto
305 cellMask = np.array(cellMask*mask,dtype=np.uint32)
306
307 finalCellMask = np.zeros(cellMask.shape,dtype=np.uint32)
308 P = regionprops(label(cellMask>0,connectivity=1),nucleiMask>0,cache=False)
309 count=0
310 for props in P:
311 if props.max_intensity>0 :
312 count += 1
313 yi = props.coords[:, 0]
314 xi = props.coords[:, 1]
315 finalCellMask[yi, xi] = count
316 nucleiMask = np.array(nucleiMask>0,dtype=np.uint32)
317 nucleiMask = finalCellMask*nucleiMask
318 cytoplasmMask = np.subtract(finalCellMask,nucleiMask)
319 return cytoplasmMask,nucleiMask,finalCellMask
320
321 def exportMasks(mask,image,outputPath,filePrefix,fileName,commit,metadata_args,saveFig=True,saveMasks = True):
322 outputPath =outputPath + os.path.sep + filePrefix
323 if not os.path.exists(outputPath):
324 os.makedirs(outputPath)
325 previewPath = outputPath + os.path.sep + 'qc'
326 if not os.path.exists(previewPath):
327 os.makedirs(previewPath)
328
329 if saveMasks ==True:
330 save_pyramid(
331 mask,
332 outputPath + os.path.sep + fileName + '.ome.tif',
333 channel_names=fileName,
334 is_mask=True,
335 **metadata_args
336 )
337 if saveFig== True:
338 mask=np.uint8(mask>0)
339 edges = find_boundaries(mask,mode = 'outer')
340 stacked_img=np.stack((np.uint16(edges)*np.amax(image),image),axis=0)
341 save_pyramid(
342 stacked_img,
343 previewPath + os.path.sep + fileName + 'Outlines.ome.tif',
344 channel_names=[f'{fileName} outlines', 'Segmentation image'],
345 is_mask=False,
346 **metadata_args
347 )
348
349 def S3punctaDetection(spotChan,mask,sigma,SD):
350 Ilog = -gaussian_laplace(np.float32(spotChan),sigma)
351 tissueMask = spotChan >0
352 fgm=peak_local_max(Ilog, indices=False,footprint=np.ones((3, 3)))*tissueMask
353 test=Ilog[fgm==1]
354 med = np.median(test)
355 mad = np.median(np.absolute(test - med))
356 thresh = med + 1.4826*SD*mad
357 return (Ilog>thresh)*fgm*(mask>0)
358
359
360
361 if __name__ == '__main__':
362 parser=argparse.ArgumentParser()
363 parser.add_argument("--imagePath")
364 parser.add_argument("--contoursClassProbPath",default ='')
365 parser.add_argument("--nucleiClassProbPath",default ='')
366 parser.add_argument("--stackProbPath",default ='')
367 parser.add_argument("--outputPath")
368 parser.add_argument("--dearrayPath")
369 parser.add_argument("--maskPath")
370 parser.add_argument("--probMapChan",type = int, default = -1)
371 parser.add_argument("--mask",choices=['TMA', 'tissue','none'],default = 'tissue')
372 parser.add_argument("--crop",choices=['interactiveCrop','autoCrop','noCrop','dearray','plate'], default = 'noCrop')
373 parser.add_argument("--cytoMethod",choices=['hybrid','distanceTransform','bwdistanceTransform','ring'],default = 'distanceTransform')
374 parser.add_argument("--nucleiFilter",choices=['IntPM','LoG','Int','none'],default = 'IntPM')
375 parser.add_argument("--nucleiRegion",choices=['watershedContourDist','watershedContourInt','watershedBWDist','dilation','localThreshold','localMax','bypass','pixellevel'], default = 'watershedContourInt')
376 parser.add_argument("--pixelThreshold",type = float, default = -1)
377 parser.add_argument("--segmentCytoplasm",choices = ['segmentCytoplasm','ignoreCytoplasm'],default = 'ignoreCytoplasm')
378 parser.add_argument("--cytoDilation",type = int, default = 5)
379 parser.add_argument("--logSigma",type = int, nargs = '+', default = [3, 60])
380 parser.add_argument("--CytoMaskChan",type=int, nargs = '+', default=[2])
381 parser.add_argument("--pixelMaskChan",type=int, nargs = '+', default=[2])
382 parser.add_argument("--TissueMaskChan",type=int, nargs = '+', default=0)
383 parser.add_argument("--detectPuncta",type=int, nargs = '+', default=[0])
384 parser.add_argument("--punctaSigma", nargs = '+', type=float, default=[0])
385 parser.add_argument("--punctaSD", nargs = '+', type=float, default=[4])
386 parser.add_argument("--saveMask",action='store_false')
387 parser.add_argument("--saveFig",action='store_false')
388 args = parser.parse_args()
389
390 imagePath = args.imagePath
391 outputPath = args.outputPath
392 nucleiClassProbPath = args.nucleiClassProbPath
393 contoursClassProbPath = args.contoursClassProbPath
394 stackProbPath = args.stackProbPath
395 maskPath = args.maskPath
396
397 commit = '1.3.11'#subprocess.check_output(['git', 'describe', '--tags']).decode('ascii').strip()
398 metadata = getMetadata(imagePath,commit)
399
400 fileName = os.path.basename(imagePath)
401 filePrefix = fileName[0:fileName.index('.')]
402
403 # convert 1-based indexing to 0-based indexing
404 CytoMaskChan = args.CytoMaskChan
405 CytoMaskChan[:] = [number - 1 for number in CytoMaskChan]
406 pixelMaskChan = args.pixelMaskChan
407 pixelMaskChan[:] = [number - 1 for number in pixelMaskChan]
408
409
410 if not os.path.exists(outputPath):
411 os.makedirs(outputPath)
412
413
414 # get channel used for nuclei segmentation
415
416 if len(contoursClassProbPath)>0:
417 legacyMode = 1
418 probPrefix = os.path.basename(contoursClassProbPath)
419 nucMaskChan = int(probPrefix.split('ContoursPM_')[1].split('.')[0])
420 elif len(stackProbPath)>0:
421 legacyMode = 0
422 probPrefix = os.path.basename(stackProbPath)
423 else:
424 print('NO PROBABILITY MAP PROVIDED')
425
426 if args.probMapChan==-1:
427 print('Using first channel by default!')
428 nucMaskChan = 0
429 else:
430 nucMaskChan = args.probMapChan
431 nucMaskChan = nucMaskChan -1 #convert 1-based indexing to 0-based indexing
432
433 if args.TissueMaskChan==0:
434 TissueMaskChan = copy.copy(CytoMaskChan)
435 TissueMaskChan.append(nucMaskChan)
436 else:
437 TissueMaskChan = args.TissueMaskChan[:]
438 TissueMaskChan[:] = [number - 1 for number in TissueMaskChan]#convert 1-based indexing to 0-based indexing
439 TissueMaskChan.append(nucMaskChan)
440
441 #crop images if needed
442 if args.crop == 'interactiveCrop':
443 nucleiCrop = tifffile.imread(imagePath,key = nucMaskChan)
444 r=cv2.selectROI(resize(nucleiCrop,(nucleiCrop.shape[0] // 30, nucleiCrop.shape[1] // 30)))
445 cv2.destroyWindow('select')
446 rect=np.transpose(r)*30
447 PMrect= [rect[1], rect[0], rect[3], rect[2]]
448 nucleiCrop = nucleiCrop[int(rect[1]):int(rect[1]+rect[3]), int(rect[0]):int(rect[0]+rect[2])]
449 elif args.crop == 'noCrop' or args.crop == 'dearray' or args.crop == 'plate':
450 nucleiCrop = tifffile.imread(imagePath,key = nucMaskChan)
451 rect = [0, 0, nucleiCrop.shape[0], nucleiCrop.shape[1]]
452 PMrect= rect
453 elif args.crop == 'autoCrop':
454 nucleiCrop = tifffile.imread(imagePath,key = nucMaskChan)
455 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)]
456 PMrect= rect
457 nucleiCrop = nucleiCrop[int(rect[0]):int(rect[0]+rect[2]), int(rect[1]):int(rect[1]+rect[3])]
458
459 if legacyMode ==1:
460 nucleiProbMaps = tifffile.imread(nucleiClassProbPath,key=0)
461 nucleiPM = nucleiProbMaps[int(PMrect[0]):int(PMrect[0]+PMrect[2]), int(PMrect[1]):int(PMrect[1]+PMrect[3])]
462 nucleiProbMaps = tifffile.imread(contoursClassProbPath,key=0)
463 PMSize = nucleiProbMaps.shape
464 nucleiPM = np.dstack((nucleiPM,nucleiProbMaps[int(PMrect[0]):int(PMrect[0]+PMrect[2]), int(PMrect[1]):int(PMrect[1]+PMrect[3])]))
465 else:
466 nucleiProbMaps = imread(stackProbPath)
467 if len(nucleiProbMaps.shape)==2:
468 nucleiPM = nucleiProbMaps[int(PMrect[0]):int(PMrect[0]+PMrect[2]), int(PMrect[1]):int(PMrect[1]+PMrect[3])]
469 else:
470 nucleiPM = nucleiProbMaps[int(PMrect[0]):int(PMrect[0]+PMrect[2]), int(PMrect[1]):int(PMrect[1]+PMrect[3]),:]
471 PMSize = nucleiProbMaps.shape
472
473 # mask the core/tissue
474 if args.crop == 'dearray':
475 TMAmask = tifffile.imread(maskPath)
476 elif args.crop =='plate':
477 TMAmask = np.ones(nucleiCrop.shape)
478
479 else:
480 tissue = np.empty((len(TissueMaskChan),nucleiCrop.shape[0],nucleiCrop.shape[1]),dtype=np.uint16)
481 count=0
482 if args.crop == 'noCrop':
483 for iChan in TissueMaskChan:
484 tissueCrop =tifffile.imread(imagePath,key=iChan)
485 tissue_gauss = gaussian(tissueCrop,1)
486 #tissue_gauss[tissue_gauss==0]=np.nan
487 tissue[count,:,:] =np.log2(tissue_gauss+1)>threshold_otsu(np.log2(tissue_gauss+1))
488 count+=1
489 else:
490 for iChan in TissueMaskChan:
491 tissueCrop = tifffile.imread(imagePath,key=iChan)
492 tissue_gauss = gaussian(tissueCrop[int(PMrect[0]):int(PMrect[0]+PMrect[2]), int(PMrect[1]):int(PMrect[1]+PMrect[3])],1)
493 tissue[count,:,:] = np.log2(tissue_gauss+1)>threshold_otsu(np.log2(tissue_gauss+1))
494 count+=1
495 TMAmask = np.max(tissue,axis = 0)
496
497
498 del tissue_gauss, tissue
499
500 # nuclei segmentation
501 if args.nucleiRegion == 'pixellevel':
502 pixelTissue = np.empty((len(pixelMaskChan),nucleiCrop.shape[0],nucleiCrop.shape[1]),dtype=np.uint16)
503 count=0
504 for iChan in pixelMaskChan:
505 pixelCrop = tifffile.imread(imagePath,key=iChan)
506 pixelTissue[count,:,:] = pixelCrop[int(PMrect[0]):int(PMrect[0]+PMrect[2]), int(PMrect[1]):int(PMrect[1]+PMrect[3])]
507 count+=1
508 nucleiMask = S3AreaSegmenter(nucleiPM, pixelTissue, TMAmask,args.pixelThreshold,filePrefix,outputPath)
509 elif args.nucleiRegion == 'bypass':
510 nucleiMask = S3NucleiBypass(nucleiPM,nucleiCrop,args.logSigma,TMAmask,args.nucleiFilter,args.nucleiRegion)
511 else:
512 nucleiMask = S3NucleiSegmentationWatershed(nucleiPM,nucleiCrop,args.logSigma,TMAmask,args.nucleiFilter,args.nucleiRegion)
513 del nucleiPM
514 # cytoplasm segmentation
515 if args.segmentCytoplasm == 'segmentCytoplasm':
516 count =0
517 if args.crop == 'noCrop' or args.crop == 'dearray' or args.crop == 'plate':
518 cyto=np.empty((len(CytoMaskChan),nucleiCrop.shape[0],nucleiCrop.shape[1]),dtype=np.uint16)
519 for iChan in CytoMaskChan:
520 cyto[count,:,:] = tifffile.imread(imagePath, key=iChan)
521 count+=1
522 elif args.crop =='autoCrop':
523 cyto=np.empty((len(CytoMaskChan),int(rect[2]),int(rect[3])),dtype=np.int16)
524 for iChan in CytoMaskChan:
525 cytoFull= tifffile.imread(imagePath, key=iChan)
526 cyto[count,:,:] = cytoFull[int(PMrect[0]):int(PMrect[0]+PMrect[2]), int(PMrect[1]):int(PMrect[1]+PMrect[3])]
527 count+=1
528 else:
529 cyto=np.empty((len(CytoMaskChan),rect[3],rect[2]),dtype=np.int16)
530 for iChan in CytoMaskChan:
531 cytoFull= tifffile.imread(imagePath, key=iChan)
532 cyto[count,:,:] = cytoFull[int(PMrect[0]):int(PMrect[0]+PMrect[2]), int(PMrect[1]):int(PMrect[1]+PMrect[3])]
533 count+=1
534 cyto = np.amax(cyto,axis=0)
535 cytoplasmMask,nucleiMaskTemp,cellMask = S3CytoplasmSegmentation(nucleiMask,cyto,TMAmask,args.cytoMethod,args.cytoDilation)
536 exportMasks(nucleiMaskTemp,nucleiCrop,outputPath,filePrefix,'nuclei',commit,metadata,args.saveFig,args.saveMask)
537 exportMasks(cytoplasmMask,cyto,outputPath,filePrefix,'cyto',commit,metadata,args.saveFig,args.saveMask)
538 exportMasks(cellMask,cyto,outputPath,filePrefix,'cell',commit,metadata,args.saveFig,args.saveMask)
539
540 cytoplasmMask,nucleiMaskTemp,cellMask = S3CytoplasmSegmentation(nucleiMask,cyto,TMAmask,'ring',args.cytoDilation)
541 exportMasks(nucleiMaskTemp,nucleiCrop,outputPath,filePrefix,'nucleiRing',commit,metadata,args.saveFig,args.saveMask)
542 exportMasks(cytoplasmMask,cyto,outputPath,filePrefix,'cytoRing',commit,metadata,args.saveFig,args.saveMask)
543 exportMasks(cellMask,cyto,outputPath,filePrefix,'cellRing',commit,metadata,args.saveFig,args.saveMask)
544
545 elif args.segmentCytoplasm == 'ignoreCytoplasm':
546 exportMasks(nucleiMask,nucleiCrop,outputPath,filePrefix,'nuclei',commit,metadata)
547 cellMask = nucleiMask
548 exportMasks(nucleiMask,nucleiCrop,outputPath,filePrefix,'cell',commit,metadata)
549 cytoplasmMask = nucleiMask
550
551 detectPuncta = args.detectPuncta
552 if (np.min(detectPuncta)>0):
553 detectPuncta[:] = [number - 1 for number in detectPuncta] #convert 1-based indexing to 0-based indexing
554 if len(detectPuncta) != len(args.punctaSigma):
555 args.punctaSigma = args.punctaSigma[0] * np.ones(len(detectPuncta))
556
557
558 if len(detectPuncta) != len(args.punctaSD):
559 args.punctaSD = args.punctaSD[0] * np.ones(len(detectPuncta))
560
561 counter=0
562 for iPunctaChan in detectPuncta:
563 punctaChan = tifffile.imread(imagePath,key = iPunctaChan)
564 punctaChan = punctaChan[int(PMrect[0]):int(PMrect[0]+PMrect[2]), int(PMrect[1]):int(PMrect[1]+PMrect[3])]
565 spots=S3punctaDetection(punctaChan,cellMask,args.punctaSigma[counter],args.punctaSD[counter])
566 cellspotmask = nucleiMask
567 P = regionprops(cellspotmask,intensity_image = spots ,cache=False)
568 numSpots = []
569 for prop in P:
570 numSpots.append(np.uint16(np.round(prop.mean_intensity * prop.area)))
571 np.savetxt(outputPath + os.path.sep + 'numSpots_chan' + str(iPunctaChan+1) +'.csv',(np.transpose(np.asarray(numSpots))),fmt='%10.5f')
572 edges = 1-(cellMask>0)
573 stacked_img=np.stack((np.uint16((spots+edges)>0)*np.amax(punctaChan),punctaChan),axis=0)
574
575
576 outputPathPuncta = outputPath + os.path.sep + filePrefix + os.path.sep + 'punctaChan'+str(iPunctaChan+1) + 'Outlines.ome.tif'
577
578 # metadata_args = dict(
579 # pixel_sizes=(metadata.physical_size_y, metadata.physical_size_x),
580 # pixel_size_units=('µm', 'µm'),
581 # software= 's3segmenter v' + commit
582 # )
583 save_pyramid(
584 stacked_img,
585 outputPathPuncta,
586 channel_names=['puncta outlines', 'image channel'],
587 is_mask=False,
588 **metadata
589 )
590
591 counter=counter+1
592