/*
* Macro to process a folder of LIFs into Channel Split and Channel Merged (Projected) images
*
* #### Change Log ####
* v0.1 - 1/23/20 - Initial Version - CK
*
* v0.2 - 1/30/20 - Changed script to split into up to 4 channels instead of RGB.
* Fixed handling of 2 channel images by changing the order in which channel colors are set. - CK
*
* v0.3 - 2/13/20 - Changed how the script handles saving files.
* Added in the ability to pick what colors you want each channel to be. Note the default order is Blue,Green,Red,Cyan.
* This script is also limited to handling only 4 channel images. If you somehow managed to image more channels than
* that let me know and share with me a test file and we can fix it.
* Added better dialog when running the script to make it as clear and easy to use as I can think of
* Added a parameter to allow for either a flat single channel RGB output or a multichannel tif output-- CK
*
* v0.4 - 2/14/20 - Added in an option to use Average Intensity Projection as well as Max Intensity Projection
* Added in an option to not project, useful to simply seperate out a lif into z-stacks tifs and set the colors. Still will be easier to work with the files and rename them.
* Added all the options for projections to the script
* Added a failsafe mode for when the user tries to split the Z-Stack into colors without projecting and trying to save as Flat images, now it will simply split the channels without projecting.
* Changed the color suffixes added to the filenames to be 2 letters, for clarity.
*/
macro "LIFs to TIFs" {
#@ String (visibility=MESSAGE, value="
How to use:
- Select the folder with the LIF files you want to process.
- Check the project box and select the type of projection you want to do.
- If it is unchecked you are simply seperating the LIF to make it easier to work with.
- If you are not projecting you can ignore the drop down box.
- Check Split Colors if you want to split into individual channels.
- Check TIFF Stack box if you want a multi-channel tiff as your maximum intensity projection output.
- Otherwise the output is a RGB image where adjusting the channel colors will be harder.
- Pick the colors you want for the corresponding channels.
- Do not worry about channels you do not have, if they don't exist in the LIF they will not be in the output. - The output will be in a folder that is named the same as the input folder but with '--Tiff' at the end.
", required=false) msg
#@ File (label = "Directory with LIF file(s):", style = "directory") input
#@ Boolean (label="Check to project:", value=true, persist=false) should_proj
#@ String (label = "Projection Type:", choices={"Max Intensity", "Average Intensity", "Min Intensity", "Sum Slices", "Standard Deviation", "Median"}, style="listBox", value="Max Intensity", persist=false) proj_type
#@ Boolean (label = "Check to Split Colors:", persist=false, value=false ) split_colors
#@ Boolean (label = "TIFF Stack:", persist=false, value = false) tiff_stack
#@ String (label = "Channel 1 color:", choices={"Blue", "Red","Green","Cyan","Magenta","Yellow", "Grays"}, style="listBox", value="Blue", persist=false) channel1_color
#@ String (label = "Channel 2 color:", choices={"Blue", "Red","Green","Cyan","Magenta","Yellow", "Grays"}, style="listBox", value="Green", persist=false) channel2_color
#@ String (label = "Channel 3 color:", choices={"Blue", "Red","Green","Cyan","Magenta","Yellow", "Grays"}, style="listBox", value="Red", persist=false) channel3_color
#@ String (label = "Channel 4 color:", choices={"Blue", "Red","Green","Cyan","Magenta","Yellow", "Grays"}, style="listBox", value="Cyan", persist=false) channel4_color
// required for naming the color splits, as imageJ1macro does not support string indexing eq. string[0]
channel1_color_first = substring(channel1_color, 0, 2);
channel2_color_first = substring(channel2_color, 0, 2);
channel3_color_first = substring(channel3_color, 0, 2);
channel4_color_first = substring(channel4_color, 0, 2);
if (tiff_stack == 0 && split_colors == 1 && should_proj == 0) tiff_stack = 1 ;{} //cant split colors without Projecting unless you are keeping TIF stacks
run("Bio-Formats Macro Extensions");
suffix = ".lif"; //global variable thats used inside processFolder(input)
setBatchMode(true);
processFolder(input);
run("Collect Garbage"); //It seems like imageJ isnt gracefully saving things without this.
showMessage(" -- Finished! --"); // this allows the user to know when they can look at their files
run("Close All");
Ext.close();
setBatchMode(false);
// function to scan folders/subfolders/files to find files with correct suffix
function processFolder(input) {
list = getFileList(input);
list = Array.sort(list);
inputParent = File.getParent(input);
inputName = File.getName(input);
// create folders for the tifs
output = inputParent+File.separator+inputName+"--Tiff";
if (File.exists(output)==false) {
File.makeDirectory(output); // new directory for tiffs
}
for (k = 0; k < list.length; k++) {
if(File.isDirectory(input + File.separator + list[k]))
processFolder(input + File.separator + list[k]);
if(endsWith(list[k], suffix))
lifToTiffRGBSplit(input, output, list[k]);
showProgress(k+1, list.length);
}
}
function splitColors() {
if( split_colors == 1 ){
run("Duplicate...", "duplicate");
mergeChannelsFnc();
run("Split Channels");
for (i=1;i<=channels;i++) {
selectImage(i);
out_path = output + File.separator+name+"_"+seriesname+"_MIP_"+j +" " + color_name[i] +".tif";
saveAs("Tiff", out_path);
}
} else {
mergeChannelsFnc();
}
}
function mergeChannelsFnc() {
if (tiff_stack == 1) {
//if (should_proj == 1) { // lets you keep the different channels if projected for the final merged flat image.
//run("Make Composite");
saveAs("Tiff", output+File.separator+name+"_"+seriesname+"_MIP_"+j+".tif");
close();
//} else { // this gives us RGB Z stacks output for non-max projected, stacks. essentially just the output of the
//run("RGB Color","slices");
//saveAs("Tiff", output+File.separator+name+"_"+seriesname+"_MIP_"+j+".tif");
//close();
//}
} else {
//this is where i need the logic to fix making tif RGB stacks tiff==1, split_colors==0, Proj == 0
// make a for loop to split each z step, run RGB TRYING run("RGB Color", slices) first
run("RGB Color");
saveAs("Tiff", output+File.separator+name+"_"+seriesname+"_MIP_"+j+".tif");
close();
close();
}
}
function setChannelColors(){ //This function allows the user to set the colors. It is done in reverse order so that if there are less than 4 colors they are still assigned correctly
Stack.setChannel(4);
run(channel4_color);
Stack.setChannel(3);
run(channel3_color);
Stack.setChannel(2);
run(channel2_color);
Stack.setChannel(1);
run(channel1_color);
}
//"", , "Standard Deviation",
function whichProjToDo() {
if (should_proj == 1) {
run("Z Project...", "projection=[" + proj_type + "]");
if( proj_type == "Max Intensity"){
proj_prefix = "MAX_";
} else if (proj_type == "Average Intensity") {
proj_prefix = "AVG_";
} else if (proj_type == "Min Intensity"){
proj_prefix = "MIN_";
} else if (proj_type == "Sum Slices"){
proj_prefix = "SUM_";
} else if (proj_type == "Standard Deviation"){
proj_prefix = "STD_";
} else if (proj_type == "Median"){
proj_prefix = "MED_";
}
return proj_prefix;
} else {
return 0;
}
}
function lifToTiffRGBSplit(input, output, file) {
color_name = newArray(" ", channel1_color_first, channel2_color_first, channel3_color_first , channel4_color_first); // need this for naming the output
path= input + File.separator + list[k];
//how many series in this lif file?
Ext.setId(path);//-- Initializes the given path (filename).
Ext.getSeriesCount(seriesCount); //-- Gets the number of image series in the active dataset.
//this is the loop that processes all the images WITHIN the LIF file.
for (j=1; j<=seriesCount; j++) {
run("Bio-Formats", "open=path autoscale color_mode=Default view=Hyperstack stack_order=XYCZT series_"+j);
name=File.nameWithoutExtension;
//retrieve name of the series from metadata
text=getMetadata("Info");
n1=indexOf(text," Name = ")+8;
// the Line in the Metadata reads "Series 0 Name = ". Complete line cannot be taken, because
// The number changes of course. But at least in the current version of Metadata this line is the
// only occurence of " Name ="
n2=indexOf(text,"SizeC = "); // this is the next line in the Metadata
seriesname=substring(text, n1, n2-2);
seriesname=replace(seriesname,"/","-");
rename(seriesname);
getDimensions(w, h, channels, slices, frames); //needed to we know how many channels we are working with, lets the logic work below.
//project and save logic
if(Stack.isHyperstack) {
proj_prefix = whichProjToDo();
if (nSlices>1) Stack.setDisplayMode("composite");{
selectWindow(seriesname);
if (should_proj == 1) {
close(); //closes non-projected window if the projection was made
selectWindow(proj_prefix + seriesname);//selects the projection and works with that. Not needed if not projecting anything
}
setChannelColors();
splitColors();
}
}
else if (nSlices>1) {
if (nSlices>1) Stack.setDisplayMode("composite");{
setChannelColors();
splitColors();
}
}
else {
Stack.setDisplayMode("composite");
setChannelColors();
splitColors();
}
run("Close All");
run("Collect Garbage");
}
Ext.close();
}
}