Mercurial > repos > perssond > s3segmenter
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 |
