-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathwsi2patches.py
163 lines (126 loc) · 5.35 KB
/
wsi2patches.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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
import os
import sys
import argparse
from glob import glob
import json
import numpy as np
from multiprocessing import Pool
from PIL import Image
import openslide
from utils import ensure_dir
def wsi2patches(arguments):
WSI_path, output_dir, patch_size = arguments
# some code is adopted from Le's code
done_fn = '{}/done.txt'.format(output_dir)
if os.path.isfile(done_fn):
return None
margin = 5
try:
oslide = openslide.OpenSlide(WSI_path)
if openslide.PROPERTY_NAME_MPP_X in oslide.properties:
mpp = float(oslide.properties[openslide.PROPERTY_NAME_MPP_X])
elif "XResolution" in oslide.properties:
mpp = float(oslide.properties["XResolution"]);
elif "tiff.XResolution" in oslide.properties:
mpp = float(oslide.properties["tiff.XResolution"]);
else:
mpp = 0.250
width = oslide.dimensions[0]
height = oslide.dimensions[1]
except:
print('Error in {}: exception caught exiting'.format(WSI_path))
raise Exception('{}: exception caught exiting'.format(WSI_path))
pw, ph = patch_size
for x in range(1, width, pw):
for y in range(1, height, ph):
# the segmentation results do not have sizes that are < patch_sizes
if x + pw > width - margin:
continue
if y + ph > height - margin:
continue
if pw <= 3 or ph <= 3:
continue
try:
patch = oslide.read_region((x, y), 0, (pw, ph)).convert('RGB')
except:
print('{}: exception caught'.format(slide_name))
continue
fn = "{}/{}_{}_{}_{}_{}_1_PATCH.png".format(output_dir, x, y, pw, ph, mpp)
patch.save(fn)
# print("{}_{}_{}_{}_{}_1_PATCH done!".format(x, y, pw, ph, mpp))
with open(done_fn, 'a') as f:
f.write(WSI_path)
f.write('\n width: {}, height: {}\n'.format(width, height))
# print('{} done!'.format(WSI_path))
def query_fn(wsi_id, path_list):
for path in path_list:
basename = path.split('/')[-1]
if basename.find(wsi_id) != -1:
return path
return None
def wsi2patches_main(config, start_idx, end_idx, ncores):
wsi_root = config['WSIs']['root_path']
nuclei_seg_root = config['Nuclei_segs']['root_path']
tumor_preds_root = config['Tumor_preds']['root_path']
til_preds_root = config['TIL_preds']['root_path']
wsi_output_path = config['WSIs']['output_path']
# nuclei_segs_output_path = config['Nuclei_segs']['output_path']
# tumor_preds_output_path = config['Tumor_preds']['output_path']
# til_preds_output_path = config['TIL_preds']['output_path']
wsi_path_list = glob('{}/*.svs'.format(wsi_root))
nuclei_segs_path_list = glob('{}/*.svs'.format(nuclei_seg_root))
tumor_preds_path_list = glob('{}/prediction-*[!.low_res]'.format(tumor_preds_root))
til_preds_path_list = glob('{}/prediction-*[!.low_res]'.format(til_preds_root))
tasks = []
for wsi_path in wsi_path_list:
wsi_fn = wsi_path.split('/')[-1]
wsi_id = wsi_fn.split('.')[0]
# not diagnoised
if wsi_id[-3:-1].lower() != 'dx':
continue
nuclei_segs_path = query_fn(wsi_id, nuclei_segs_path_list)
if nuclei_segs_path is None:
continue
tumor_path = query_fn(wsi_id, tumor_preds_path_list)
if tumor_path is None:
continue
til_path = query_fn(wsi_id, til_preds_path_list)
if til_path is None:
continue
wsi_output_path_cur = '{}/{}'.format(wsi_output_path, wsi_id)
ensure_dir(wsi_output_path_cur)
tasks.append((wsi_path, wsi_output_path_cur, (4000,4000)))
total_num = int(len(tasks))
print('Total number of WSIs is {}'.format(total_num))
end_idx = min(end_idx, total_num)
tasks = tasks[start_idx:end_idx]
if ncores > 1:
p = Pool(ncores)
print('Using {} cores'.format(ncores))
print('Dividing into patches ...')
for i, _ in enumerate(p.imap_unordered(wsi2patches, tasks), 1):
sys.stderr.write('\rDividing {0:%} done! '.format(i / len(tasks)))
else:
for task in tasks:
wsi2patches(task)
print('\nAll done! \n')
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Interpolation')
parser.add_argument('-c', '--config', default=None, type=str, help='config file path (default: None)')
parser.add_argument('--start_idx', type=int, default=0, help='start index')
parser.add_argument('--end_idx', type=int, default=50000, help='end index, (not included)')
parser.add_argument('--ncores', type=int, default=10, help='number of cores')
args = parser.parse_args()
if args.config:
config = json.load(open(args.config))
else:
raise AssertionError("Configuration file need to be specified. Add '-c config.json', for example.")
print(config)
start_idx = int(args.start_idx)
end_idx = int(args.end_idx)
ncores = int(args.ncores)
ensure_dir(config['WSIs']['output_path'])
ensure_dir(config['Nuclei_segs']['output_path'])
ensure_dir(config['Tumor_preds']['output_path'])
ensure_dir(config['TIL_preds']['output_path'])
wsi2patches_main(config, start_idx, end_idx, ncores)