User Tools

Site Tools


documents:101029imagej_cui_lifconversion

Command Line: LIF to Tiff conversion

LIF is a grouped-stack file format containing multiple stacks. One could access each stack by LOCI Bio-Format plugin installed to ImageJ, but when file size is huge and data is in data server, data transfer rate becomes a bottle neck for the progress of work.

TO avoid this, one could do the file conversion via command line. This could be done by "bfconvert" command line tool available from Bio-format web site. Following command will do the job, converting all.

sh /g/almf/software/bftools/bfconvert <filename.lif>   converted_%s_%n_C%c.tiff

One missing function with this CL tool is that physical scales in x, y and z are not read out from LIF so that resulting Tiff stacks are devoid of these parameters. In addition, dimensional values such as number of slices per time point, and number of time points are not converted.

For this reason, following shell script was created to transfer physical scales in together with conversion.

sh /g/almf/software/ij/lifcon.sh </full/path/to/file.lif>

This script will extract metadata from LIF, convert each stack to Tiff stack, and set the physical parameters of the image by extracting these values from metadata. Tiff stack will be saved under a newly created directly where the LIF is located. Name of the directory will be

<file.lif>_tifStack

A text file named

<filename.lif>.meta.txt

is also generated, where extracted metadata is stored.

How Metadata is Extracted

Bioformat commandline tool “showinf” is used to save metadata as a text file. Then During the extraction of tiff stacks, physical scales and dimensionality information is extracted from the text and applied to the tiff stack.

Since macro command run(“Properties…”, arg1, arg2) does not work when IJ is headless since Properties command uses AWT. To avoid this, a small plugin (that does not appear in the menu) was created for setting image properties. This plugin is called from macro to set physical scales.

Link for the Image Property setter.

Shell Script lifcon.sh

#!/bin/sh
#script for converting Lif file to tif, and set physical scale.  
#
imgfullpath=$1

# path to IJ jar file
IJJARS="/g/almf/software/ij"

# path to image 
IMGFILE="${imgfullpath##*/}"
IMGPATH="${imgfullpath%/*}"
METAFULLPATH="${imgfullpath}.meta.txt"
echo ${METAFULLPATH}

# Lif converting IJ macro name
IJMACRONAME="LifOpenerCUI.ijm"

#timer
jobstart=$(date +%s)

sh /g/almf/software/bftools/showinf -nopix -nocore ${imgfullpath}>${METAFULLPATH}

chmod ugo+x ${METAFULLPATH}

/usr/struct/bin/java -cp ${IJJARS}/headless.jar:${IJJARS}/ij-1.44h.jar -Djava.awt.headless=true ij.ImageJ -ijpath ${IJ
JARS} -batch ${IJJARS}/${IJMACRONAME} ${imgfullpath}

# timer
jobend=$(date +%s)
echo "Time: $((jobend-jobstart)) secs."

ImpProps.java

Accessing Image Physical Properties. Compiled class should be copied to the imageJ plugin folder. Original java code was modified to access image properties scales and dimensions.

import ij.*;
import ij.measure.Calibration;
//import java.lang.Double;
/**
 * This simple class can be called from an ImageJ macro via the "call" mechanism to
 * get and set the (string) properties of the active image (ImagePlus). 
 *
 * call("ImpProps.setProperty", "<key>", "<value>");
 *	set property <key> to <value>, returns <value> if successful, 
 *	"" otherwise (no active image)
 *
 * call("ImpProps.getProperty", "<key>");
 *	returns value of property <key> if set, "" otherwise (not found or no active image)
 *
 * @see    ij.ImagePlus#setProperty
 * @see    ij.ImagePlus#getProperty
 *
 * @author Joachim Wesner
 * @author Leica Microsystems CMS GmbH
 * @author joachim.wesner@leica-microsystems.com
 * @version 2008-3-15
 * 
 * @author Kota Miura
 * cmci, embl
 * added methods for setting image dimension sizes and pixel scales. 
 * this was done for setting these values in headless mode. 
 * @version 2010-10-28
 * This class can be compiled with ImageJ's Plugins>Compile and Run command.
 */

public class ImpProps {

	//kota
	public static String getProperties() {
		ImagePlus imp = WindowManager.getCurrentImage();
		if (imp == null)
			return "";
		Object prop = imp.getProperties();
		if (prop != null && prop instanceof String)
			return (String)prop;
		else
			return "";
	}

	public static String setProperty(String arg1, String arg2) {
		ImagePlus imp = WindowManager.getCurrentImage();
		if (imp == null)
			return "";
		imp.setProperty(arg1, arg2);
		imp.updateAndDraw();
		return arg2;
	}

	public static String getProperty(String arg1) {
		ImagePlus imp = WindowManager.getCurrentImage();
		if (imp == null)
			return "";
		Object prop = imp.getProperty(arg1);
		if (prop != null && prop instanceof String)
			return (String)prop;
		else
			return "";
	}

	//kota
	public static int setCalibration(String unit, String spixelWidth, String spixelHeight, String spixelDepth){
		double pixelWidth = java.lang.Double.parseDouble(spixelWidth);
		double pixelHeight = java.lang.Double.parseDouble(spixelHeight);
		double pixelDepth = java.lang.Double.parseDouble(spixelDepth);
		ImagePlus imp = WindowManager.getCurrentImage();
		if (imp == null)
			return -1;
		Calibration cal = imp.getCalibration();
		cal.setUnit(unit);
		cal.pixelWidth = pixelWidth;
		cal.pixelHeight = pixelHeight;
		cal.pixelDepth = pixelDepth;
		imp.setCalibration(cal);
		WindowManager.repaintImageWindows();
		return 1;
	}

	//kota
	public static int setCalibration(
		String schannels, String sslices, 
			String sframes, String unit, 
				String spixelWidth, String spixelHeight, 
					String spixelDepth) {
		int channels = java.lang.Integer.parseInt(schannels);
		int slices   = java.lang.Integer.parseInt(sslices);
		int frames   = java.lang.Integer.parseInt(sframes);
		double pixelWidth  = java.lang.Double.parseDouble(spixelWidth);
		double pixelHeight = java.lang.Double.parseDouble(spixelHeight);
		double pixelDepth  = java.lang.Double.parseDouble(spixelDepth);
		
		ImagePlus imp = WindowManager.getCurrentImage();
		if (imp == null)
			return -1;
		int stackSize = imp.getImageStackSize();			
		if (channels*slices*frames==stackSize)
 			imp.setDimensions(channels, slices, frames);
 		else
 			IJ.error("Properties", "The product of channels ("+channels+"), slices ("+slices
 				+")\n and frames ("+frames+") must equal the stack size ("+stackSize+").");
		Calibration cal = imp.getCalibration();
		cal.setUnit(unit);
		//cal.setTimeUnit(IJ.micronSymbol + "sec");
		cal.pixelWidth = pixelWidth;
		cal.pixelHeight = pixelHeight;
		cal.pixelDepth = pixelDepth;
		imp.setCalibration(cal);
		WindowManager.repaintImageWindows();
		return 1;
	}
}

bfconvert help

To convert a file between formats, run:

bfconvert [-debug] [-stitch] [-separate] [-merge] [-expand]
  [-bigtiff] [-compression codec] [-series series] [-map id]
  in_file out_file
  1. debug: turn on debugging output
  2. stitch: stitch input files with similar names
  3. separate: split RGB images into separate channels
  4. merge: combine separate channels into RGB image
  5. expand: expand indexed color to RGB
  6. bigtiff: force BigTIFF files to be written

-compression: specify the codec to use when saving images

  1. series: specify which image series to convert
    1. map: specify file on disk to which name should be mapped

If any of the following patterns are present in out_file, they will be replaced with the indicated metadata value from the input file.

 Pattern:     Metadata value:
 ---------------------------
 %s           series index
 %n           series name
 %c           channel index
 %w           channel name
 %z           Z index
 %t           T index

If any of these patterns are present, then the images to be saved will be split into multiple files. For example, if the input file contains 5 Z sections and 3 timepoints, and out_file is

converted_Z%z_T%t.tiff

then 15 files will be created, with the names

converted_Z0_T0.tiff
converted_Z0_T1.tiff
converted_Z0_T2.tiff
converted_Z1_T0.tiff
...
converted_Z4_T2.tiff

