//These macros were written by Steve Rothery
//FILM - Facility for Imaging in Light Microscopy, Imperial College London
//http://www3.imperial.ac.uk/imagingfacility/


///////////////////////////////////////////////////////////////////1

macro "Change Channels LUT's Action Tool - Cccc F00hh C000 T0809L T6809U Td809T Cg00 T0g09R C0g0 T6g09G C00g Tdg09B" 
{

bit=bitDepth();

if (bit==24){
run("Make Composite");
}

getDimensions(width, height, channels, slices, frames);


Dialog.create("Change Channel Look-up Tables")
  Dialog.addMessage("Select Colour for each channel");
Colour = newArray("Red", "Green", "Blue", "Cyan", "Magenta", "Yellow", "Grays", "Light Blue", "HiLo", "16 colors", "Spectrum","lifetime");
for (i=1; i<=channels; i++) {
Ch="Channel " + i;
Dialog.addRadioButtonGroup(Ch, Colour, 2, 1, Colour[i-1]);
}
Dialog.show(); 


for (j=1; j<=channels; j++){
	if (channels>1){
	Stack.setChannel(j);
	}
newcol = Dialog.getRadioButton();
run(newcol);
}
}


/////////////////////////////////////////////////////////////////////////////2



macro "Sequentially Extract the best z focus from a time series Action Tool - C000 T0709E T6709X Td709T  T6g091"
{
// extract the best z position from a time series
fn=getTitle();
getDimensions(width, height, channels, slices, frames);
w=width;
h=height;
c=channels;
z=slices;
f=frames;

//get calibtaion
getVoxelSize(width, height, depth, unit);
units=unit;
px=width;
pz=depth;

rename("temp");

curr=1;
selectWindow("temp");
Stack.setPosition(1, 1, 1);
title = "Get info";
msg = "Select Z position:\n \n time frame = " + curr + " \n\n then select OK to continue";
waitForUser(title, msg);


Stack.getPosition(channel, slice, frame);
a=channel;
b=slice;
curr=frame;

selectWindow("temp");
new= "title=[temp0] duplicate channels=1-3 slices=" + b + " frames=" + curr;
run("Duplicate...",new);


for (i=2; i<=f; i++){
curr=i;
selectWindow("temp");
Stack.setPosition(a, b, curr);

title = "Get info";
msg = "Select Z position:\n \n time frame = " + curr + " \n\n then select OK to continue";
waitForUser(title, msg);

Stack.getPosition(channel, slice, frame);
a=channel;
b=slice;
curr=frame;

new= "title=[temp1] duplicate channels=1-3 slices=" + b + " frames=" + curr;
run("Duplicate...", new);
run("Concatenate...", "  title=[temp0] image1=[temp0] image2=[temp1] image3=[-- None --]");

}
selectWindow("temp");
rename(fn);
selectWindow("temp0");
rename("Best Z focus " + fn );

//re-calibrate
newscale="distance=1 known=" + px + " pixel=1 unit=" + units;
run("Set Scale...", newscale);
}

///////////////////////////////////////////////////////////////////////////3

macro "Sequentially extract a focussed z plane/stack Action Tool - C000 T0709E T6709X Td709T  T6g09Z"
{
//Sequentially extract a focussed z series from a time series
//creates balnk slices where necessary
fn=getTitle();
getDimensions(ImageWidth, ImageHeight, ImageChannels, ImageSlices, ImageFrames);
bit=bitDepth();
type="" + bit + "-bit color-mode label";

//get calibtaion
getVoxelSize(px, py, pz, units);

//get number of z slices and create starting hyperstack
Dialog.create("Get information");
  Dialog.addMessage("Enter z slice range");
  opt = newArray("Up and down", "Centre");
  Dialog.addRadioButtonGroup("Select method", opt, 1, 4, "Centre");
  Dialog.addMessage("Enter slices above and below selected focal plane");
  Dialog.addNumber("z slices above focus", 0, 0, 1,"" );
  Dialog.addNumber("z slices below focus", 0, 0, 1,"" );
  Dialog.addMessage("Or number equally either side of selected focal plane");
  Dialog.addNumber("z slices each side of focus", 0, 0, 1,"" );
Dialog.show;
method = Dialog.getRadioButton();
newz2 = Dialog.getNumber();
newz1 = Dialog.getNumber();
newz = Dialog.getNumber();


//get number of z slices and create starting hyperstack
if (method=="Centre"){
totalnewz=(2*newz)+1;
newz1=newz;
newz2=newz;
}
else {
totalnewz=newz1+newz2+1;
}

newImage("temp0", type, ImageWidth, ImageHeight, ImageChannels, totalnewz, 1);

channel=1;
slice=1;

//get centre z focus position for each time point
for (i=1; i<=ImageFrames; i++){
frame=i;
selectWindow(fn);
Stack.setPosition(channel, slice, frame);
waitForUser("Get slice info", "Select Z position:\n \n time frame = " + frame + " \n\n then select OK to continue");
Stack.getPosition(channel, slice, frame);

z1=slice-newz1;
z2=slice+newz2;

z1test=z1;
if (z1<1) {
	z1test=1;
}

//duplicate and join to series
selectWindow(fn);
run("Duplicate...", "title=[temp1] duplicate channels=1-"+ ImageChannels +" slices=" + z1test + "-" + z2+ " frames=" + frame);

AddSlices();

run("Concatenate...", "  title=[temp0] image1=[temp0] image2=[temp1] image3=[-- None --]");
Stack.setPosition(channel, slice, frame+2);
}

//finish up
run("Stack to Hyperstack...", "order=xyczt(default) channels="+ImageChannels+" slices=+"+totalnewz+" frames="+ImageFrames+1+" display=Composite");

//delete starting hyperstack
selectWindow("temp0");
Stack.setPosition(1, 1, 1);
run("Delete Slice", "delete=frame");
selectWindow("temp0");
Stack.setPosition(1, totalnewz/2, ImageFrames/2);
rename("Focus Aligned Z " + fn );
setVoxelSize(px, py, pz, units);

function AddSlices(){
//add blank z slices before
prez=z1;
while (prez<1) {
  selectWindow("temp1");
  Stack.setPosition(1, 1, 1);
  run("Add Slice", "add=slice prepend");
  prez=prez+1;
}  
//add blank z slices after
postz=z2;   
while (postz>ImageSlices) {
   selectWindow("temp1");
   getDimensions(ImageWidth, ImageHeight, tmpC, tmpS, tmpF);
  Stack.setPosition(tmpC, tmpS, tmpF);
  run("Add Slice", "add=slice");
  postz=postz-1;
}	
}


}


