Hi,
I would like to make a movie from a z-stack with it’s corresponding orthogonal projections (+ crosshairs) moving from one extremity to the other.
I found the following macro written by [Martin Höhne] (http://imagej.1557.x6.nabble.com/Orthogonal-Views-td5005236.html)
/*
* Macro to fullfill this task I asked for in the ImageJ-list:
*
* ... when I have a z-stack (RGB) and view this stack with the orthogonal views switched on,
* I can play that stack, i.e. move through the z-stack and the yellow cross-hair is
* moving in parallel in the yz and xz view.
* Is there a way of saving this whole view, i.e. xy, yz and xz including the moving
* yellow crosshair in one series/avi?
*
* The idea how to solve this (use reslice and combine stacks) is from the reply from Tiago Ferreira.
*
* Martin Hoehne 2012-10-08
*
* - added color variables 2013-10-21
*
*/
// define z-color globally. Needs to be available in the macro and in a function
var colZ_arr=newArray(255,255,255); //=same color as colZ in RGB
macro "Ortho view movie" {
run("Overlay Options...", " "); // this ensures that the xy-crosshair and labels are shown in all stacks. Removes the
// Overlay option "Set stack position"
//colors
//color for X view
colX="red";
colX_arr=newArray(255,0,0); //=same color as colX in RGB
//color for Y view
colY="cyan";
colY_arr=newArray(0,255,255); //=same color as colY in RGB
//color for Z view (xy-view)
colZ="white";
//colZ_arr=newArray(0,255,0); //=same color as colX in RGB //already defined globally
//color for background canvas
colCanvas_arr=newArray(40,40,40); //=dark grey
if (nImages()!=0) exit ("please close all other images before running the macro");
//open file and create results dir
path = File.openDialog("Select the file");
open(path);
//run("Bat Cochlea Volume (19K)"); //works as a testfile
getDimensions(width, height, channels, slices, frames);
getVoxelSize(voxwidth, voxheight, depth, unit);
run("Orthogonal Views");
msg1 = "\nPostion the crosshair in the xy window."+
"\n(original stack)"+
"\n \nWhen done, continue with <OK>";
waitForUser(msg1);
setBatchMode(true);
// get the position where the user has put the yellow cross-hair in the xy-stack. The position is read from the titles
// of the YZ and XZ images using the function "ccord" --> see below
for (i=1; i<=3; i++){
img=getTitle();
if (substring(img,0,2)=="YZ") {
yzID = getImageID();
x=coord(img);
rename("YZ_"+x); //no space in title allowed to combine stacks later in macro
yztitle=getTitle();
}
if (substring(img,0,2)=="XZ") {
xzID = getImageID();
y=coord(img);
rename("XZ_"+y); //no space in title allowed to combine stacks later in macro
xztitle=getTitle();
}
close();
// in the first round the original image is still selected and closed
// in the next two round the YZ and XZ views are selected, resp.
// I could not find another way of getting hold of the titles of the
// XZ and YZ windows
}
// image has to be reopened
//("Bat Cochlea Volume (19K)");
open(path);
run("RGB Color");
imgID=getImageID();
setLineWidth(20);
// reslice YZ
// produce a single y-slice at the x-position chosen by the user in the xy view by placing the crosshair
selectImage(imgID);
makeLine(x,0,x,height);
run("Add Selection...", "stroke="+colY+" width=1"); //add the vertical crosshair line to the selection
run("Reslice [/]...", "output="+ depth+" slice_count=1 rotate");
getDimensions(w,h,c,s,f); //dimensions are dependent on depth, i.e. slice thickness
// colY-colored frame around the image
setBackgroundColor(colY_arr[0],colY_arr[1],colY_arr[2]);
run("Canvas Size...","width="+w+4+" height="+h+4+" position=Center");
rename("YZ_"+ x);
orthoYZ=getImageID();
makestack(orthoYZ, slices, width, height, voxwidth, voxheight, depth, 1); //makestack function see below
// reslice XZ
// produce a single x-slice at the y-position chosen by the user in the xy view by placing the crosshair
selectImage(imgID);
makeLine(0,y,width,y);
run("Add Selection...", "stroke="+colX+" width=1"); //add the horizontal crosshair line to the selection
run("Reslice [/]...", "output="+ depth+" slice_count=1");
getDimensions(w,h,c,s,f); //dimensions are dependent on depth, i.e. slice thickness
// colX-colored frame around the image
setBackgroundColor(colX_arr[0],colX_arr[1],colX_arr[2]);
run("Canvas Size...","width="+w+4+" height="+h+4+" position=Center");
rename("XZ_"+ y);
orthoXZ=getImageID();
makestack(orthoXZ, slices, width, height, voxwidth, voxheight, depth, 2); //makestack function see below
// flatten the crosshair onto the original xy-stack
selectImage(imgID);
run("Flatten", "stack");
// white frame around the xy image
setBackgroundColor(colZ_arr[0],colZ_arr[1],colZ_arr[2]);
run("Canvas Size...", "width="+width+4+" height="+height+4+" position=Center");
// combine views
stk1=getTitle();
setBackgroundColor(colCanvas_arr[0],colCanvas_arr[1],colCanvas_arr[2]);
run("Combine...", "stack1="+ stk1 +" stack2="+ yztitle);
rename("combi1");
run("Combine...", "stack1=combi1" +" stack2="+ xztitle +" combine");
setBatchMode(false);
// grey frame around the image + labeling
getDimensions(w,h,c,s,f); //dimensions of the combined stacks
run("Canvas Size...", "width="+w+20+" height="+h+40+" position=Center");
setFont("Sanserif", 14);
makeText("xy view", 20, 0);
run("Add Selection...", "stroke="+colZ);
makeText("xz view", 20, h+18);
run("Add Selection...", "stroke="+colX);
makeText("yz view", w-44,0);
run("Add Selection...", "stroke="+colY);
// "stupid" command to unselect the "yz view" text -- most likely there are more elegant ways
makePoint(w*2, h);
}
//-FUNCTIONS-----------------------------------------------------------------------------------//
function coord(imgname) {
// function returns the x or y value of the selected section. Extracted from the image title
//(e.g. title = YZ 123) --> 123 is returned
string=substring(imgname,3,lengthOf(imgname));
return parseInt(string);//Converts string to an integer and returns it. Returns NaN if the string cannot be converted into a integer.
}
function makestack(imgID, slices, xmax, ymax, voxwidth, voxheight, depth, orient) {
// duplicate the YZ or the XZ image resp. z-times (i.e. make a stack with
// identical number of slices as the original x-y-z stack.
// Draw a line in each of the images indicating a different z-position. If the z-slice
// is thicker than 1 pixel (interpolated) the line is drawn in the middle of the slice position
//
// The last argument of the function (orient) is needed for the orientation. I.e. to differentiate between x and y view
setForegroundColor(colZ_arr[0],colZ_arr[1],colZ_arr[2]);
neuID = getImageID();
titel = getTitle();
run("Select All");
run("Copy");
run("Duplicate...", "title=["+titel+"]");
dup=getImageID();
selectImage(neuID);
close();
selectImage(dup);
for (i=0; i<slices; i++) {
run("Paste");
// draw line indicating the z-plane
if (orient==1) {
zspace=depth/voxwidth; //take thickness of z-slices into account
drawLine(i*zspace+zspace/2,2,i*zspace+zspace/2,ymax+1);
}
if (orient==2) {
zspace=depth/voxheight;
drawLine(2,i*zspace+zspace/2,xmax+1,i*zspace+zspace/2);
}
run("Add Slice");
}
run("Delete Slice");
}
I also found the following but it has no crosshairs and doesn’t include the original XY images. ( [Tiago Ferreira-2] (http://imagej.1557.x6.nabble.com/Orthogonal-Views-td5005236.html)
// ---- ---
run("T1 Head (2.4M, 16-bits)");
img = getImageID();
getVoxelSize(width, height, depth, unit);
vws = newArray("Top", "Left", "Bottom", "Right");
setBatchMode(true);
// Create projections
for (i=0; i<vws.length; i++) {
selectImage(img);
rtt = "";
if (i%2) rtt = " rotate";
run("Reslice [/]...", "output="+ depth +" start="+ vws[i] + rtt);
rename(vws[i]);
}
// combine top views
run("Combine...", "stack1="+ vws[0] +" stack2="+ vws[2] +" combine");
rename("TB");
// Append side views
run("Combine...", "stack1="+ vws[1] +" stack2=TB");
rename("LTB");
run("Combine...", "stack1=LTB stack2="+ vws[3]);
setBatchMode("exit & display");
doCommand("Start Animation [\\]");
// ---- ---
But sadly I cant make it work. Would anyone know how to fix the macro or have an alternative ?
I know that I could export the projections but I would need to synchronise them and also they wouldn’t have the cross-hairs.
Thank you very much