Each file would have a single image plane.

LifOpenerCUI.ijm

ImageJ macro for converting LIF stack series to multiple tiff stacks, together with setting physical parameters.

// converts LIF file to channel-separated tif stacks. 
// output files will be saved under the folder <LIF file name>_tifStack

//bach command example
/*
/usr/struct/bin/java -cp /g/almf/software/ij/headless.jar:/g/almf/software/ij/ij-1.44h.jar -Djava.awt.headless=true ij.ImageJ -ijpath /g/almf/software/ij -batch /g/almf/software/ij/LifOpenerCUI.ijm /g/almf/miura/lif/laminedapi23012.lif
*/
// TODO: scale should be set as the propertiy of tiff file. 
// reading out of the scale from LIF is somehow not working, unlike it was done in 2009
// metadata of .lif file would be saved as <filename.lif>.meta.txt
//will be saved in the same directory. 
// TODO: program might return error if sequence is terminated abruptly. 

// for setting scale, plugin " ImpProp.class" is required.

	srcfile = getArgument();		//cui
//	srcfile = File.openDialog("Select a LIF File"); //gui	
	requires("1.43d");
	run("Bio-Formats Macro Extensions");

	path = srcfile;
	name = File.getName(path);
	dir = File.getParent(path);	
	DAPIch = 0;//getNumber("DAPI ch=?", 0);
	FISHch = 1;//getNumber("FISH ch=?", 1);
	metaname = name + ".meta.txt";

	q = File.separator; //090912
	metafullpath = dir+q+metaname;
	metastr = File.openAsString(metafullpath);
	workdir = File.getParent(srcfile);  //getDirectory("Choose a work space directory to save resulting files");

	//create "tiffStack" folder under the gene folder (tiff stacks will have series No. and channel so no overlaps)
	pathtifstack = workdir + q + name+ "_tifStack"; print(pathtifstack );
	if (File.isDirectory(pathtifstack)==0) File.makeDirectory(pathtifstack);

	Ext.setId(path);
	Ext.getSeriesCount(seriesCount);
	Ext.getCurrentFile(file);
	Ext.close();	
	print("File:"+ file);
	print("series total number" + seriesCount);

	for (s=0; s<seriesCount; s++) {

		seriesNum = s;
		//Ext.setId(path); 			//out 090925 v4n
		//Ext.setSeries(seriesNum);
		//Ext.getSeriesName(seriesName);
		//Ext.close(); //out 090925 v4n

		if (s>0) refresh =0;

		seriesName = OpenLIFSeriesOneChannel(path, name, seriesNum, DAPIch, 0, metastr);	//modified 090925
		G_GID = getImageID();
		savepath = pathtifstack + q+getTitle();
		print(savepath);
		saveAs("tiff", savepath);
		close();

		OpenLIFSeriesOneChannel(path, name, seriesNum, FISHch, 0, metastr);
		G_RID = getImageID(); 
		savepath = pathtifstack  + q+ getTitle();
		print(savepath);
		saveAs("tiff", savepath);
		close();
	}