///////////////////////////////////////////////////////////////////////4

macro "Manually Align Images in a Time Series Action Tool - C999 V06cc C999 V66cc C444 V566c C000 O06cc O66cc L32e2 L3251 L3254 Le2b1 Le2b4" 
{
//macro to manually allign frames

//initialise
fn=getTitle();
roiManager("Reset");
run("Set Measurements...", "area mean min centroid bounding display redirect=None decimal=3");
getDimensions(OrigWidth, OrigHeight, channels, slices, frames);
getVoxelSize(px, py, pz, unit)
run("Duplicate...", "title=Temp duplicate");
run("Clear Results");

origImageChannels=channels;
origImageSlices=slices;
origImageFrames=frames




//check to make sure it is a time series
if (frames==1 && slices==1){
	exit("This is not a time series");
}
if (frames==1 && slices!=1){
con=getBoolean("Image has only 1 frame, but " + slices + " slicess, do you want to convert slices to frames for alignment");
if (con==1){
run("Stack to Hyperstack...", "order=xyczt(default) channels=1 slices=" + frames + " frames=" + slices + " display=Color");
getDimensions(OrigWidth, OrigHeight, channels, slices, frames);

Stack.setTUnit("frame");
}
}


range="";
if (slices>1){
range="duplicate frames=";
}

//get position info
Xpos=newArray(frames);
Ypos=newArray(frames);

title = "Add Position";
	msg = "Draw an ROI\n press OK to continue";
	waitForUser(title, msg);
roiManager("Add");

for (fr=0;fr<frames;fr++){

	Stack.setFrame(fr+1);

	title = "Add Position";
	msg = "Frame "+fr+1+" - Move ROI to correct position\n press OK to continue";
	waitForUser(title, msg);
	run("Measure");
	Xpos[fr]=floor(getResult("BX", fr)/px);
	Ypos[fr]=floor(getResult("BY", fr)/py);
}

Array.getStatistics(Xpos, Xmin, Xmax, Xmean, XstdDev);
Array.getStatistics(Ypos, Ymin, Ymax, Ymean, YstdDev);

Xcanvas=OrigWidth+(Xmax-Xmin);
Ycanvas=OrigHeight+(Ymax-Ymin);

setBatchMode("hide");


//enlage canvas
selectWindow("Temp");
run("Select None");
run("Canvas Size...", "width=Xcanvas height=Ycanvas position=Center zero");


//first image extraction
selectWindow("Temp");
Stack.setFrame(1);
makeRectangle(Xpos[0]-Xmin, Ypos[0]-Ymin, OrigWidth, OrigHeight);
//run("Duplicate...", "");
run("Duplicate...", range+1);
if (slices>1){
run("Add Slice", "add=frame prepend");
}
rename("new");



//image extraction
for (i=1;i<frames;i++){
selectWindow("Temp");
Stack.setFrame(i+1);
makeRectangle(Xpos[i]-Xmin, Ypos[i]-Ymin, OrigWidth, OrigHeight);
//run("Duplicate...", "");
run("Duplicate...", range+i+1);
rename("next");

run("Concatenate...", "  title=[new] image1=[new] image2=[next] image3=[-- None --]");
}

//finish up
rename("Aligned "+fn);
Stack.setFrame(1);
if (origImageSlices>1 && origImageFrames>1){
run("Delete Slice", "delete=frame");
//run("Stack to Hyperstack...", "order=xyczt(default) channels=origImageChannels slices=origImageSlices frames=origImageFrames display=Color");
}
run("Stack to Hyperstack...", "order=xyczt(default) channels=origImageChannels slices=origImageSlices frames=origImageFrames display=Color");
setBatchMode("exit and display");
selectWindow("Temp");
close();
}




////////////////////////////////////////////////5

macro "Channel Shift Alignment (pixel based) Action Tool -Cf55 F11ee C5f5 F33ee C000 L55dd L5595 L5559 L9ddd Ld9dd" 
{

fn=getTitle();
getDimensions(ImageWidth, ImageHeight, ImageChannels, ImageSlices, ImageFrames);
ch=Array.getSequence(ImageChannels+1)
ch=Array.slice(ch,1,ImageChannels+1);

for (i=0;i<ch.length;i++){
	ch[i]=d2s(ch[i],0);
}

Dialog.create("Options");
Dialog.addChoice("channel to shift", ch);
Dialog.addNumber("Shift in X (pixels)", 0);
Dialog.addNumber("Shift in Y (pixels)", 0);
Dialog.show();


run("Select None");
run("Duplicate...", "title=aligned duplicate");

ShCh=Dialog.getChoice();
ShX=Dialog.getNumber();
ShY=Dialog.getNumber();

for (fr=1;fr<=ImageFrames;fr++){
for (sl=1;sl<=ImageSlices;sl++){
selectWindow("aligned");
Stack.setPosition(ShCh, sl, fr);
makeRectangle(0, 0, ImageWidth, ImageHeight);
run("Cut");
makeRectangle(ShX, ShY, ImageWidth, ImageHeight);
run("Paste");
}
}
selectWindow("aligned");
rename(fn+" aligned");
run("Select None");

}


////////////////////////////////////////////////6

macro "Save individual images from Library Action Tool -Cg00 L0848 C00g Ld1h1 Ld4h4 Ld7h7 Ldaha Lddhd Ldghg C000 L68bf L68b1" 
{


OS=getInfo("os.name");

if(startsWith(OS, "Wind")==true){
sep="\\";
}
if(startsWith(OS, "Mac")==true){
sep="/";
}



//dialog
Dialog.create("Options");
Dialog.setInsets(0, 10, 0);
Dialog.addMessage("Extract:");
Option = newArray("Single file", "Folder of files");
Dialog.setInsets(0, 75, 0);
Dialog.addRadioButtonGroup("", Option, 1, 3, "Single file");
Dialog.setInsets(20, 1, 1);
Dialog.addMessage("Information:");
Dialog.setInsets(0, 10, 0);
Dialog.addMessage("- Single file option will create an output subfolder in the source folder");
Dialog.setInsets(-2, 10, -2);
Dialog.addMessage("- Directory of files option will create output subfolders in the selected output folder");
Dialog.setInsets(-2, 25, -2);
Dialog.addMessage("IMPORTANT source folder should only contain images to extract and output");
Dialog.setInsets(-2, 25, 0);
Dialog.addMessage("folder must not be within the source folder");
Dialog.setInsets(-2, 10, -2);
Dialog.addMessage("- Subfolder naming is based on filename");
Dialog.addMessage("NB - Existing output images or output folders will be overwritten");
Dialog.show(); 

//exit();
//get response
ExtractType=Dialog.getRadioButton();

//start bioformats 
run("Bio-Formats Macro Extensions");

//single file
if (ExtractType=="Single file"){
//get file 
filename = File.openDialog("Select file"); 
f=lastIndexOf(filename, sep);
output=substring(filename, 0, f+1);
setBatchMode(true);
Extract();
}


//folder of images
if (ExtractType=="Folder of files"){
input = getDirectory("Select folder location of input images");
output = getDirectory("Select folder for output images");
list = getFileList(input);
setBatchMode(true);
for (image=0;image<list.length;image++){
full = input +  list[image];
filename=full;
Extract();
}
}


function Extract() {
   //main function
f=lastIndexOf(filename, sep);
l=lastIndexOf(filename, ".");
dirname=substring(filename, f+1, l);
fileoutput=output+dirname;
File.makeDirectory(fileoutput);
out=fileoutput+sep+dirname;

//initialise image file
Ext.setId(filename); 

//get number of image series in filename
Ext.getSeriesCount(seriesCount);
 

//subloop
for (im=0;im<seriesCount;im++){
	
//set the series to open
//Ext.setSeries(im);

//open series
run("Bio-Formats Importer", "open=filename autoscale color_mode=Composite view=Hyperstack stack_order=XYCZT series_"+im+1);

//Ext.openImagePlus(filename);

fn=getTitle();
fn=fn.replace("/"," ");


getDimensions(ImageWidth, ImageHeight, ImageChannels, ImageSlices, ImageFrames);
//display as composite
if (ImageChannels>1){
run("Make Composite");
}
//save image
saveAs("Tiff",out+fn);
close();


print(fn+" extracted and saved");

}
print("Finished");
}



//finish up
Ext.close(); 
setBatchMode(false);
}

/////////////////////////////////////////////////////////7

macro "Split a stack of images (Z or Time) Action Tool - Cg00 L0040 L0242 L0444 L0646 L0848 L0a4a L0c4c L0e4e L0g4g  C00g Ld1h1 Ld4h4 Ld7h7 Ldaha Lddhd Ldghg C000 L59c9 L87c9 L8bc9  "  
{

//get image information 
fn=getTitle();
getDimensions(width, height, channels, slices, frames);
interval=Stack.getFrameInterval();
getVoxelSize(px, py, pz, unit);
tp=frames;
range1="1-"+slices;	

//get options
Dialog.create("Options");
	opt=newArray("Z-stacks", "Frames");
	Dialog.addChoice("Split image into: ", opt, "Frames");
	Dialog.addNumber("Number Images to Split into:", 6);
Dialog.show();

Type=Dialog.getChoice();
SplitNumber=Dialog.getNumber();

//get range of slices or frames 
if (Type=="Z-stacks"){
tp=slices;	
}

//error check
if (SplitNumber>tp){
	exit("Split number is greater than frames or slices");
}

//create range
for (extractImage=1;extractImage<=SplitNumber;extractImage++){

//reset range
range2="";

for (sl=1*extractImage;sl<=tp;sl+=SplitNumber){
	range2=range2+sl+",";
}
a=lengthOf(range2);
range2=substring(range2, 0, a-1);
//print(range);


//swap slices for frames if required
if (Type=="Z-stacks"){
range1=range2;
range2="1-"+frames;	
}



//extractImage images
ListOfFrames="channels=1-"+channels+" slices="+range1+" frames="+range2;

if (slices==1){
	ListOfFrames="channels=1-"+channels+" frames="+range2;
}


//print(ListOfFrames);
// create images
selectWindow(fn);
run("Make Substack...", ListOfFrames);
Stack.setFrameInterval(SplitNumber*interval);
getDimensions(wh, ht, ch, sl, fr);
if (slices==1){
run("Stack to Hyperstack...", "order=xyczt(default) channels=ch slices=fr frames=sl display=Color");
}
}
}




///////////////////////////////////////////////////////////8

