-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathConvert_ndf_to_ROI.ijm
More file actions
executable file
·280 lines (229 loc) · 9.54 KB
/
Convert_ndf_to_ROI.ijm
File metadata and controls
executable file
·280 lines (229 loc) · 9.54 KB
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
// Convert_ndf_to_ROI macro by Christophe Leterrier
// 20-01-2015
//
// From a folder with 8-bit images and corresponding .ndf files (containing tracing coordinates as output by the NeuronJ plugin),
// generates ROIs from each tracing, and stores them in the ROI Manager. Output ROI line width is adjustable.
// Keeps tracings color and type according to the ndf file (tracing type stored in ROI name and ROI properties).
// Warning: does not save the ROI set on disk in the end (only in the ROI manager).
// For multichannel tracings (different tracings on different channels in the input folder), can output either
// - an hyperstack with tracings on their respective channels
// - a stack of the first channel containing tracings from different channels flattened (single channel output option)
// This allows to measure intensities on channels others than the ones used to draw tracings,
// by applying ROIs on different single-channels stacks from the same acquisition.
macro "Convert_ndf_to_ROI" {
// Default parameter values
lineWidth_def = 1; // width (in pixels) of the line ROIs
chNumber_def = 1; // number of channels in the input folder
singCh_def = false; // single channel option (applies only if more than one channel)
keepCh_def = 1; // in case of single channel output, which channel to keep (1-n)
// Colors as defined in the NeuronJ plugin
neuronJColors = newArray("black", "blue", "cyan", "green", "magenta", "orange", "pink", "red", "yellow");
// macro parameters (when called as "runMacro(macro, arg)")
params = getArgument();
if (params == "")
{
// Retrieve the images from the NeuronJ image folder
inDir = getDirectory("Select a directory");
print("\n\n\n*** Convert ndf to ROI log ***");
print("Input directory:" + inDir);
//Creation of the dialog box
Dialog.create("ndf to ROI Options");
Dialog.addNumber("Line width", lineWidth_def, 0, 2, "pixels" ); // width (in pixels) of the line ROIs
Dialog.addMessage("");
Dialog.addNumber("Channel number", chNumber_def, 0, 2, "channels" ); // number of channels in the input folder
Dialog.addCheckbox("Single channel output", singCh_def); // single channel option (applies only if more than one channel)
Dialog.addNumber(" Keep channel #", keepCh_def, 0, 2, "" ); // in case of single channel output, which channel to keep (1-n)
Dialog.show();
// Feeding variables from dialog choices
lineWidth = Dialog.getNumber();
chNumber = Dialog.getNumber();
singCh = Dialog.getCheckbox();
keepCh = Dialog.getNumber();
}
else
{
// if not provided, assign default values
inDir = "";
lineWidth = lineWidth_def;
chNumber = chNumber_def;
singCh = singCh_def;
keepCh = keepCh_def;
// extract arguments
macro_args = split(params);
for (ik = 0; ik < macro_args.length; ik++)
{
if (startsWith(macro_args[ik],"dir="))
inDir = substring(macro_args[ik], 4);
else if (startsWith(macro_args[ik],"line="))
lineWidth = parseInt(substring(macro_args[ik], 5));
else if (startsWith(macro_args[ik],"channel="))
chNumber = parseInt(substring(macro_args[ik], 8));
else if (startsWith(macro_args[ik],"single"))
singCh = true;
else if (startsWith(macro_args[ik],"keep="))
keepCh = parseInt(substring(macro_args[ik], 5));
else
print("Unknown argument!");
}
if ("inDir" == "" || !File.exists(inDir) || !File.isDirectory(inDir))
exit("Could not find directory!");
if (!endsWith(inDir,"\\"))
inDir = inDir+"\\";
}
inParent = File.getParent(inDir);
inName = File.getName(inDir);
// Clear ROI manager
roiManager("reset");
// Open all images in the folder
run("Image Sequence...", "open=[" + inDir + "] sort");
// Get slice number, and number of slice after channels split
allSlice = nSlices();
sliceNumber = allSlice / chNumber;
// Verify that images in folder can be split into channels
if (sliceNumber != floor(sliceNumber))
exit("Image number not multiple of channel number in the folder");
// Make an hyperstack with slices and channels
if (allSlice > 1)
run("Stack to Hyperstack...", "order=xyczt(default) channels=" + chNumber + " slices=" + sliceNumber + " frames=1 display=Grayscale");
// Loop over all slices in the hyperstack, retrieve the ndf files and create the ROI
for (i=0; i < allSlice; i++) {
// Set slice and get HS position
setSlice(i + 1);
Stack.getPosition(currCh, currSlice, currFrame);
// Get .ndf file name
if (allSlice == 1)
ndfName = Property.getSliceLabel; // strange bug in single-image case, there is .ndf already in the name
else {
imageName = Property.getSliceLabel;
ndfName = replace(imageName, ".tif", ".ndf");
}
// Log
print(" image #" + (i + 1));
print(" ndf file: " + ndfName);
if (File.exists(inDir + ndfName) == 1) {
ndfFile = File.openAsString(inDir + ndfName);
// uses the function "wordsplit" to break the file into Tracings
ndfParts = wordsplit(ndfFile, "// Tracing");
// Log
//for( i = 0; i < ndfParts.length; i++) print("ndfParts[" + i + "]=" + Parts[i]);
nTracings = ndfParts.length - 1;
logString = " contains " + nTracings + " tracings";
// Get types and colors
ndfHeader = wordsplit(ndfParts[0], "//");
ndfTypes = split(ndfHeader[3], "\n");
typeLength = (ndfTypes.length - 1) / 2;
typeNames = newArray(typeLength);
typeAdd = newArray(typeLength);
typeColors = newArray(typeLength);
for (a = 1; a < ndfTypes.length; a = a + 2){
// print("a=" + a + " " + ndfTypes[a] + "-" + ndfTypes[a+1])
typeNames[(a - 1) / 2] = ndfTypes[a];
nColor = parseInt(ndfTypes[a + 1]);
typeColors[(a - 1) / 2] = neuronJColors[nColor];
}
// Loop (over tracings) retrieves the coordinates and creates the ROI
for (k = 1; k < nTracings + 1 ; k++) {
// Split coordinates
coorList = split(ndfParts[k], "\n");
// Tracing type
tracType = parseInt(coorList[2]);
// print("tracType = " + tracType);
// Get number a valid coordinates
listLength = 0;
for (j = 6; j < coorList.length; j++) {
if (startsWith(coorList[j], "// Segment") == false && startsWith(coorList[j], "// End") == false) {
listLength++;
}
}
// print("listLength =" + listLength);
// Build the array of valid coordinates
cleanCoor = newArray(listLength);
c = 0;
for (j = 6; j < coorList.length; j++) {
if (startsWith(coorList[j], "// Segment") == false && startsWith(coorList[j], "// End") == false) {
cleanCoor[c] = coorList[j];
c++;
}
}
// Split in X and Y arrays
lineX = newArray(listLength / 2);
lineY = newArray(listLength / 2);
for (j = 0; j < listLength; j = j + 2) {
lineX[j / 2] = cleanCoor[j];
lineY[j / 2] = cleanCoor[j+1];
}
logString = logString + ", N" + (k + 1) + " (l" + lineX.length + ")";
// Create the ROI from coordinates
makeSelection("polyline", lineX, lineY);
// Allow to smooth the tracing
run("Fit Spline");
// Put ROI only on first channel if single channel output option is checked
if (chNumber > 1 && singCh == true)
Stack.setPosition(1, currSlice, currFrame);
// Set ROI properties
Roi.setProperty("TracingType", tracType);
Roi.setProperty("TypeName", typeNames[tracType]);
// Add ROI to the ROI manager
roiManager("Add");
// Rename the ROI to add the type of tracing
roiManager("Select",roiManager("count") - 1);
roiName = getInfo("selection.name");
roiName = roiName + "-" + tracType + "-" + typeNames[tracType];
roiManager("Rename", roiName);
// Change the ROI color according to type and the ROI line width
roiManager("Select",roiManager("count") - 1);
roiManager("Set Color", typeColors[tracType]);
roiManager("Set Line Width", lineWidth);
}
print(logString);
}
//Log if no ndf file for a slice
else print(" no tracing (no .ndf file)");
}
if (chNumber > 1 && singCh == true) {
setSlice(keepCh);
run("Reduce Dimensionality...", "slices");
for (r = 0; r < roiManager("count"); r++) {
roiManager("Select", r);
roiName = getInfo("selection.name");
roiPos = split(roiName, "-");
roiSlice = parseInt(roiPos[0]);
newSlice = floor(roiSlice / chNumber) + 1;
setSlice(newSlice);
roiManager("Update");
nameSlice = IJ.pad(newSlice, 4);
newName = replace(roiName, roiPos[0], nameSlice);
roiManager("Rename", newName);
}
}
// reset slice and ROI display
roiManager("Deselect");
setSlice(1);
// Presents all the ROIs created
roiManager("Associate", "true");
roiManager("Show All");
roiManager("Show All with labels");
// roiManager("Save", inPar + File.separator + inName + "_ROIs.zip");
print("*** Convert ndf to ROI end ***");
showStatus("Convert ndf to ROI finished");
}
// Function is similar to the "split" built-in function but with a "word" splitter (a series of characters interpreted as a whole)
function wordsplit(StartString, DeliString) {
ShrinkString=StartString;
nParts=0;
DelIndex=0;
while (DelIndex>-1) {
DelIndex=indexOf(ShrinkString,DeliString);
ShrinkString=substring(ShrinkString, DelIndex+lengthOf(DeliString));
nParts++;
}
SplitString=newArray(nParts);
ShrinkString=StartString;
for (j=0; j<nParts-1; j++) {
DelIndex=indexOf(ShrinkString,DeliString);
SplitString[j]=substring(ShrinkString, 0, DelIndex);
ShrinkString=substring(ShrinkString, DelIndex+lengthOf(DeliString));
}
SplitString[nParts-1]=ShrinkString;
return SplitString;
}