-
-
Save schiklen/3736509 to your computer and use it in GitHub Desktop.
Using TurboReg from ImageJ macro, to output shifts.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* A 2D drift correction macro for multichannel multislide stacks | |
* by Kota Miura | |
* and Christoph Schikenk, schiklen@embl.de | |
* | |
* still missing: write calculations to metadata and retrieve it, | |
* or import results automatically when opening. | |
* | |
*/ | |
var npos = 0; // number of imaged positions for batch-mode | |
var directapply = 0;// "boolean" user input direct application of driftcorrect | |
var crop = 0; // "boolean" user input crop to ROI after drift correction | |
var splitch = 0; // "boolean" user input splitting of channels after drift correction | |
var targetstack = 1;// ImageID of the stack that is to be processed | |
var dir; // Directory of open image | |
var cropxmax = 0; | |
var cropymax = 0; | |
var maxout = 0; | |
var startout = 0; | |
macro "Driftcorrect_" { | |
ipos = 0; // imaged position currently processed | |
ch = 0; | |
frame = 0; | |
slice = 0; | |
// -------------- Start of actual code ---------------- | |
setBatchMode(true); | |
dropdown = newArray(nImages()+2); // creating dropdown array for startup dialog | |
for (i = 0; i < nImages; i++) | |
{ | |
selectImage(i+1); | |
dropdown[i] = getTitle(); | |
} | |
dropdown[dropdown.length-2] = "Open single stack"; | |
dropdown[dropdown.length-1] = "Batch-process folder"; | |
setBatchMode(false); | |
Dialog.create("Driftcorrect"); // creating startup dialog | |
Dialog.addChoice("Driftcorrect", dropdown); | |
Dialog.addCheckbox("Show corrected stack(s)", true); | |
Dialog.addCheckbox("Crop to covered region", true); | |
Dialog.addCheckbox("Split channels after correction", false); | |
Dialog.show(); | |
dropdownselect = Dialog.getChoice(); | |
directapply = Dialog.getCheckbox(); | |
crop = Dialog.getCheckbox(); | |
splitch = Dialog.getCheckbox(); | |
// maybe add here: select, which channel should be used as reference. | |
//---- single mode ----- | |
if (dropdownselect == "Open single stack") | |
{ | |
npos = 0; | |
ipos = 0; | |
dir = File.openDialog("Please select the stack"); | |
print(dropdownselect + ": " + dir); | |
run("Bio-Formats Importer", | |
"open=[" + dir +"]" | |
+ " autoscale" | |
+ " color_mode=Grayscale" | |
+ " view=Hyperstack" | |
+ " stack_order=XYCZT" | |
); | |
openimage = getImageID(); | |
measure_driftcorrect(openimage, false); | |
if (directapply == true) | |
{ | |
selectImage(openimage); | |
apply_driftcorrect(openimage, crop); | |
} | |
Stack.getDimensions(w, h, chn, sln, frn); | |
if (splitch == true && chn > 1) | |
{ | |
selectImage(openimage); | |
run("Split Channels"); | |
} | |
} // end of if: Open single stack mode | |
//------- batch-process mode ------- | |
else | |
{ | |
if (dropdownselect == "Batch-process folder") | |
{ | |
print("Batch/Folder mode"); | |
setBatchMode(true); | |
dir = getDirectory("Please select a folder containing stacks"); | |
list = getFileList(dir); // .dv file counter and list maker | |
dv_list = newArray(list.length); | |
for (i = 0; i < list.length; i++) | |
{ | |
if (endsWith(list[i], ".dv") == true) | |
{ | |
dv_list[npos] = list[i]; | |
npos++; | |
} | |
} | |
dv_list = Array.trim(dv_list, npos); | |
if (npos <= 0) | |
exit("No *.dv files in chosen directory."); | |
else | |
{ | |
write(npos + " *.dv files found in chosen directory: "); | |
Array.print(dv_list); | |
} // End of .dv file counter and list maker | |
for (ipos = 0 ; ipos < npos; ipos++) //Image importer loop. | |
{ | |
run("Bio-Formats Importer", | |
"open=[" + dir + dv_list[ipos] + "]" | |
+ " autoscale" | |
+ " color_mode=Grayscale" | |
+ " view=Hyperstack" | |
+ " stack_order=XYCZT" | |
+ " use_virtual_stack"); | |
openimage = getImageID(); | |
measure_driftcorrect(openimage, true); // true is for driftcorrect's batchmode=true | |
} | |
setBatchMode(false); | |
} | |
//----------- already opened image mode ------------ | |
else | |
{ | |
print("Opened image mode - " + dropdownselect); | |
selectWindow(dropdownselect); | |
dir = getInfo("image.filename"); // getting path of open image. Problem: what if not saved?? | |
openimage = getImageID(); | |
measure_driftcorrect(openimage, false); // false is for folder-mode = false | |
if (directapply == true) | |
{ | |
selectImage(openimage); | |
apply_driftcorrect(openimage, crop); | |
} | |
Stack.getDimensions(w, h, chn, sln, frn); | |
if (splitch == true && chn > 1) | |
{ | |
selectImage(openimage); | |
run("Split Channels"); | |
} | |
} | |
} | |
print("I'm done."); | |
} // end Macro | |
// ------ function definitions ------- | |
function measure_driftcorrect(dcstack, foldermode) // add arg. refchannel | |
{ | |
setBatchMode(true); | |
if (isOpen(dcstack) != true) //check that target-window open | |
exit("The stack you want to correct for drift is not open!"); | |
else | |
{ | |
selectImage(dcstack); | |
Stack.getDimensions(w, h, chn, sln, frn); | |
filename = getInfo("image.filename"); | |
dcresultsx = newArray(frn+1); | |
dcresultsy = newArray(frn+1); | |
// SET CHANNEL HERE.?? function machen? | |
if (chn > 1) | |
{ | |
Stack.setChannel(refchannel); | |
} | |
// print("Using channel" + + "as basis."); | |
if (sln > 1) | |
{ | |
cenSl = sln/2; // go to central Z-postition. dirty here! needs to be rounded up! cenSl: central slice | |
write("Moving to slice " + cenSl + " of " + sln); | |
Stack.setSlice(cenSl); // better: z-projection (but which mode? avg/max/min/stdev). make selectable in dialog. | |
run("Reduce Dimensionality...", " frames keep"); | |
dcstack = getImageID(); // | |
selectImage(dcstack); // select new window with the reduced timepoint | |
Stack.setFrame(0); // set to first time frame - for StackReg as reference | |
write("Starting driftcorrect calculation on position " + ipos + ", slide " + cenSl); | |
} | |
for (frame = 0; frame <= frn; frame++) | |
{ | |
selectImage(dcstack); | |
Stack.setFrame(frame); | |
run("Duplicate...", "title=sourceimage"); | |
frame1 = "sourceimage"; // a frame in a sequence | |
selectImage(dcstack); | |
Stack.setFrame(frame + 1); // select next frame. | |
run("Duplicate...", "title=targetimage"); | |
frame2 = "targetimage"; // next frame in the sequence | |
selectWindow(frame1); | |
width = getWidth(); | |
height = getWidth(); | |
run("TurboReg ", | |
"-align " | |
+ "-window " + frame1 + " "// Source (window reference). | |
+ " 0 0 " + (width - 1) + " " + (height - 1) | |
+ " -window " + frame2 + " "// Target (window reference). | |
+ " 0 0 " + (width - 1) + " " + (height - 1) | |
+ " -translation" | |
+ " " + (width / 2) + " " + (height / 2) | |
+ " " + (width / 2) + " " + (height / 2) | |
+ " -hideOutput" | |
); | |
sourceX0 = getResult("sourceX", 0); // First line of the table. | |
sourceY0 = getResult("sourceY", 0); | |
targetX0 = getResult("targetX", 0); | |
targetY0 = getResult("targetY", 0); | |
xoffset = sourceX0 - targetX0; // calculate offsets in respect to previous image. | |
yoffset = sourceY0 - targetY0; | |
xoffsetsum = xoffsetsum + xoffset; // x and yoffsetsums: value each frame has to be aligned in respect to first frame. | |
yoffsetsum = yoffsetsum + yoffset; | |
dcresultsx[frame] = xoffsetsum; // saving results for each frame in arrays | |
dcresultsy[frame] = yoffsetsum; | |
print("Frame " + frame + " - x: " + xoffsetsum + " y: " + yoffsetsum); | |
selectWindow(frame1); | |
close(); | |
selectWindow(frame2); | |
close(); | |
} // closes for (frame = 0; frame <= driftcorfrn; frame++); | |
} //closes else | |
if (sln > 1) | |
{ | |
selectImage(dcstack); | |
close(); | |
} | |
print("Done calculating drift in position " + ipos+1); | |
run("Clear Results"); // transferring results to results-table | |
for (i = 0; i < dcresultsx.length; i++) | |
{ | |
setResult("Frame", i, i); | |
setResult("X-offsetsum", i, dcresultsx[i]); | |
setResult("Y-offsetsum", i, dcresultsy[i]); | |
} | |
absolute_max(dcresultsx); // absolute maxfunction | |
setResult("X-max", 0, maxout); | |
setResult("X-start", 0, startout); | |
absolute_max(dcresultsy); | |
setResult("Y-max", 0, maxout); | |
setResult("Y-start", 0, startout); | |
updateResults(); | |
selectWindow("Results"); | |
filename1 = split(filename, "."); | |
print("Saving results as " + filename1[0] + "driftcor.xls"); | |
saveAs("Results", filename1[0] + "driftcor.xls"); // saves resultstable as a file. | |
if (foldermode == true) | |
{ | |
selectImage(dcstack); | |
close(); | |
} | |
setBatchMode(false); | |
} // end of function | |
function apply_driftcorrect(targetstack, croparg) // targetstack is ImageID | |
{ | |
selectImage(targetstack); | |
Stack.getDimensions(w, h, chn, sln, frn); | |
for (frame = 0; frame <= frn; frame++) // frame <= frn!! | |
{ | |
corx = getResult("X-offsetsum", frame); // load corrected x-position from results-table | |
cory = getResult("Y-offsetsum", frame); // load corrected y-position | |
for (slice = 1; slice <= sln; slice++) // shift all z-slices of one frame | |
{ | |
for (channel = 1; channel <= chn; channel++) | |
{ | |
selectImage(targetstack); | |
Stack.setPosition(channel, slice, frame); | |
run("Translate...", "x=" + corx + " y=" + cory + " interpolation=None slice"); | |
} | |
} | |
} | |
if (croparg == true) | |
{ | |
makeRectangle(getResult("X-start", 0), getResult("Y-start", 0), w-abs(getResult("X-max", 0)), h-abs(getResult("Y-max",0))); | |
run("Crop"); | |
} | |
} // end of function | |
function absolute_max(array) | |
{ | |
Array.getStatistics(array, min, max, mean, stdDev); | |
startout = max; | |
if (abs(min) <= abs(max)) | |
{ | |
maxout = max; | |
} | |
if (abs(min) > abs(max)) | |
{ | |
maxout = min; | |
} | |
} // end of function | |
// End of code |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment