Produce max projections from LIF files in imageJ

How can I produce max projections from all of the image stacks in a lif file project saved from a confocal microscope? Right now I am using the Definiens Tissue Studio software to open the lif file which then contains many image stacks. Then I need to click through each image stack and make a max projection tif file one image stack file at a time. With a lot of image stacks this can be tedious, time consuming, and error prone. Is there a way I can use imageJ to automatically batch process all of the image stacks in a life file and output a max projection tif file for each lif file?

Hi @azim58

Using the ImageJ-Integration in KNIME Image Processing you can easily apply the image stack projection to all images at once.

Here I created a small example workflow:


You can download it from here (9.0 KB).

To open this workflow install KNIME + all free extensions and then use File > Import KNIME Workflow to open the example.

5 Likes

Okay great! Thanks for the information!

You can also accomplish this in the ImageJ application itself using its batch processing functionality.

For an overview, see:

You will use the Bio-Formats plugin to open the LIF files. If the LIF files are too large and you cannot load all images into memory at once, then you may need to open them one series at a time, using the Bio-Formats API (or the Bio-Formats Macro Extensions if you are writing a macro). If you need to go this route, let us know and we can reply back on this thread with more details.

2 Likes

I happen to have a macro that does what you want. It is pasted below.

macro 'convert LIF tiff' {

/*
 * - converts LIF files into TIFF. 
 * - the macro ask for an input folder that should contain 1 or more lif files. Nothing else.
 * - each series is saved as one tiff. The name of the series is appended to the file name.
 * - if the series has more the one frame, a Max Intensity projection is performed before saving
 * - the TIFFs are saved in a folder generated by the macro
 * 
 * Martin Hoehne, August 2015
 */
run("Bio-Formats Macro Extensions");


dir1 = getDirectory("Choose folder with lif files ");
list = getFileList(dir1);

setBatchMode(true);

// create folders for the tifs
	dir1parent = File.getParent(dir1);
	dir1name = File.getName(dir1);
	dir2 = dir1parent+File.separator+dir1name+"--Tiff_MIP";
	if (File.exists(dir2)==false) {
				File.makeDirectory(dir2); // new directory for tiff
		}
 
for (i=0; i<list.length; i++) {
	showProgress(i+1, list.length);
	print("processing ... "+i+1+"/"+list.length+"\n         "+list[i]);
	path=dir1+list[i];

	//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.
	
	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,"Image name = ")+13;// 13 Zeichen
		n2=indexOf(text,"Location = ");
		seriesname=substring(text, n1, n2-1);

	//project and save
		if (nSlices>1) {
			run("Z Project...", "projection=[Max Intensity]");
			saveAs("TIFF", dir2+File.separator+name+"_"+seriesname+"_MIP");
		}
		else saveAs("TIFF", dir2+File.separator+name+"_"+seriesname);
		run("Close All");
		run("Collect Garbage");
		
	}

}
showMessage(" -- finished --");	
run("Close All");
setBatchMode(false);

} // macro
2 Likes

Great! Thanks a lot! This macro looks really useful!

I used the macro only for single channel (time) series and it worked fine. Now I tried with multi-channel z-stacks and it failed.
Below is a corrected version that works with both for me.

macro 'convert LIF tiff' {

/*
 * - converts LIF files into TIFF. 
 * - the macro ask for an input folder that should contain 1 or more lif files. Nothing else.
 * - each series is saved as one tiff. The name of the series is appended to the file name.
 * - if the series has more the one frame, a Max Intensity projection is performed before saving
 * - the TIFFs are saved in a folder generated by the macro
 * 
 * Martin Hoehne, August 2015
 * 
 *  Update October 2015: works for Multichannel images as well
 */
run("Bio-Formats Macro Extensions");


dir1 = getDirectory("Choose folder with lif files ");
list = getFileList(dir1);

setBatchMode(true);

// create folders for the tifs
	dir1parent = File.getParent(dir1);
	dir1name = File.getName(dir1);
	dir2 = dir1parent+File.separator+dir1name+"--Tiff_MIP";
	if (File.exists(dir2)==false) {
				File.makeDirectory(dir2); // new directory for tiff
		}
 
for (i=0; i<list.length; i++) {
	showProgress(i+1, list.length);
	print("processing ... "+i+1+"/"+list.length+"\n         "+list[i]);
	path=dir1+list[i];

	//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.
	
	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);
	//project and save
		if (nSlices>1) {
			run("Z Project...", "projection=[Max Intensity]");
			if (nSlices>1) Stack.setDisplayMode("composite");
			saveAs("Tiff", dir2+File.separator+name+"_"+seriesname+"_MIP.tif");
		}	
		else saveAs("TIFF", dir2+File.separator+name+"_"+seriesname+".tif");
		run("Close All");
		run("Collect Garbage");
		
	}

}
showMessage(" -- finished --");	
run("Close All");
setBatchMode(false);

} // macro
2 Likes

