forked from jo-mueller/MicroQuant
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathRun_classification.ijm
300 lines (251 loc) · 7.84 KB
/
Run_classification.ijm
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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
/*
* This script applies a previously trained classifier
* for HE images to all HE images that match a predefined
* directory structure.
*
* The structure is expected to look like this:
* root | Mouse 1 |
* ...
* | Mouse N |Histology | Sample_1 |
* ...
* | Sample_N | HE filename
*
* The HE image is identified by the string "HE" in the filename
* The output image is then saved into the newly created directory
* "..../Sample x/seg/"
*
* Steps that are taken:
* - Image is openend in max resolution
* - Image is saved as .hdf5 format for Ilastik to understand
* - Ilastik is called to segment image
* - hdf5 image is deleted again to save storage
* - Output image is moved to output directory
*/
// Config
close("*");
roiManager("reset");
var usebatch = false;
var hasbeencropped = false;
setBatchMode(usebatch);
type = "IF"; // which type of image is segmented? "HE" or "IF"
reseg = true; // if true, segmentation will be done all over again. If false, only unprocessed samples will be segmented
// Ilastik files
root = "E:/Promotion/Projects/2020_Radiomics/Data/";
classifier = root + "../Scripts/Histology/Classify/"+type+"_classifier_AD_JM_2.ilp";
Ilastik_exe = "C:/Program Files/ilastik-1.3.3post3/run-ilastik.bat";
// Input dir
mice = getsubdirs(root);
// iterate over all mice
for (i = 0; i < mice.length; i++) {
print(d2s(i+1, 0) + "/" + d2s(mice.length, 0) + " animals");
dir_sample = root + mice[i] + "Histology/";
samples = getsubdirs(dir_sample);
// iterate over samples (aka tissue sections
for (j = 0; j < samples.length; j++) {
fnames = findFileByID(dir_sample + samples[j], type);
// Check if all images are provided:
// IF HE or IF is missing, there's no need for segmentation
files = getFileList(dir_sample + samples[j]);
if (files.length <2) {
print(" Probably some data missing in " + dir_sample + samples[j]);
continue;
}
// check plausibility of filenames
if (fnames.length>1) {
intrpt = getBoolean(" Something's weird here. Check?");
if (intrpt) {
exit();
} else {
continue;
}
}
if (fnames.length == 0) {
print(" ---> No IF image found here");
continue;
}
fname = fnames[0]; // extract fname from single-element array <fnames>
// Make output directory ( if it doesn't already exist)
seg_dir = dir_sample + samples[j] + "1_seg/";
if (!File.exists(seg_dir)) {
File.makeDirectory(seg_dir);
}
// Check if seg has been done before
if (!(reseg || ! File.exists(seg_dir + type + "_seg_Simple_Segmentation.tif"))) {
print(" Has been segmented before. Skipping.");
continue;
}
// (Pre-) process
image = Load(dir_sample + samples[j] + fname); // Load image
// Normalize if IF and identify black tiles if HE
if (type == "IF") { image = Normalize(image); }
if (type == "HE") { getTileBackground(image, seg_dir); }
// If a ROI has been provided
if ((roiManager("count") > 0) && (!hasbeencropped)) {
roiManager("save selected", dir_sample + samples[j] + File.getNameWithoutExtension(fname) + ".roi");
roiManager("select", 0);
run("Crop");
}
image = getTitle();
f_hdf5 = ExportH5(image, seg_dir + type + "_seg"); // convert to H5 and save
RunIlastik(Ilastik_exe, classifier, f_hdf5); // Call Ilastik
// Clean up
close("*");
roiManager("reset");
}
}
function RunIlastik(IL_executable, classifier, filename){
// Runs Ilastik <executable> to apply <classifier> on <filename>
print(" Running pixel classification on " + filename);
outpath = File.getDirectory(filename);
exec(IL_executable,
"--headless",
"--project=" + classifier,
filename,
"--output_format=tif",
"--export_source=Simple Segmentation",
"--output_filename_format="+outpath+"/{nickname}_Simple_Segmentation");
File.delete(filename); // remove h5 image to save storage
}
function getTileBackground(image, dst_dir){
selectWindow(image);
setSlice(1);
run("Duplicate...", "duplicate title=TileBackground0 channels=1");
run("Duplicate...", "duplicate title=TileBackground1 channels=1");
// identify pixels with value 0
selectWindow("TileBackground0");
setThreshold(0, 0);
run("Convert to Mask");
// identify pixels with value 255
selectWindow("TileBackground1");
setThreshold(255, 255);
run("Convert to Mask");
imageCalculator("OR create", "TileBackground0","TileBackground1");
result = getTitle();
close("TileBackground0");
close("TileBackground1");
// extract ROI
selectWindow(result);
run("Erode");
setThreshold(128, 255);
run("Create Selection");
// smooth ROI outline
run("Enlarge...", "enlarge=-30 pixel");
run("Enlarge...", "enlarge=60 pixel"); // expand ROI by 20 pixels to include edges in segmented image
roiManager("add");
close(result);
roiManager("save", dst_dir + "BlackTiles.zip");
}
function ExportH5(img, f_output){
// saves input image <image> as <f_output>.h5
selectWindow(img);
run("Export HDF5", "select="+f_output+".h5 " +
"exportpath=" + f_output + ".h5 " +
"datasetname=data " +
"compressionlevel=0 " +
"input=["+img+"]");
return f_output +".h5";
}
function Normalize (image){
/*
* Function for the preprocessing of IF image data.
* Images are re-sorted into RGB stacks, converted to 16-bit
* and normalized. Brightest pixels are clipped to eliminate
* the influence of staining artifacts.
*/
selectWindow(image);
if (nSlices ==1) {
run("RGB Stack");
}
run("Make Composite");
run("16-bit");
// do BG subtraction and normalization
// check if sample comes from Slidescanner
N = nSlices;
if (N == 4){
C0 = 2;
C1 = 4;
} else {
C0 = 1;
C1 = 3;
}
// in every loop, copy channel, subtract background and normalize
index = 1;
for (i = C0; i <= C1; i++) {
selectWindow(image);
setSlice(i);
run("Duplicate...", "title=" + index);
selectWindow(index);
run("Subtract Background...", "rolling=50 stack");
run("Enhance Contrast...", "saturated=0.3 normalize");
index += 1;
}
exit();
// if it's slidescanner data (which is typically badly cropped)
// give user chance to draw his own ROI
if (N == 4) {
setBatchMode(false);
selectWindow("1");
selectWindow("2");
selectWindow("3");
waitForUser("Set a ROI if image is badly cropped.\n"+
"Or do nothing if it's fine");
if (selectionType() != -1) {
roiManager("add");
roiManager("select", 0);
}
}
setBatchMode(usebatch);
close(image);
run("Merge Channels...", "c1=1 c2=2 c3=3 create");
rename(image);
return image;
}
function Load(f_input){
// converts an input file <f_input> into an hdf5 file <f_ouput>.
// The ".h5" file extension will be added on the fly.
//print(" --->"+f_input);
hasbeencropped = false;
run("Bio-Formats Importer", "open="+f_input+" autoscale "+
"color_mode=Default "+
"rois_import=[ROI manager] "+
"view=Hyperstack "+
"stack_order=XYCZT "+
"series_1");
dir = File.getDirectory(f_input);
f = File.getNameWithoutExtension(f_input);
if (File.exists(dir + f + ".roi")) {
roiManager("open", dir + f + ".roi");
roiManager("select", 0);
run("Crop");
hasbeencropped = true;
}
return getTitle();
}
function findFileByID(path, ID){
// browse directory <path> and check for files that match the given ID string <ID>
files = newArray();
filelist = getFileList(path);
for (i = 0; i < filelist.length; i++) {
// exclude ROIs from search
if (endsWith(filelist[i], "roi")) {
continue;
}
if (matches(filelist[i], ".*" + ID + ".*")) {
files = Array.concat(files, filelist[i]);
}
}
print(" Found " + d2s(files.length, 0) +" files matching " + ID + " in " + path);
Array.show(files);
return files;
}
function getsubdirs(path){
// Returns array with all subdirectories in <path>
list = getFileList(path);
dirlist = newArray();
for (i = 0; i < list.length; i++) {
if (File.isDirectory(path + list[i])) {
dirlist = Array.concat(dirlist, list[i]);
}
}
return dirlist;
}