//working  maybe memory flashing problem, but not sure. 
/* 090907 
	090908
	- save tif file in a specified directory
	- problem with DAPI appearance in the resulting window.  ---> seperate 2D analysis files in other macro?
*/
function OpenLIFSeriesOneChannel(id, name, seriesNum, ch, datasetOpened, metastr){
	run("Bio-Formats Macro Extensions");

	//if (datasetOpened ==0) Ext.setId(id);
	Ext.setId(id);
	Ext.setSeries(seriesNum);
	Ext.getSeriesName(seriesName); print(seriesName);
	Ext.getSizeZ(sizeZ);
	Ext.getSizeC(sizeC);
	Ext.getSizeT(sizeT);
	Ext.getImageCount(imageCount);
	print("ImageCount:"+imageCount);
	calculatedCount = sizeZ*sizeC*sizeT;
	print("...calculated"+sizeZ*sizeC*sizeT);
	if (imageCount != calculatedCount) {
		print();
		exit();
	}
	sizeT = imageCount/sizeC/sizeZ;
	print("C:"+sizeC+" Z:"+sizeZ+" T:"+sizeT);
	newname = name+"_"+seriesNum+"_ch"+ch+".tif";
	setBatchMode(true);
	for (j=0; j<sizeT; j++){		
		for (i=0; i<sizeZ; i++){
			currentZch0 = i*sizeC;
			currentPlane = j*sizeZ*sizeC + i*sizeC;
			Ext.openImage("t"+j+"_z"+i, currentPlane+ch);
			if ((i==0) && (j==0))
				stackID=getImageID();
			else	{
				run("Copy");
				close;
				selectImage(stackID);
				run("Add Slice");
				run("Paste");
			}
			//print(currentPlane);
		}
	}
	rename(newname);
	xscale = returnXscale(metastr);
	yscale = returnYscale(metastr);
	zscale = returnZscale(metastr);	
	tscale = 1;//returnTscale(metastr);		
	xscalemicron = parseFloat(xscale) * pow(10, 6);
	yscalemicron = parseFloat(yscale) * pow(10, 6);
	zscalemicron = parseFloat(zscale) * pow(10, 6);
	op = "channels=1 slices="+sizeZ+" frames="+sizeT+" unit=micron pixel_width="+xscalemicron +" pixel_height="+yscalemicron +" voxel_depth="+zscalemicron +" frame=[0 sec] origin=0,0";
	//since run("Properties...", op); cannot be used (AWT problem in headless)
	//follwoing is a new plugin for setting image properties. 
	// ImpProp.class
	SsizeC = ""+1;
	SsizeZ = ""+sizeZ;
	SsizeT = ""+sizeT;
	Sxscalemicron = ""+xscalemicron;
	Syscalemicron = ""+yscalemicron;
	Szscalemicron = ""+zscalemicron;			
	call("ImpProps.setCalibration", 
		SsizeC, SsizeZ, SsizeT, "micron", 
		Sxscalemicron, Syscalemicron, Szscalemicron);

	setBatchMode(false);
	//if (datasetOpened ==0) Ext.close();
	Ext.close();		
	return seriesName;	
}

//zscale in micron
function returnZscale(metastr){
	metaA = split(metastr, "\n");
	zscale = 1;
	for (i=0; i<metaA.length; i++){
		if (startsWith(metaA[i], "HardwareSetting|ScannerSettingRecord|dblStepSize")){
			lineA = split(metaA[i], " ");
			//for (j=0; j<lineA.length; j++)print(lineA[j]);
			if (lineA.length>=3) {
				zscale = parseFloat(lineA[2]);
				print(zscale);
			}
		}
	}
	return zscale;		 
}

//Xscale in micron
function returnXscale(metastr){
	metaA = split(metastr, "\n");
	xscale = 1;
	for (i=0; i<metaA.length; i++){
		if (startsWith(metaA[i], "HardwareSetting|ScannerSettingRecord|dblVoxelX")){
			lineA = split(metaA[i], " ");
			//for (j=0; j<lineA.length; j++)print(lineA[j]);
			if (lineA.length>=3) { 
				xscale = parseFloat(lineA[2]);
				print(xscale);
			}
		}
	}
	return xscale;		 
}

function returnYscale(metastr){
	metaA = split(metastr, "\n");
	yscale = 1;
	for (i=0; i<metaA.length; i++){
		if (startsWith(metaA[i], "HardwareSetting|ScannerSettingRecord|dblVoxelY")){
			lineA = split(metaA[i], " ");
			//for (j=0; j<lineA.length; j++)print(lineA[j]);
			if (lineA.length>=3){
				yscale = parseFloat(lineA[2]);
				print(yscale);
			}
		}
	}
	return yscale;			 
}

function returnTscale(){
	metaA = split(metastr, "\n");
	for (i=0; i<metaA.length; i++){
	if (startsWith(metaA[i], "HardwareSetting|ScannerSettingRecord|dblStepSize")){
		lineA = split(metaA[i], " ");
		//for (j=0; j<lineA.length; j++)print(lineA[j]);
		if (lineA.length>=3) print(parseFloat(lineA[2]));
	}
	}		 
}
documents/101029imagej_cui_lifconversion.txt · Last modified: 2020/11/26 09:11 by 127.0.0.1

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki