diff UNetCoreograph.py @ 1:57f1260ca94e draft

"planemo upload commit fec9dc76b3dd17b14b02c2f04be9d30f71eba1ae"
author watsocam
date Fri, 11 Mar 2022 23:40:51 +0000
parents 99308601eaa6
children
line wrap: on
line diff
--- a/UNetCoreograph.py	Wed May 19 21:34:38 2021 +0000
+++ b/UNetCoreograph.py	Fri Mar 11 23:40:51 2022 +0000
@@ -3,6 +3,9 @@
 import shutil
 import scipy.io as sio
 import os
+os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
+import logging
+logging.getLogger('tensorflow').setLevel(logging.FATAL)
 import skimage.exposure as sk
 import cv2
 import argparse
@@ -14,10 +17,11 @@
 from skimage.segmentation import chan_vese, find_boundaries, morphological_chan_vese
 from skimage.measure import regionprops,label, find_contours
 from skimage.transform import resize
-from skimage.filters import gaussian
+from skimage.filters import gaussian, threshold_otsu
 from skimage.feature import peak_local_max,blob_log
-from skimage.color import label2rgb
+from skimage.color import gray2rgb as gray2rgb
 import skimage.io as skio
+from scipy.ndimage.morphology import binary_fill_holes
 from skimage import img_as_bool
 from skimage.draw import circle_perimeter
 from scipy.ndimage.filters import uniform_filter
@@ -525,27 +529,27 @@
 
 
 def identifyNumChan(path):
-   tiff = tifffile.TiffFile(path)
-   shape = tiff.pages[0].shape
-   numChan=None
-   for i, page in enumerate(tiff.pages):
-      if page.shape != shape:
-         numChan = i
-         return numChan
-         break
-#      else:
-#         raise Exception("Did not find any pyramid subresolutions") 
 
-   if not numChan:
-      numChan = len(tiff.pages)
-      return numChan
+	s = tifffile.TiffFile(path).series[0]
+	return s.shape[0] if len(s.shape) > 2 else 1
+   # shape = tiff.pages[0].shape
+   # tiff = tifffile.TiffFile(path)
+   # for i, page in enumerate(tiff.pages):
+	#    print(page.shape)
+	#    if page.shape != shape:
+	# 	   numChan = i
+	# 	   return numChan
+	# 	   break
+#	   else:
+#		   raise Exception("Did not find any pyramid subresolutions") 
+
 
 def getProbMaps(I,dsFactor,modelPath):
    hsize = int((float(I.shape[0]) * float(0.5)))
    vsize = int((float(I.shape[1]) * float(0.5)))
    imagesub = cv2.resize(I,(vsize,hsize),cv2.INTER_NEAREST)
 
-   UNet2D.singleImageInferenceSetup(modelPath, 1)
+   UNet2D.singleImageInferenceSetup(modelPath, 0)
 
    for iSize in range(dsFactor):
 	   hsize = int((float(I.shape[0]) * float(0.5)))
@@ -557,42 +561,22 @@
    UNet2D.singleImageInferenceCleanup()
    return probMaps 
 
-def coreSegmenterOutput(I,probMap,initialmask,preBlur,findCenter):
+def coreSegmenterOutput(I,initialmask,findCenter):
 	hsize = int((float(I.shape[0]) * float(0.1)))
 	vsize = int((float(I.shape[1]) * float(0.1)))
 	nucGF = cv2.resize(I,(vsize,hsize),cv2.INTER_CUBIC)
-#	Irs = cv2.resize(I,(vsize,hsize),cv2.INTER_CUBIC)
-#	I=I.astype(np.float)
-#	r,c = I.shape
-#	I+=np.random.rand(r,c)*1e-6
-#	c1 = uniform_filter(I, 3, mode='reflect')
-#	c2 = uniform_filter(I*I, 3, mode='reflect')
-#	nucGF = np.sqrt(c2 - c1*c1)*np.sqrt(9./8)
-#	nucGF[np.isnan(nucGF)]=0
 	#active contours
 	hsize = int(float(nucGF.shape[0]))
 	vsize = int(float(nucGF.shape[1]))
 	initialmask = cv2.resize(initialmask,(vsize,hsize),cv2.INTER_NEAREST)
 	initialmask = dilation(initialmask,disk(15)) >0
-		
-#	init=np.argwhere(eroded>0)
+
 	nucGF = gaussian(nucGF,0.7)
 	nucGF=nucGF/np.amax(nucGF)
 	
-   
-#	initialmask = nucGF>0
 	nuclearMask = morphological_chan_vese(nucGF, 100, init_level_set=initialmask, smoothing=10,lambda1=1.001, lambda2=1)
 	
-#	nuclearMask = chan_vese(nucGF, mu=1.5, lambda1=6, lambda2=1, tol=0.0005, max_iter=2000, dt=15, init_level_set=initialmask, extended_output=True)	
-#	nuclearMask = nuclearMask[0]
-  
-	
 	TMAmask = nuclearMask
-#	nMaskDist =distance_transform_edt(nuclearMask)
-#	fgm = peak_local_max(h_maxima(nMaskDist, 2*preBlur),indices =False)
-#	markers= np.logical_or(erosion(1-nuclearMask,disk(3)),fgm)
-#	TMAmask=watershed(-nMaskDist,label(markers),watershed_line=True)
-#	TMAmask = nuclearMask*(TMAmask>0)
 	TMAmask = remove_small_objects(TMAmask>0,round(TMAmask.shape[0])*round(TMAmask.shape[1])*0.005)
 	TMAlabel = label(TMAmask)
 # find object closest to center
@@ -632,7 +616,8 @@
 	parser.add_argument("--imagePath")
 	parser.add_argument("--outputPath")
 	parser.add_argument("--maskPath")
-	parser.add_argument("--downsampleFactor",type = int, default = 5)
+	parser.add_argument("--tissue", action='store_true')
+	parser.add_argument("--downsampleFactor", type=int, default = 5)
 	parser.add_argument("--channel",type = int, default = 0)
 	parser.add_argument("--buffer",type = float, default = 2)
 	parser.add_argument("--outputChan", type=int, nargs = '+', default=[-1])
@@ -642,25 +627,11 @@
 	args = parser.parse_args()
 
 	outputPath = args.outputPath
-	imagePath = args.imagePath
+	imagePath =  args.imagePath
 	sensitivity = args.sensitivity
-	#scriptPath = os.path.dirname(os.path.realpath(__file__))
-	#modelPath = os.path.join(scriptPath, 'TFModel - 3class 16 kernels 5ks 2 layers')
-	#modelPath = 'D:\\LSP\\Coreograph\\model-4layersMaskAug20'
 	scriptPath = os.path.dirname(os.path.realpath(__file__))
 	modelPath = os.path.join(scriptPath, 'model')
-#	outputPath = 'D:\\LSP\\cycif\\testsets\\exemplar-002\\dearrayPython' ############
 	maskOutputPath = os.path.join(outputPath, 'masks')
-#	imagePath = 'D:\\LSP\\cycif\\testsets\\exemplar-002\\registration\\exemplar-002.ome.tif'###########
-#	imagePath = 'Y:\\sorger\\data\\RareCyte\\Connor\\TMAs\\CAJ_TMA11_13\\original_data\\TMA11\\registration\\TMA11.ome.tif'
-#	imagePath = 'Y:\\sorger\\data\\RareCyte\\Connor\\TMAs\\Z124_TMA20_22\\TMA22\\registration\\TMA22.ome.tif'
-#	classProbsPath = 'D:\\unetcoreograph.tif'
-#	imagePath = 'Y:\\sorger\\data\\RareCyte\\Connor\\Z155_PTCL\\TMA_552\\registration\\TMA_552.ome.tif'
-#	classProbsPath = 'Y:\\sorger\\data\\RareCyte\\Connor\\Z155_PTCL\\TMA_552\\probMapCore\\TMA_552_CorePM_1.tif'
-#	imagePath = 'Y:\\sorger\\data\\RareCyte\\Zoltan\\Z112_TMA17_19\\190403_ashlar\\TMA17_1092.ome.tif'
-#	classProbsPath = 'Z:\\IDAC\\Clarence\\LSP\\CyCIF\\TMA\\probMapCore\\1new_CorePM_1.tif'
-#	imagePath = 'Y:\\sorger\\data\\RareCyte\\ANNIINA\\Julia\\2018\\TMA6\\julia_tma6.ome.tif'
-#	classProbsPath = 'Z:\\IDAC\\Clarence\\LSP\\CyCIF\\TMA\\probMapCore\\3new_CorePM_1.tif'
 
 	
 #	if not os.path.exists(outputPath):
@@ -669,65 +640,85 @@
 #		shutil.rmtree(outputPath)
 	if not os.path.exists(maskOutputPath):
 		os.makedirs(maskOutputPath)
-
-
-	channel = args.channel 
+	print(
+		'WARNING! IF USING FOR TISSUE SPLITTING, IT IS ADVISED TO SET --downsampleFactor TO HIGHER THAN DEFAULT OF 5')
+	channel = args.channel
 	dsFactor = 1/(2**args.downsampleFactor)
-#	I = tifffile.imread(imagePath, key=channel)
 	I = skio.imread(imagePath, img_num=channel)
-
 	imagesub = resize(I,(int((float(I.shape[0]) * dsFactor)),int((float(I.shape[1]) * dsFactor))))
 	numChan = identifyNumChan(imagePath)
-	
+
 	outputChan = args.outputChan
 	if len(outputChan)==1:
 		if outputChan[0]==-1:
 			outputChan = [0, numChan-1]
 		else:
 			outputChan.append(outputChan[0])
-	
-	classProbs = getProbMaps(I,args.downsampleFactor,modelPath)
-#	classProbs = tifffile.imread(classProbsPath,key=0)
-	preMask = gaussian(np.uint8(classProbs*255),1)>0.8
-	
-	P = regionprops(label(preMask),cache=False)
-	area = [ele.area for ele in P]
-	print(str(len(P)) + ' cores detected!')
-	if len(P) <3:
-		medArea = np.median(area)
-		maxArea = np.percentile(area,99)
+	classProbs = getProbMaps(I, args.downsampleFactor, modelPath)
+
+	if not args.tissue:
+		print('TMA mode selected')
+		preMask = gaussian(np.uint8(classProbs*255),1)>0.8
+
+		P = regionprops(label(preMask),cache=False)
+		area = [ele.area for ele in P]
+		if len(P) <3:
+			medArea = np.median(area)
+			maxArea = np.percentile(area,99)
+		else:
+			count=0
+			labelpreMask = np.zeros(preMask.shape,dtype=np.uint32)
+			for props in P:
+					count += 1
+					yi = props.coords[:, 0]
+					xi = props.coords[:, 1]
+					labelpreMask[yi, xi] = count
+					P=regionprops(labelpreMask)
+					area = [ele.area for ele in P]
+			medArea =  np.median(area)
+			maxArea = np.percentile(area,99)
+		preMask = remove_small_objects(preMask,0.2*medArea)
+		coreRad = round(np.sqrt(medArea/np.pi))
+		estCoreDiam = round(np.sqrt(maxArea/np.pi)*1.2*args.buffer)
+
+		#preprocessing
+		fgFiltered = blob_log(preMask,coreRad*0.6,threshold=sensitivity)
+		Imax = np.zeros(preMask.shape,dtype=np.uint8)
+		for iSpot in range(fgFiltered.shape[0]):
+			yi = np.uint32(round(fgFiltered[iSpot, 0]))
+			xi = np.uint32(round(fgFiltered[iSpot, 1]))
+			Imax[yi, xi] = 1
+		Imax = Imax*preMask
+		Idist = distance_transform_edt(1-Imax)
+		markers = label(Imax)
+		coreLabel  = watershed(Idist,markers,watershed_line=True,mask = preMask)
+		P = regionprops(coreLabel)
+		centroids = np.array([ele.centroid for ele in P]) / dsFactor
+		np.savetxt(outputPath + os.path.sep + 'centroidsY-X.txt', np.asarray(centroids), fmt='%10.5f')
+		numCores = len(centroids)
+		print(str(numCores) + ' cores detected!')
+		estCoreDiamX = np.ones(numCores) * estCoreDiam / dsFactor
+		estCoreDiamY = np.ones(numCores) * estCoreDiam / dsFactor
 	else:
-		count=0
-		labelpreMask = np.zeros(preMask.shape,dtype=np.uint32)
-		for props in P:
-				count += 1
-				yi = props.coords[:, 0]
-				xi = props.coords[:, 1]
-				labelpreMask[yi, xi] = count              
-				P=regionprops(labelpreMask)
-				area = [ele.area for ele in P]
-		medArea =  np.median(area)
-		maxArea = np.percentile(area,99)
-	preMask = remove_small_objects(preMask,0.2*medArea)
-	coreRad = round(np.sqrt(medArea/np.pi))
-	estCoreDiam = round(np.sqrt(maxArea/np.pi)*1.2*args.buffer)
+		print('Tissue mode selected')
+		imageblur = 5
+		Iblur = gaussian(np.uint8(255*classProbs), imageblur)
+		coreMask = binary_fill_holes(binary_closing(Iblur > threshold_otsu(Iblur), np.ones((imageblur*2,imageblur*2))))
+		coreMask = remove_small_objects(coreMask, min_size=0.001 * coreMask.shape[0] * coreMask.shape[1])
 
-#preprocessing
-	fgFiltered = blob_log(preMask,coreRad*0.6,threshold=sensitivity)
-	Imax = np.zeros(preMask.shape,dtype=np.uint8)
-	for iSpot in range(fgFiltered.shape[0]):
-		yi = np.uint32(round(fgFiltered[iSpot, 0]))
-		xi = np.uint32(round(fgFiltered[iSpot, 1]))
-		Imax[yi, xi] = 1
-	Imax = Imax*preMask
-	Idist = distance_transform_edt(1-Imax)
-	markers = label(Imax)
-	coreLabel  = watershed(Idist,markers,watershed_line=True,mask = preMask)
-	P = regionprops(coreLabel)
-	centroids = np.array([ele.centroid for ele in P])/dsFactor
-	numCores = len(centroids)
-	estCoreDiamX = np.ones(numCores)*estCoreDiam/dsFactor
-	estCoreDiamY = np.ones(numCores)*estCoreDiam/dsFactor
+		## watershed
+		Idist = distance_transform_edt(coreMask)
+		markers = peak_local_max(h_maxima(Idist,20),indices=False)
+		markers = label(markers).astype(np.int8)
+		coreLabel = watershed(-Idist, markers, watershed_line=True,mask = coreMask)
+
+		P = regionprops(coreLabel)
+		centroids = np.array([ele.centroid for ele in P]) / dsFactor
+		np.savetxt(outputPath + os.path.sep + 'centroidsY-X.txt', np.asarray(centroids), fmt='%10.5f')
+		numCores = len(centroids)
+		print(str(numCores) + ' tissues detected!')
+		estCoreDiamX = np.array([(ele.bbox[3]-ele.bbox[1])*1.1 for ele in P]) / dsFactor
+		estCoreDiamY = np.array([(ele.bbox[2]-ele.bbox[0])*1.1 for ele in P]) / dsFactor
 
 	if numCores ==0 & args.cluster:
 		print('No cores detected. Try adjusting the downsample factor')
@@ -736,8 +727,9 @@
 	singleMaskTMA = np.zeros(imagesub.shape)
 	maskTMA = np.zeros(imagesub.shape)
 	bbox = [None] * numCores
-
- 
+	imagesub = imagesub/np.percentile(imagesub,99.9)
+	imagesub = (imagesub * 255).round().astype(np.uint8)
+	imagesub = gray2rgb(imagesub)
 	x=np.zeros(numCores)
 	xLim=np.zeros(numCores)
 	y=np.zeros(numCores)
@@ -761,24 +753,31 @@
 			y[iCore]=1
 
 		bbox[iCore] = [round(x[iCore]), round(y[iCore]), round(xLim[iCore]), round(yLim[iCore])]
-		
+		coreStack = np.zeros((outputChan[1]-outputChan[0]+1,np.int(round(yLim[iCore])-round(y[iCore])-1),np.int(round(xLim[iCore])-round(x[iCore])-1)),dtype='uint16')
+
 		for iChan in range(outputChan[0],outputChan[1]+1):
 			with pytiff.Tiff(imagePath, "r", encoding='utf-8') as handle:
 				handle.set_page(iChan)
-				coreStack= handle[np.uint32(bbox[iCore][1]):np.uint32(bbox[iCore][3]-1), np.uint32(bbox[iCore][0]):np.uint32(bbox[iCore][2]-1)]
-			skio.imsave(outputPath + os.path.sep + str(iCore+1)  + '.tif',coreStack,append=True)	
+				coreStack[iChan,:,:] =handle[np.uint32(bbox[iCore][1]):np.uint32(bbox[iCore][3]-1), np.uint32(bbox[iCore][0]):np.uint32(bbox[iCore][2]-1)]
 
+		skio.imsave(outputPath + os.path.sep + str(iCore+1)  + '.tif',np.uint16(coreStack),imagej=True,bigtiff=True)
 		with pytiff.Tiff(imagePath, "r", encoding='utf-8') as handle:
 			handle.set_page(args.channel)
 			coreSlice= handle[np.uint32(bbox[iCore][1]):np.uint32(bbox[iCore][3]-1), np.uint32(bbox[iCore][0]):np.uint32(bbox[iCore][2]-1)]
 
 		core = (coreLabel ==(iCore+1))
-		initialmask = core[np.uint32(y[iCore]*dsFactor):np.uint32(yLim[iCore]*dsFactor),np.uint32(x[iCore]*dsFactor):np.uint32(xLim[iCore]*dsFactor)]
-		initialmask = resize(initialmask,size(coreSlice),cv2.INTER_NEAREST)
+		initialmask = core[np.uint32(y[iCore] * dsFactor):np.uint32(yLim[iCore] * dsFactor),
+					  np.uint32(x[iCore] * dsFactor):np.uint32(xLim[iCore] * dsFactor)]
+		if not args.tissue:
+			initialmask = resize(initialmask,size(coreSlice),cv2.INTER_NEAREST)
 
-		singleProbMap = classProbs[np.uint32(y[iCore]*dsFactor):np.uint32(yLim[iCore]*dsFactor),np.uint32(x[iCore]*dsFactor):np.uint32(xLim[iCore]*dsFactor)]
-		singleProbMap = resize(np.uint8(255*singleProbMap),size(coreSlice),cv2.INTER_NEAREST)
-		TMAmask = coreSegmenterOutput(coreSlice,singleProbMap,initialmask,coreRad/20,False) 
+			singleProbMap = classProbs[np.uint32(y[iCore]*dsFactor):np.uint32(yLim[iCore]*dsFactor),np.uint32(x[iCore]*dsFactor):np.uint32(xLim[iCore]*dsFactor)]
+			singleProbMap = resize(np.uint8(255*singleProbMap),size(coreSlice),cv2.INTER_NEAREST)
+			TMAmask = coreSegmenterOutput(coreSlice,initialmask,False)
+		else:
+			Irs = resize(coreSlice,(int((float(coreSlice.shape[0]) * 0.25)),int((float(coreSlice.shape[1]) * 0.25))))
+			TMAmask = coreSegmenterOutput(Irs, np.uint8(initialmask), False)
+
 		if np.sum(TMAmask)==0:
 			TMAmask = np.ones(TMAmask.shape)
 		vsize = int(float(coreSlice.shape[0]))
@@ -786,17 +785,16 @@
 		masksub = resize(resize(TMAmask,(vsize,hsize),cv2.INTER_NEAREST),(int((float(coreSlice.shape[0])*dsFactor)),int((float(coreSlice.shape[1])*dsFactor))),cv2.INTER_NEAREST)
 		singleMaskTMA[int(y[iCore]*dsFactor):int(y[iCore]*dsFactor)+masksub.shape[0],int(x[iCore]*dsFactor):int(x[iCore]*dsFactor)+masksub.shape[1]]=masksub
 		maskTMA = maskTMA + resize(singleMaskTMA,maskTMA.shape,cv2.INTER_NEAREST)
-		cv2.putText(imagesub, str(iCore+1), (int(P[iCore].centroid[1]),int(P[iCore].centroid[0])), 0, 0.5, (np.amax(imagesub), np.amax(imagesub), np.amax(imagesub)), 1, cv2.LINE_AA)
+
+		cv2.putText(imagesub, str(iCore+1), (int(P[iCore].centroid[1]),int(P[iCore].centroid[0])), 0, 0.5, (0,255,0), 1, cv2.LINE_AA)
 		
 		skio.imsave(maskOutputPath + os.path.sep + str(iCore+1)  + '_mask.tif',np.uint8(TMAmask))
-		print('Segmented core ' + str(iCore+1))	
+		print('Segmented core/tissue ' + str(iCore+1))
 		
 	boundaries = find_boundaries(maskTMA)
-	imagesub = imagesub/np.percentile(imagesub,99.9)
-	imagesub[boundaries==1] = 1
-	skio.imsave(outputPath + os.path.sep + 'TMA_MAP.tif' ,np.uint8(imagesub*255))
-	print('Segmented all cores!')
-	
+	imagesub[boundaries==1] = 255
+	skio.imsave(outputPath + os.path.sep + 'TMA_MAP.tif' ,imagesub)
+	print('Segmented all cores/tissues!')
 
 #restore GPU to 0
 	#image load using tifffile