Ah okay good to know. I’ve been sidetracked with some other projects so I haven’t even tried the first macro yet. It is good to know that you made this macro though in case I or anyone else needs it! Thanks a lot!!

I found this post very useful, thank you MartinH for the macro. We have a new SP8 confocal, and it is often easier to have the files as separate tiffs rather than lifs. However, if you use mark and find to create a list of positions to image, LasX creates a subfolder in the life for these images called MarkandFind001 etc. This in itself wouldn’t be a problem, but the image name is stored as MarkandFind001/position001 etc. You cannot save a file with / in it’s name.

Therefore, I have altered the macro to take this into account. It removes the / if it is present in the filename. I’ve also altered to save both the original stack and a MIP if the data are z stacks.

Here is the altered version from me, if it is of use to anyone. Please check it has formatted okay on your machine- linux text editors often end up with long lines that may have then have carriage returns added in them in windows, so some commented lines may have ended up as half uncommented.

macro 'convert LIF tiff' {

/*
 * - converts LIF files into TIFF. 
 * - the macro ask for an input folder that should contain 1 or more lif files. Nothing else.
 * - each series is saved as one tiff. The name of the series is appended to the file name.
 * - if the series has more than one frame, a Max Intensity projection is also performed 
 * - before saving. The TIFFs are saved in a folder generated by the macro in the same 
 * - parent folder as the lifs, with the same prefix for the folder name, with TIFF suffix.
 * 
 * Martin Hoehne, August 2015
 * 
 *  Update October 2015: works for Multichannel images as well
 *
 * Update Jan2016 (Glyn Nelson).  Now also saves z stack as well as mip if it is a z stack.
 *  This works with SP8 images as long as they aren't in subfolders, such as Mark and Find: these
 *  images have a '/' in their name, so it throws an error when trying to save. 
 * Update Jan2016 (Glyn Nelson).  Fixed.  IT will now remove / if it exists in the imagename before saving. 
 */
run("Bio-Formats Macro Extensions");


dir1 = getDirectory("Choose folder with lif files ");
list = getFileList(dir1);

setBatchMode(true);

// create folders for the tifs
	dir1parent = File.getParent(dir1);
	dir1name = File.getName(dir1);
	dir2 = dir1parent+File.separator+dir1name+"_Tiff";
	if (File.exists(dir2)==false) {
				File.makeDirectory(dir2); // new directory for tiff
		}
 
for (i=0; i<list.length; i++) {
	showProgress(i+1, list.length);
	print("processing ... "+i+1+"/"+list.length+"\n         "+list[i]);
	path=dir1+list[i];

	//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.
	
	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
		extractedname=substring(text,n1,n2-2);
		cleanname=split(extractedname,"/");  // this is done here to remove the forward slash that is found in the image name 
					// if it is part of a mark and find subfolder, for example 

//We still want both parts of the filenename.  So if there are two parts to the array, then stick them together, otherwise just take the first:
		if (cleanname.length==2){
			seriesname=cleanname[0]+cleanname[1];
			}		
		else seriesname=cleanname[0];
	//project and save
		if (nSlices>1) {
			run("Z Project...", "projection=[Max Intensity]");
			if (nSlices>1) Stack.setDisplayMode("composite");
			saveAs("Tiff", dir2+File.separator+name+"_"+seriesname+"_MIP.tif");
			close();
			saveAs("TIFF", dir2+File.separator+name+"_"+seriesname+".tif");
		}	
		else saveAs("TIFF", dir2+File.separator+name+"_"+seriesname+".tif");
		run("Close All");
//		run("Collect Garbage");
		
	}

}
showMessage(" Well, I think we gave them a damn good thrashing there, what what??");	
run("Close All");
setBatchMode(false);
2 Likes

Thank you MartinH. This macro is very helpful for batch processing lif files with some modification.

Thank you MartinH. The script was working for some LIF files, but then it was not working if the LIF file contained subfolders. Also, the output files from the script were tif files (e.g. 8-bit tif files) with multiple channels, but I was hoping to get tif files with all of the color channels merged so that they were tif files in RGB format. I have pasted the modified script below which will handle LIF files with subfolders and also output tif files in RGB format with all of the color channels merged. However, now I still have a problem. For some of my LIF files, I receive an error which says “A 2 or 3 image stack, or a HyperStack, required”. I think this happens because some of the images in my LIF file are not stacks but just single images. Is there some way that the script can be modified so that it will continue and not breakdown when there are these kind of exceptions? I already have LIF files like this with these exceptions, and I don’t know how I can change these LIF files.

macro 'convert LIF tiff' {

/*
 * - converts LIF files into TIFF. 
 * - the macro ask for an input folder that should contain 1 or more lif files. Nothing else.
 * - each series is saved as one tiff. The name of the series is appended to the file name.
 * - if the series has more the one frame, a Max Intensity projection is performed before saving
 * - the TIFFs are saved in a folder generated by the macro
 * 
 * Martin Hoehne, August 2015
 * 
 *  Update October 2015: works for Multichannel images as well
 */
run("Bio-Formats Macro Extensions");


dir1 = getDirectory("Choose folder with lif files ");
list = getFileList(dir1);

setBatchMode(true);

// create folders for the tifs
    dir1parent = File.getParent(dir1);
    dir1name = File.getName(dir1);
    dir2 = dir1parent+File.separator+dir1name+"--Tiff_MIP";
    if (File.exists(dir2)==false) {
                File.makeDirectory(dir2); // new directory for tiff
        }
 
for (i=0; i<list.length; i++) {
    showProgress(i+1, list.length);
    print("processing ... "+i+1+"/"+list.length+"\n         "+list[i]);
    path=dir1+list[i];

    //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.
    
    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);

        
    //project and save
        if (nSlices>1) {
            run("Z Project...", "projection=[Max Intensity]");
            if (nSlices>1) Stack.setDisplayMode("composite");
            
{run("Stack to RGB");
            saveAs("Tiff", dir2+File.separator+name+"_"+seriesname+"_MIP.tif");
}
        }    
        else 
        {run("Stack to RGB");
        saveAs("TIFF", dir2+File.separator+name+"_"+seriesname+".tif");
}
        run("Close All");
        run("Collect Garbage");
        
    }

}
showMessage(" -- finished --");    
run("Close All");
setBatchMode(false);

} // macro

Okay I fixed the problem I was having with the error with lif files which contained images without multiple planes in a stack. I also fixed a few other things that could have caused problems (e.g. if two different images had the same name they would have been overwritten with the previous script). This new script is working for me in a variety of situations. The script can go through a lif file and make maximum projections, merge the channels, and output rgb tifs.

macro 'convert LIF tiff' {

/*
 * - converts LIF files into TIFF. 
 * - the macro ask for an input folder that should contain 1 or more lif files. Nothing else.
 * - each series is saved as one tiff. The name of the series is appended to the file name.
 * - if the series has more the one frame, a Max Intensity projection is performed before saving
 * - the TIFFs are saved in a folder generated by the macro
 * 
 * Martin Hoehne, August 2015
 * 
 *  Update October 2015: works for Multichannel images as well
 *  Update October 2016 by azim58: works for lif which contain images that are not stacks.  The script will also not overwrite images if they have the same name.
 */
run("Bio-Formats Macro Extensions");


dir1 = getDirectory("Choose folder with lif files ");
list = getFileList(dir1);

setBatchMode(true);

// create folders for the tifs
    dir1parent = File.getParent(dir1);
    dir1name = File.getName(dir1);
    dir2 = dir1parent+File.separator+dir1name+"--Tiff_MIP";
    if (File.exists(dir2)==false) {
                File.makeDirectory(dir2); // new directory for tiff
        }
 
for (i=0; i<list.length; i++) {
    showProgress(i+1, list.length);
    print("processing ... "+i+1+"/"+list.length+"\n         "+list[i]);
    path=dir1+list[i];

    //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.
    
    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);

        
    //project and save
    if(Stack.isHyperstack)
    {
        run("Z Project...", "projection=[Max Intensity]");
            if (nSlices>1) Stack.setDisplayMode("composite");
        {
            
            run("RGB Color");
            
            saveAs("Tiff", dir2+File.separator+name+"_"+seriesname+"_MIP_"+j+".tif");
        }
    }
        else if (nSlices>1) {
            if (nSlices>1) Stack.setDisplayMode("composite");
        {
            
            run("RGB Color");
            
            saveAs("Tiff", dir2+File.separator+name+"_"+seriesname+"_MIP_"+j+".tif");
        }
        }    
        else 
        {
        Stack.setDisplayMode("composite");
        run("Stack to RGB");
        saveAs("Tiff", dir2+File.separator+name+"_"+seriesname+"_MIP_"+j+".tif");
    }
        run("Close All");
        run("Collect Garbage");
        
    }

}
showMessage(" -- finished --");    
run("Close All");
setBatchMode(false);

} // macro
3 Likes

