-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBinary-Mask-Generator.py
144 lines (118 loc) · 6.14 KB
/
Binary-Mask-Generator.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# -*- coding: utf-8 -*-
"""
Created on Fri Nov 10 12:57:38 2023
@author: Olivier-Rukundo - Modifications by [email protected] - Olivier Rukundo Ph.D.
"""
# @original script: https://github.com/ruchikaverma-iitg/MoNuSAC/blob/master/Binary_mask_generation.ipynb
# Errors generated by the original script: ValueError: A linearring requires at least 4 coordinates.
# Corrections or updates made (see lines):
# if len(regions[0]) >= 4:
# poly = Polygon(regions[0])
.
.
.
# else:
# print("Skipping creation of Polygon. Insufficient coordinates.")
# Additional problems with the original script: The original script saved images as .tif format, which resulted in huge size of saved masks and masks without metadata.
# Additional updates: I consided using a more common format (like PNG) to automatically handle metadata more consistently with our expectations (see lines):
# cv2.imwrite(sub_image_loc[:-4]+'.png', np.array(img.read_region((0,0),0,img.level_dimensions[0])))
# mask_path = sub_path+'/'+str(count)+'_mask.png'
import os # OR added this to find the openslide DLL file
os.add_dll_directory(r'C:\Users\...\openslide-win64-20231011\openslide-win64-20231011\bin')
#Process whole slide images
# import os
import openslide
# from xml.dom import minidom
import numpy as np
# import openslide
# from openslide import open_slide
from glob import glob
import cv2
# import matplotlib.pyplot as plt
# import scipy.io as sio
# from PIL import Image
# import scipy
# import scipy.ndimage
from shapely.geometry import Polygon
from skimage import draw
import xml.etree.ElementTree as ET
# Read svs files from the desired path
count = 0
data_path = r'C:\Users\...\TestingData\MoNuSAC Testing Data and Annotations' #Path to read data from
destination_path = r'C:\Users\...\BinaryMaskTestData' # Path to save binary masks corresponding to xml files
os.chdir(destination_path)
try:
os.mkdir(destination_path+'\MoNuSAC_masks')
except OSError:
print ("Creation of the mask directory %s failed" % destination_path)
os.chdir(destination_path+'\MoNuSAC_masks')#Create folder named as MoNuSAC_masks
patients = [x[0] for x in os.walk(data_path)]#Total patients in the data_path
len(patients)
for patient_loc in patients:
patient_name = patient_loc[len(data_path)+1:]#Patient name
print(patient_name)
## To make patient's name directory in the destination folder
try:
os.mkdir(patient_name)
except OSError:
print ("\n Creation of the patient's directory %s failed" % patient_name)
## Read sub-images of each patient in the data path
sub_images = glob(patient_loc+'/*.svs')
for sub_image_loc in sub_images:
sub_image_name = sub_image_loc[len(data_path)+len(patient_name)+1:-4]
print(sub_image_name)
## To make sub_image directory under the patient's folder
sub_image = './'+patient_name+'/'+sub_image_name #Destination path
try:
os.mkdir(sub_image)
except OSError:
print ("\n Creation of the patient's directory %s failed" % sub_image)
image_name = sub_image_loc
img = openslide.OpenSlide(image_name)
# If svs image needs to save in tif
cv2.imwrite(sub_image_loc[:-4]+'.png', np.array(img.read_region((0,0),0,img.level_dimensions[0])))
# Read xml file
xml_file_name = image_name[:-4]
xml_file_name = xml_file_name+'.xml'
tree = ET.parse(xml_file_name)
root = tree.getroot()
#Generate binary mask for each cell-type
for k in range(len(root)):
label = [x.attrib['Name'] for x in root[k][0]]
label = label[0]
for child in root[k]:
for x in child:
r = x.tag
if r == 'Attribute':
count = count+1
print(count)
label = x.attrib['Name']
binary_mask = np.transpose(np.zeros((img.read_region((0,0),0,img.level_dimensions[0]).size)))
print(label)
# Create directory for each label
sub_path = sub_image+'/'+label
try:
os.mkdir(sub_path)
except OSError:
print ("Creation of the directory %s failed" % label)
else:
print ("Successfully created the directory %s " % label)
if r == 'Region':
regions = []
vertices = x[1]
coords = np.zeros((len(vertices), 2))
for i, vertex in enumerate(vertices):
coords[i][0] = vertex.attrib['X']
coords[i][1] = vertex.attrib['Y']
regions.append(coords)
# poly = Polygon(regions[0])
if len(regions[0]) >= 4: # OR added this condition to check if there are fewer than 4 coordinates or else to print a skipping message
poly = Polygon(regions[0])
vertex_row_coords = regions[0][:,0]
vertex_col_coords = regions[0][:,1]
fill_row_coords, fill_col_coords = draw.polygon(vertex_col_coords, vertex_row_coords, binary_mask.shape)
binary_mask[fill_row_coords, fill_col_coords] = 255
mask_path = sub_path+'/'+str(count)+'_mask.png'
cv2.imwrite(mask_path, binary_mask)
else:
print("Skipping creation of Polygon. Insufficient coordinates.")