macro "Area Time Plots (one channel) Action Tool - Caa0 L1a55 L56hd C000 T1507A T8507r Tb507e Tg507a T1g07T T6g07i T8g07m Tgg07e L000h L0hhh"
{
//initialize
run("Clear Results");
fn=getTitle();
run("Set Measurements...", "area mean min feret's display redirect=None decimal=3");
yscalelim=100000;

//get file info
getDimensions(ImageWidth, ImageHeight, ImageChannels, ImageSlices, ImageFrames);


if (ImageFrames==1 && ImageSlices==1){
	exit("This is not a time series");
}
if (ImageFrames==1 && ImageSlices!=1){
convert=getBoolean("Image has only 1 frame, but " + ImageSlices + " slicess, do you want to convert slices to frames");
if (convert==1){
run("Stack to Hyperstack...", "order=xyczt(default) channels=1 slices=" + ImageFrames + " frames=" + ImageSlices + " display=Color");
getDimensions(ImageWidth, ImageHeight, ImageChannels, ImageSlices, ImageFrames);
Stack.setTUnit("frame");
}
}

// create array
ChannelArea=newArray(ImageFrames);


//get plot details
Dialog.create("Plot Options");
  Dialog.addMessage("Pre-Processing Options: \n");
  Dialog.addCheckbox("Run Minimum Filter", false)
  Dialog.addNumber("Set Minimum Filter ", 4, 0, 6," pixels" );
  Dialog.addMessage("Select Detection Options: \n");
  Dialog.addNumber("Detected Area Size Minimum ", 25, 0, 6," pixels" );
  range = newArray(" Set own limits ", " Limit to upper area "," Limit to area range ");
  Dialog.addRadioButtonGroup("Select intensity range (y-axis)", range, 1, 4, " Limit to area range ");
  Dialog.addNumber("Low area value ", 0, 0, 6," pixels" );
  Dialog.addNumber("High area value ", yscalelim, 0, 6," pixels" );
  Dialog.addMessage("Enter dimensions of plot window");
  Dialog.addNumber("X dimension ", 650, 0, 4," pixels" );
  Dialog.addNumber("Y dimension ", 350, 0, 4," pixels" );
  Dialog.addMessage("Set line width");
  Dialog.addNumber("Line width ", 1, 0, 4," pixels" );  
Dialog.show;

filter = Dialog.getCheckbox();
minFilter = Dialog.getNumber();
minArea = Dialog.getNumber();
rangelimits = Dialog.getRadioButton();
lowy = Dialog.getNumber(); 
highy = Dialog.getNumber(); 
plotsizex = Dialog.getNumber(); 
plotsizey = Dialog.getNumber();
plotlinewidth = Dialog.getNumber();  
ymin=0;


//filter and threshold
if (filter==1){
run("Minimum...", "radius="+minFilter+" stack");
}


run("Threshold...");
title = "Get info";
msg = "set threshold\n then select OK to continue";
waitForUser(title, msg);
//analyse and get results
run("Analyze Particles...", "size="+minArea+"-Infinity show=Outlines display summarize include stack");

IJ.renameResults("Results","Individual measurements "+fn);

IJ.renameResults("Summary of "+fn,"Results");

for (fr=0;fr<ImageFrames;fr++){
  ChannelArea[fr]=getResult("Total Area", fr);
} 


//get y range
Array.getStatistics(ChannelArea, min, max, mean, stdDev);
highlevel=max;
lowlevel=min;

extend=(highlevel-lowlevel)*0.025;
highlevel=highlevel + extend;
lowlevel=lowlevel - extend;


//get x range
Frame_Interval=newArray(ImageFrames);
FrmInt=Stack.getFrameInterval();
if (FrmInt==0){
	FrmInt=1;
}
Stack.getUnits(X, Y, Z, Time, Value);
for (fr=1;fr<ImageFrames;fr++){
Frame_Interval[fr]=fr * FrmInt;
} 
Array.getStatistics(Frame_Interval, min, max, mean, stdDev);
xscalelen=max;
for (t=0;t<ImageFrames;t++){
      setResult("Frame Interval (" + Time + ")", t, Frame_Interval[t]);
}


//y range selection

if (rangelimits==" Set own limits "){
	ymax=highy;
	ymin=lowy;
}
if (rangelimits==" Limit to upper area "){
	ymax=highlevel;
	ymin=0;
}
if (rangelimits==" Limit to area range "){
	ymin=lowlevel;
	ymax=highlevel;
}



//main plot and results
Channel=newArray(ImageFrames);

        Plot.create(fn+" - Time Area Plot", "Time (" + Time + ")", "Area");
        Plot.setLimits(0, xscalelen, ymin, ymax);
        Plot.setFrameSize(plotsizex, plotsizey);
        Plot.setLineWidth(plotlinewidth);


		Plot.setColor("Red");     
        Plot.add("line",Frame_Interval, ChannelArea);
        Plot.addText("Total Area ", 0.1, 0);

Plot.show();
IJ.renameResults("Results",fn+" - Area Data");
}


////////////////////////////////////////////////////////9


macro "Set one image/stack for a stack/time series (v2.3) Action Tool - Cg00 L0141 L0444 L0747 L0a4a L0d4d L0g4g   C00g L61a1 L64a4 L67a7 L6aaa L6dad L6gag C000 Lc8g8" 
{
a=nImages; 
if(a>0){};
else {
	 exit("No Image open")
};

setBackgroundColor(0, 0, 0);

fl=getTitle();
getDimensions(width, height, channels, slices, frames);
w=width;
h=height;
ctot=channels;
ztot=slices;
ftot=frames;

if (ztot==1 && ftot==1) {
	exit("Image is not a multichannel z-stack or time series");
}

ID = getImageID();
title = "Get info";
msg = "Before you start you will either need to know:\n \n   - the channel you want changed \n   - the z-slice you want to copy \n   - the time point you want to copy \n \nor \n \nyou can select now the required channel, slice and frame on the image \n \n then select OK to continue";
waitForUser(title, msg);
selectImage(ID); 

rename("temp");

Stack.getPosition(channel, slice, frame)
a=channel;
b=slice;
c=frame;

all="";
for (i=1; i<=ctot; i++)
{
noc="c"+i+"=C"+i+"-temp ";
all=all + noc;
}
all= all + " create";

//input channel and slice info

Dialog.create("Select");
  Dialog.addMessage("Channel editing options");
  todo = newArray("Copy a single slice into a Z stack", "Clear all but one slice in a Z stack", 
  "Copy a Z stack into time series", "Copy a single slice into a Z stack in a time series" );
  Dialog.addRadioButtonGroup("What do you want to do?", todo, 4, 2, "Copy a single slice into a Z stack");
  Dialog.addMessage("Now enter channel number and  the Z-slice or the timepoint");
  Dialog.addNumber("Which channel", a, 0, 1,"" );
  Dialog.addNumber("Which Slice", b, 0, 1,"" );
  Dialog.addNumber("Which timepoint", c, 0, 1,"" );
Dialog.show;
  
op = Dialog.getRadioButton(); 
CH = Dialog.getNumber(); 
zsl = Dialog.getNumber();
fn = Dialog.getNumber();
//error checking
if (CH>ctot) {exit ("Channel does not exist");}
else if (zsl>ztot)  {exit("Z Slice does not exist");}
else if (fn>ftot)  {exit("Time point does not exist");}

run("Split Channels");

if (op == "Copy a single slice into a Z stack" )
{
Ch_z_stack();
}
else if (op == "Copy a Z stack into time series")
{
Ch_t_series();
}
else if (op == "Copy a single slice into a Z stack in a time series")
{
Ch_zt_series();
}
else if (op == "Clear all but one slice in a Z stack")
{
single_slice();
}

function Ch_z_stack()
{
//select source image
selectWindow("C" + CH + "-temp");
run("Duplicate...", "title=Slice duplicate range=zsl");
run("Copy");
//copy image to destination
selectWindow("C" + CH + "-temp");
for (z=1; z<=ztot; z++)
{
Stack.setSlice(z);
run("Paste");
}
}


function Ch_t_series()
{
//select source s
selectWindow("C" + CH + "-temp");
run("Duplicate...", "title=Slice duplicate slices=1-ztot frames=fn");

//copy images to destination
for (f=1; f<=ftot; f++)
{
for (z=1; z<=ztot; z++)
{
selectWindow("Slice");
Stack.setFrame(f);
Stack.setSlice(z);
run("Copy");
selectWindow("C" + CH + "-temp");
Stack.setFrame(f);
Stack.setSlice(z);
run("Paste");
}
}
}

function Ch_zt_series()
{
//select source s
selectWindow("C" + CH + "-temp");
run("Duplicate...", "title=Slice duplicate slices=zsl frames=fn");
selectWindow("Slice");
run("Copy");

selectWindow("C" + CH + "-temp");
//copy images to destination
for (f=1; f<=ftot; f++)
{
for (z=1; z<=ztot; z++)
{
Stack.setFrame(f);
Stack.setSlice(z);
run("Paste");
}
}
}

function single_slice()
{
//select source image
selectWindow("C" + CH + "-temp");
run("Duplicate...", "title=Slice duplicate range=zsl");
run("Copy");
//copy image to destination
selectWindow("C" + CH + "-temp");
//setTool("rectangle");
makeRectangle(0, 0, w, h);
run("Clear", "stack");
Stack.setSlice(zsl);
run("Paste");
}


//tidy up
selectWindow("Slice");
close();
run("Merge Channels...",all);
g= "altered " + fl;
rename(g);
}

////////////////////////////////////////////////////////////////////////10

macro "Manually tile 2 Z stacks Action Tool - Cg00 L0141 L0444 L0747 L0a4a L0d4d L0g4g   C00g Lc1g1 Lc4g4 Lc7g7 Lcaga Lcdgd Lcggg C000 L59c9 L5987 L598b   L53c3 L5381 L5385   L5fcf L5f8d L5f8h"  
{

//Manually align and join z-stacks

//Main image
title = "Main";
msg = "select main image to add to\n then select OK to continue";
waitForUser(title, msg);
destination=getTitle();

getDimensions(width_destination, height_destination, channels_destination, slices_destination, frames_destination);


//second image
title = "Insert";
msg = "Select second image to insert\n then select OK to continue";
waitForUser(title, msg);
source=getTitle();

getDimensions(width_source, height_source, channels_source, slices_source, frames_source);


if (channels_destination!=channels_source || slices_destination!=slices_source){
    title = "Warning!";
    msg = "Images have digfferent numbers of channels or slices";
waitForUser(title, msg);
	//	exit("Images have digfferent numbers of channels or slices")
}

Chans=newArray(channels_source);

//select options
Dialog.create("Select Options")
  Dialog.addMessage("Position to Insert Z-stack");
  Insert = newArray("Above", "Below", "Right", "Left");
  Dialog.addRadioButtonGroup("Direction", Insert, 1, 4, "Right");
  Dialog.addMessage("Select Channels to Insert");
  analyseChannel = newArray("Yes", "No");
  for (i=1; i<=channels_source; i++) {
  Ch="Channel " + i;
  Dialog.addRadioButtonGroup(Ch, analyseChannel, 1, 1, "Yes");
  }
Dialog.show(); 

//set options
InsertDir = Dialog.getRadioButton();
if (InsertDir=="Above"){
	InsertDir="Bottom-Center";
	xpos=width_destination*0.05;
	ypos=height_destination*0.05;
}
if (InsertDir=="Below"){
	InsertDir="Top-Center";
	xpos=width_destination*0.05;
	ypos=height_destination;
}
if (InsertDir=="Right"){
	InsertDir="Center-Left";
	xpos=width_destination;
	ypos=height_destination*0.05;
}
if (InsertDir=="Left"){
	InsertDir="Center-Right";
	xpos=width_destination*0.05;
	ypos=height_destination*0.05;
}



for (w=1;w<=channels_source;w++){
Chans[w-1] = Dialog.getRadioButton();
}

if (InsertDir=="Bottom-Center" || InsertDir=="Top-Center"){
	hi=height_destination+height_source+(height_source*0.1);
	wi=width_destination+(width_destination*0.1);
}
if (InsertDir=="Center-Left" || InsertDir=="Center-Right"){
	wi=width_destination+width_source+(width_source*0.1);
	hi=height_destination+(height_destination*0.1);
}

//expand main image
newcanvas="width=wi height=hi position=" + InsertDir + " zero";
selectWindow(destination);
run("Canvas Size...", newcanvas);

//adjust position for insert of second image
selectWindow(destination);
run("Specify...", "width=width_source height=height_source x=xpos y=ypos");
title = "Get info";
msg = "Draw/move Roi  \n then select OK to continue";
waitForUser(title, msg);

//do the copy

setBatchMode("hide");

for (chan=1;chan<=channels_source;chan++){
	if (Chans[chan-1]=="Yes"){
for (slice=1;slice<=slices_source;slice++){

selectWindow(source);
Stack.setPosition(chan, slice, 1);

run("Copy");


selectWindow(destination);
Stack.setPosition(chan, slice, 1);


run("Paste");
}
}
}

setBatchMode("exit and display");

}

///////////////////////////////////////////////11