Thank you, @azim58, @Glyn_Nelson, @MartinH for sharing and perfecting this macro, which just saved me a ton of work!

In the spirit of the thread I’ll share my modified version in case it is of use to anyone. It preserves bit depth (no RGB conversion) and has a parameter to easily change whether it saves a Z projection or the intact stack.

macro 'convert LIF tiff' {

/*
 * - converts LIF files into TIFF. 
 * - the macro ask for an input folder that should contain 1 or more lif files. Nothing else.
 * - each series is saved as one tiff. The name of the series is appended to the file name.
 * - if the series has more the one frame, a Max Intensity projection is performed before saving
 * - the TIFFs are saved in a folder generated by the macro
 * 
 * Martin Hoehne, August 2015
 * 
 *  Update October 2015: works for Multichannel images as well
 *  Update October 2016 by azim58: works for lif which contain images that are not stacks.  The script will also not overwrite images if they have the same name.
 *  Update March 2017 by Theresa Swayne: bit depth is preserved, Z projection is optional 
 *  
 */

Z_PROJECT = "True"; // "True" to make a max projection; "False" to leave z stacks intact

run("Bio-Formats Macro Extensions");

dir1 = getDirectory("Choose folder with lif files ");
list = getFileList(dir1);

setBatchMode(true);

// create folders for the tifs
dir1parent = File.getParent(dir1);
dir1name = File.getName(dir1);
dir2 = dir1parent+File.separator+dir1name+"--Tiff_MIP";
if (File.exists(dir2)==false) 
	{
	File.makeDirectory(dir2); // new directory for tiff
    }
 
for (i=0; i<list.length; i++) 
	{
    showProgress(i+1, list.length);
    print("processing ... "+i+1+"/"+list.length+"\n         "+list[i]);
    path=dir1+list[i];

    //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.
    
    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);
		
	    // project and save
    	getDimensions(width, height, channels, slices, frames); // check if is a stack of any kind
    	if (slices>1) // it is a z stack
    		{
        	if (Z_PROJECT == "True")
        		{
        		run("Z Project...", "projection=[Max Intensity]");
        		selectWindow("MAX_"+seriesname);
        		}
	        saveAs("Tiff", dir2+File.separator+name+"_"+seriesname+"_MIP_"+j+".tif");    
    		}
        else
        	{
	        saveAs("Tiff", dir2+File.separator+name+"_"+seriesname+"_MIP_"+j+".tif");
        	}    
        run("Close All");
        run("Collect Garbage");
    	}
	}
showMessage(" -- finished --");    
run("Close All");
setBatchMode(false);

} // macro


3 Likes

Hi all,

I appreciate you guys posting your code. I am trying to convert from .lif to .ome-tiff and was not able to get the saveAs function to work. Are there any other solutions to exporting files as .ome-tiff? I am running into bugs trying this code for a list of files in a directory.

Thanks

path = getDirectory(“ImageExpt_Chi”);
outputFolder = getDirectory("/Users/labadmin/Desktop/From confocal”)
filelist = getFileList(path); //load array of all files inside input directory
for (i=0; i< filelist.length; i++) {
// process lif files only
if (endsWith(filelist[i], “.lif”)) {
// open file, requires LOCI tools (aka Bio-Formats)
run(“Bio-Formats Importer”, “open= + path + filelist[i] color_mode=Default view=Hyperstack stack_order=XYCZT”);
run(“Bio-Formats Exporter”, “save=” + outputFolder + filelist[i] + “.ome.tif export compression=Uncompressed”);

when I record the Save As OME-TIFF command I get

run("OME-TIFF...", ....

did you try already a version of your macro with

run("OME-TIFF...", "save=" + outputFolder + filelist[i] + ".ome.tif export compression=Uncompressed");
1 Like

Thanks! I will try that, but in my experience Bioformats has less freeze when saving to ome-tiff.

Another question: For multi-channel data the script included combines the channels into one tif stack, is there a way to save each channel as a separate data stack?

You guys are my Heros tonight. Thanks. :slight_smile:

OMG!!! Thank you a lot, I spent all my morning trying to understand whey it didnt work for me, now I know :slight_smile:

Thank you again,
Monara