macro "Copy overlay to all slices or frames Action Tool -C000 R00f8 R08f8 T4g08z Tbg08f Cg00 H44b48c00 " 
{

fn=getTitle();
getDimensions(width, height, channels, slices, frames);
n=roiManager("count");

	if (n>0){
//get plot details
Dialog.create("ROIs");
	opt = newArray("Yes","No");
		Dialog.addChoice("Do you want to keep existing ROI's", opt, "Yes")
Dialog.show;
	}

	
if (n>0){
answer=Dialog.getChoice();
if (answer=="No"){
roiManager("Reset");	
}
}

//draw rois
//roiManager("Reset");
title = "Add ROI's";
msg = "Add ROI's to ROI Manager - press t after each to add\n \n then select OK to continue";
waitForUser(title, msg);


n=roiManager("count");
if (n<1){
	exit("No Rois");
	}
run("Select None");
run("Duplicate...", "title=Overlay duplicate");

if (channels>1){
run("Make Composite");
run("RGB Color", "slices keep");
}


//set roi to position 1
for (roi=0;roi<n;roi++){
roiManager("Select",roi);
Stack.setPosition(1, 1, 1);
roiManager("Update");
roiManager("rename", "Slice/frame "+1+" Roi "+roi)
}

//check image
if (slices==1 && frames==1){
	exit("This macro does not work on a Z time series");
	}
if (slices>1 && frames==1){
	total=slices;
	type1=1;
	type2=0;
	}
if (slices==1 && frames>1){
	total=frames;
	type1=0;
	type2=1;
	}

//main process - copy rois to each slice/frame
selectWindow("Overlay");
for (slfr=2;slfr<=total;slfr++){

for (roi=0;roi<n;roi++){
roiManager("Select",roi);
roiManager("Add");
roiManager("Select",roi+n*(slfr-1));
Stack.setPosition(1, slfr*type1, slfr*type2);
roiManager("Update");
roiManager("rename", "Slice/frame "+slfr+" Roi "+roi)
}

}
	
//flatten
roiManager("Show All without labels");
run("Flatten", "stack");
rename(fn+" with Overlay");
}





////////////////////////////////////////////////////12

macro "Loading multichannel multi Zslice images Action Tool - Cg00 L0141 L0444 L0747 L0a4a L0d4d L0g4g C0g0 L61a1 L64a4 L67a7 L6aaa L6dad L6gag C00g Lc1g1 Lc4g4 Lc7g7 Lcaga Lcdgd Lcggg" 
{
	
//select location of images
input = getDirectory("Location for images");
ImageNumber=getNumber("Number of images ",3);

images=newArray(ImageNumber);
cols=newArray(ImageNumber);

newcol=newArray("Blue","Green","Red","Magenta","Cyan","Yellow","Light Blue","Grays");

//gets list of files
list = getFileList(input);

//dialogs
Dialog.create("Select images");

for (sel=0;sel<ImageNumber;sel++){
Dialog.addChoice("Select Image "+sel+1+" :", list, list[sel]);
Dialog.addChoice("Select LUT for Channel "+sel+1+" :", newcol, newcol[sel]);
}

Dialog.show(); 

merge="";

for (sel=0;sel<ImageNumber;sel++){
images[sel]=Dialog.getChoice();
cols[sel]=Dialog.getChoice();
full = input + images[sel];
open(full);
Bit=bitDepth();
Stack.getStatistics(voxelCount, mean, min, max, stdDev);
setMinAndMax(min,max);
//setMinAndMax(0, pow(2,Bit));
run(cols[sel]);
merge=merge+"c"+sel+1+"=["+images[sel]+"] ";


}

merge=merge+" create";

run("Merge Channels...", merge);
rename(images[0]+ "Merged");

getDimensions(ImageWidth, ImageHeight, ImageChannels, ImageSlices, ImageFrames);
Stack.setSlice(ImageSlices/2);

}




////////////////////////////////////////////////////13

macro "Create Random Cell Pattern Action Tool - C444 F00hh Cggg D55 D38 Df7 D4c D78 Ddb D7e D82 Da4 D9b Da7"
{
//initialise
run("Clear Results");
run("Set Measurements...", "area mean min stack display redirect=None decimal=3");

//get spot info
Dialog.create("Options");
	New=newArray("Use Existing Image Format","Create New Image");
	Dialog.addRadioButtonGroup("Image Options", New, 1, 2, New[0]);
	Dialog.addMessage("Cell options:");
	Dialog.addNumber("Number of Cells to Add:", 50);
	Dialog.addNumber("Cell diameter (pixels) must be odd:", 5);
	Dialog.addNumber("Maximum Distance cells move per frame in X (um):", 7);
	Dialog.addNumber("Maximum Distance cells move per frame in Y (um):", 7);
	Dialog.addNumber("Maximum Distance cells move per frame in Z (um):", 7);
	Dialog.addCheckbox("Print calculated locations", false);
	exl=newArray("No Inclusion/Exclusion Regions","Use existing Inclusion/Exclusion ROIs","Invert and Use Existing ROI's","Create New Inclusion ROIs by drawing","Create New Inclusion ROIs by threshold");
	Dialog.addRadioButtonGroup("Inclusion/Exclusion Options",exl, 5, 1, "No Inclusion/Exclusion Regions");
	Dialog.addCheckbox("Change INCLUDE ROI region to EXCLUDE during creation", false);
	Dialog.addCheckbox("Create mask image from the ROI's", false);
	Dialog.addCheckbox("Save ROI's", false);
Dialog.show(); 
	
//get responses
ImOpt=Dialog.getRadioButton()
total=Dialog.getNumber();
CellSize=Dialog.getNumber();
MaxTravelDistanceX=Dialog.getNumber();
MaxTravelDistanceY=Dialog.getNumber();
MaxTravelDistanceZ=Dialog.getNumber();
Pr=Dialog.getCheckbox();
Exclusion=Dialog.getRadioButton()
Inv=Dialog.getCheckbox();
maskIm=Dialog.getCheckbox();
SaveRoi=Dialog.getCheckbox();


//creatw new cell image
if (ImOpt=="Create New Image"){
Dialog.create("Options");
	Dialog.addNumber("Image Width:", 512);
	Dialog.addNumber("Image Height:", 512);
	Dialog.addNumber("Number Z slices", 10);
	Dialog.addNumber("Number of Frames", 25);
	bdepth=newArray(8,16);
	Dialog.addChoice("bit Depth", bdepth);
	Dialog.addNumber("Pixel size in X", 1);
	Dialog.addNumber("Pixel size in Y", 1);
	Dialog.addNumber("pixel size in Z", 5);
	Dialog.addString("units", "um");
Dialog.show(); 

wd=Dialog.getNumber();
ht=Dialog.getNumber();
sl=Dialog.getNumber();
fr=Dialog.getNumber();
bd=Dialog.getChoice();
px=Dialog.getNumber();
py=Dialog.getNumber();
pz=Dialog.getNumber();
unit=Dialog.getString();
	
newImage("Cells", bd+"-bit black", wd, ht,1,sl,fr);
setVoxelSize(px, py, pz, unit);
getDimensions(ImageWidth, ImageHeight, ImageChannels, ImageSlices, ImageFrames);
}else{



//create from existing image
fn=getTitle();
getDimensions(ImageWidth, ImageHeight, ImageChannels, ImageSlices, ImageFrames);
getVoxelSize(px, py, pz, unit);
Bit=bitDepth(); 
newImage("Cells", Bit+"-bit black", ImageWidth, ImageHeight,1,ImageSlices,ImageFrames);
}

//setup arrays
RoiSlice=newArray(ImageSlices);
rx=newArray(total);
ry=newArray(total);
rz=newArray(total);

//change inclsion to exclusion
inex="Inclusion";
if (Inv==true){
	inex="Exclusion";
}

//create roi options
if (Exclusion=="Create New Inclusion ROIs by drawing"){
	DrawRoi();
	Exclusion="Use existing Inclusion/Exclusion ROIs";
}

if (Exclusion=="Create New Inclusion ROIs by threshold"){
	ThreshRoi();
	Exclusion="Use existing Inclusion/Exclusion ROIs";
}


if (Exclusion=="Invert and Use Existing ROI's" ){
	n=roiManager("count");
	if (n!=ImageSlices){
		exit("missing ROI's");
	}
for (roi=0;roi<n;roi++){
roiManager("select", roi);
run("Make Inverse");
roiManager("update");
}
Exclusion="Use existing Inclusion/Exclusion ROIs";
}

if (Exclusion=="Use existing Inclusion/Exclusion ROIs"){
	n=roiManager("count");
	if (n!=ImageSlices){
		exit("missing ROI's");
	}
}


setBatchMode("hide");
///////////////////initial random positions
frame=1;
// all dots in image
for (dot=0;dot<total;dot++){ 
do{
rx[dot]=(random*ImageWidth*px);
ry[dot]=(random*ImageHeight*py);
rz[dot]=(random*ImageSlices*pz);
rslice=round(rz[dot]/pz);
}while (rslice<1 || rslice>ImageSlices);

/////exclusion routine
if (Exclusion=="Use existing Inclusion/Exclusion ROIs"){
Stack.setSlice(rslice);
roiManager("Select",rslice-1);
if (Roi.contains(rx[dot]/px, ry[dot]/px)==false ){
dot=dot-1;
}
}
}
//print results
if (Pr==true){
Table.create("Position Data");	
Table.setColumn("X t="+frame, rx);	
Table.setColumn("Y t="+frame, ry);
Table.setColumn("Z t="+frame, rz);			
}



////plot first dots
PlotDots();

//routine for rest of the frames
for (frame=2;frame<=ImageFrames;frame++){
MoveDots(rx,ry,rz);
PlotDots();
}


//finish up
run("Select None");
run("Grays");

//create mask
if (maskIm==true && Exclusion!="No Inclusion/Exclusion Regions" ){
	selectWindow("Cells");
	newImage("ROIs", Bit+"-bit black", ImageWidth, ImageHeight,1,ImageSlices,ImageFrames);
//	roiManager("Deselect");
//	roiManager("Remove Slice Info");

for (fr=0;fr<ImageFrames;fr++){
	Stack.setFrame(fr+1);
for (sl=0;sl<ImageSlices;sl++){
//	Stack.setSlice(Im+1);
	roiManager("Select",sl);
	run("Fill", "slice");
}
}
run("Select None");
a=pow(2, Bit);
level="code=v="+a+"-v stack";
run("Macro...", level);	
}

setBatchMode("exit and display");

//end

function MoveDots(rx,ry,rz){
for (dot=0;dot<total;dot++){
//newX position
direction=1;
sign=random;
if (sign<0.5){
direction=-1;
}
x2=rx[dot]+(random*MaxTravelDistanceX*direction);
//newY position
direction=1;
sign=random;
if (sign<0.5){
direction=-1;
}
y2=ry[dot]+(random*MaxTravelDistanceY*direction);
//newZ position
direction=1;
sign=random;
if (sign<0.5){
direction=-1;
}
z2=rz[dot]+(random*MaxTravelDistanceZ*direction);

/////exclusion routine
if (Exclusion=="Use existing Inclusion/Exclusion ROIs"){
rslice=round(z2/pz);
if (rslice>0 && rslice<=ImageSlices){
Stack.setSlice(rslice);
roiManager("Select",rslice-1);
if (Roi.contains(x2/px, y2/py)==false){
dot=dot-1;
}else{
	rx[dot]=(x2);
	ry[dot]=(y2);
	rz[dot]=(z2);
}
}
}else{
	rx[dot]=(x2);
	ry[dot]=(y2);
	rz[dot]=(z2);
}
}
//print results
if (Pr==true){
//Table.create("Position Data");	
Table.setColumn("X t="+frame, rx);	
Table.setColumn("Y t="+frame, ry);
Table.setColumn("Z t="+frame, rz);			
}
}


function PlotDots(){
//plot dots	
for (dot=0;dot<total;dot++){	
//converts Z into slice position in the image
rslice=round(rz[dot]/pz);
if (rslice>0 && rslice<=ImageSlices){
Stack.setSlice(rslice);
//roiManager("Select",rslice-1);
run("Specify...", "width="+CellSize+" height="+CellSize+" x="+(rx[dot]/px)+" y="+(ry[dot]/py)+" slice="+rslice+(ImageSlices*(frame-1))+" oval centered");
run("Colors...", "foreground=white background=black selection=white");
run("Fill", "slice");	
}
}
}


function DrawRoi(){
newImage("mask", "8-bit black", ImageWidth, ImageHeight,1,ImageSlices,1);
roiManager("reset");
getDimensions(MaskWidth, MaskHeight, MaskChannels, MaskSlices, MaskFrames);
setTool("freehand");
run("Select None");
Stack.setSlice(1);
for (roi=0;roi<MaskSlices;roi++){
run("Select None");
Stack.setSlice(roi+1);
waitForUser("","draw "+inex+" area slice "+roi+1);
if (Inv==true){
run("Make Inverse");
}
roiManager("Add");
}
//save rois
if (SaveRoi==true){
output = getDirectory("Output ditrectory for ROI's");
roiout = output + fn + " ROIs.zip";
roiManager("Save", roiout);
}
selectWindow("mask");
close();
selectWindow("Cells");
}



function ThreshRoi(){
waitForUser("","Duplicate 1 channel, 1 time point and full Z stack");
rename("mask"); 
roiManager("reset");
getDimensions(MaskWidth, MaskHeight, MaskChannels, MaskSlices, MaskFrames);
setAutoThreshold("Huang dark");
run("Threshold...");
waitForUser("","Set Threshold for "+inex+" area");
getThreshold(lower, upper);
run("Select None");
Stack.setSlice(1);
for (roi=0;roi<ImageSlices;roi++){
run("Select None");
Stack.setSlice(roi+1);
getRawStatistics(nPixels, mean, min, max, std, histogram);
if (max<lower || min>upper){
	run("Specify...", "width=1 height=1 x=0 y=0 slice="+roi+1+" centered");
} else {
	run("Create Selection");
}
if (Inv==true){
run("Make Inverse");
}
roiManager("Add");
}
//save rois
if (SaveRoi==true){
output = getDirectory("Output ditrectory for ROI's");
roiout = output + fn + " ROIs.zip";
roiManager("Save", roiout);
}
selectWindow("mask");
close();
selectWindow("Cells");
}
}




///////////////////////////////////////////////////////14



macro "Reverse Z in Hyperstack Action Tool -C000 T2d12Z Ld0dh Lb2d0 Lf2d0 Lbedh Lfedh" 
{

fn=getTitle();
getDimensions(ImageWidth, ImageHeight, ImageChannels, ImageSlices, ImageFrames);
getVoxelSize(px, py, pz, unit);

if (ImageSlices==1){
	exit("This is not a Z-stack");
}

setBatchMode("Hide");
selectWindow(fn);
run("Duplicate...", "title=tempStack duplicate slices=1-"+ImageSlices+" frames=1");
Reverse();
rename("NewSeries");
setBatchMode("exit and display");

if (ImageFrames>1){
setBatchMode("Hide");	
selectWindow("NewSeries");
run("Add Slice", "add=frame prepend");

for (fr=2;fr<=ImageFrames;fr++){
selectWindow(fn);
run("Duplicate...", "title=tempStack duplicate slices=1-"+ImageSlices+" frames="+fr);
Reverse();
run("Concatenate...", "  title=NewSeries image1=NewSeries image2=tempStack");
}

selectWindow("NewSeries");
Stack.setFrame(1);
run("Delete Slice", "delete=frame");
}	

setBatchMode("exit and display");

selectWindow("NewSeries");
rename(fn+" Reversed");
if (ImageChannels==1){
run("Stack to Hyperstack...", "order=xyczt(default) channels=ImageChannels slices=ImageSlices frames=ImageFrames display=Composite");
}

function Reverse(){
merge="";
Stack.setSlice(ImageSlices/2);
if (ImageChannels>1){
run("Split Channels");
for (ch=1;ch<=ImageChannels;ch++){
selectWindow("C"+ch+"-tempStack");
run("Reverse");
merge=merge+"c"+ch+"=[C"+ch+"-tempStack] ";
}
merge=merge+"create";
run("Merge Channels...", merge);
}
else {
run("Reverse");	
}
}
}

/////////////////////////////////////////////////15

macro "Bleach Corretion Simple Ratio method Action Tool - C000 T0508B T7508l T9508c Tf508h T0h08C T7h08o Tch08r Tgh08r "
{
//initialise
fn=getTitle();
//roiManager("reset");
print("\\Clear");

//options
Dialog.create("Bleach Correction");
Dialog.addMessage("Bleach Correction: This method will estimate a baseline intensity level");
Dialog.addMessage("in a selected background region (ROI) across the stack or time series.");
Dialog.addMessage("The Curve Fitting Tool using the Exponential with Offset equation");
Dialog.addMessage("(Formula: y = a*exp(-bx) + c) is used to get the value of c from this data.");
Dialog.addMessage("The Bleach Correction plugin using Simple Ratio and using the same ROI");
Dialog.addMessage("is run using this value of C as the background value.");
Dialog.addCheckbox("Show Fit Plot", false);
Dialog.addCheckbox("Show output Data", false);
Dialog.show();

//responses
Show_Plot=Dialog.getCheckbox();
Show_Data=Dialog.getCheckbox();


//draw and measure background roi
waitForUser("Draw ROI in background \n then press OK");
//roiManager("add");
run("Plot Z-axis Profile");
Plot.showValues();
xp=Table.getColumn("X");
yp=Table.getColumn("Y");
run("Close");
close();

//show results
if (Show_Data==true){
Fit.logResults;
}
//curve fitting
Fit.doFit("Exponential with Offset", xp, yp);
//show the plot and fit
if (Show_Plot==true){
Fit.plot;
}
//get data
back_ground=Fit.p(2);
log_data=getInfo("log");

//bleach correction
selectWindow(fn);
//run("Select None");
//roiManager("select", 0);
run("Bleach Correction", "correction=[Simple Ratio] background=back_ground");

//print data if wanted
print("\\Clear");
print(log_data);

}






