Using macro to open .lif/.tif files

Hi,

I am experienced java developer, but I am new to fiji. Trying to help out scientists friend to automate his image processing.

I am trying to open .lif/.tif files, which contains multiple images in “stack”. Once files are opened, I can change slices and do most of actions I’d want.
Problem is opening itself. When I open file using “open” command (or manually), “Bio-Formats Import Options” window shows up. I don’t know how to confirm that window (I just need to press “OK” or hit “enter”). Then another window “Bio-Formats Series Options” appears, where I need to press “Select All” and “OK”.

I couldn’t find a way. I biggest problem is, that when those windows are opened, script is blocked until they are closed so lines after “open” are not executed until those windows are resolved and closed. How would you proceed?

I probably could create plugin, that will run something on background so that it doesn’t get blocked, wait for image with that title, find button with text in there and click on it, but that sounds quite complicated and a bit of overkill.
Is it normal, that some windows block macro execution and make it almost impossible for macro to control them?

Any general comments, that explain this behaviour is welcomed as I am very new to fiji ecosystem. I don’t mind making some good generic tool for usecases like this with some guidance.

K

I’ve found, that there’s Windowless_Importer and macro extensions, that allow opening file through that windowless importer and do what I wanted to do quite simply:

Dear @fijikh,

you can use the following macro and adapt it regarding your import options for your series. Tthis is easiest done by once recording one image import and then changing it accordingly in the macro.
At the labelled part you can put your macro code for processing. With some small changes this should actually work for all types of Bio-Format readable files in a specified folder (and all subfolders).

run("Bio-Formats Macro Extensions");

userChosenDirectory = getDirectory("Choose a Directory");

processBioFormatFiles(userChosenDirectory);

function processBioFormatFiles(currentDirectory) {

	fileList = getFileList(currentDirectory);

	for (file = 0; file < fileList.length; file++) {
		Ext.isThisType(currentDirectory + fileList[file], supportedFileFormat);
		if (supportedFileFormat=="true") {
			Ext.setId(currentDirectory + fileList[file]);
			Ext.getSeriesCount(seriesCount);
			for (series = 1; series <= seriesCount; series++) {
				//record the Bio-Formats importer with the setup you need if different from below and change accordingly
				run("Bio-Formats Importer", "open=[" + currentDirectory + fileList[file] + "] autoscale color_mode=Composite rois_import=[ROI manager] view=Hyperstack stack_order=XYCZT series_"+series);
				//add your macro code here
			}
		} else if (endsWith(fileList[file], "/")) {
			processBioFormatFiles(currentDirectory + fileList[file]);
		}
	}
}
1 Like

Thanks, that can be useful if I need to change parameters of import when needed!
For now I am happy with headless import, which remembers last settings, that was used in normal import dialog.

Thank you so much!
That was super usefull.

Best,
äly

Here an update on the macro posted above, in case someone wants to limit it to specific non-BioFormat files in the first row. Just add the file type extension you need and/or delete the other ones.

Additionally, it uses the parameter scripting way to define the input directory.

Furthermore, you can specify your own macro code in a separate function to keep it a little bit more tidy.

//@ File (label = "Input directory", style = "directory") chosenDir

inputDir = chosenDir + File.separator;

var acceptedNonBioFormatsFiles = "jpg, jpeg, tif, png, bmp, gif, avi, ijm, txt";

run("Bio-Formats Macro Extensions");

processBioFormatFiles(inputDir);

function processBioFormatFiles(currentDirectory) {

	fileList = getFileList(currentDirectory);

	for (file = 0; file < fileList.length; file++) {
		
		Ext.isThisType(currentDirectory + fileList[file], supportedFileFormat);
		
		if (supportedFileFormat=="true" && !matches(acceptedNonBioFormatsFiles, ".*" + substring(fileList[file], lengthOf(fileList[file])-3) + ".*")) {
			Ext.setId(currentDirectory + fileList[file]);
			Ext.getSeriesCount(seriesCount);
			
			for (series = 1; series <= seriesCount; series++) {
				//record the Bio-Formats importer with the setup you need if different from below and change accordingly
				run("Bio-Formats Importer", "open=[" + currentDirectory + fileList[file] + "] autoscale color_mode=Composite rois_import=[ROI manager] view=Hyperstack stack_order=XYCZT series_"+series);
				runMyMacro();
			}
			
		} else if (matches(acceptedNonBioFormatsFiles, ".*" + substring(fileList[file], lengthOf(fileList[file])-3) + ".*")) {
			
			open(currentDirectory + fileList[file]);
			runMyMacro();
			
		} else if (endsWith(fileList[file], "/")) {
			
			processBioFormatFiles(currentDirectory + fileList[file]);
			
		}
	}
}


function runMyMacro() {
	//here comes your macro code
}

Hi biovoxxel,

thanks a lot for that AWESOME script.

It works really good.
Now I was wondering to modify it a little, but I am struggling with it.
I would like to use those dialogues in the beginning of the script:

#@ File (label = “Input directory”, style = “directory”) input
#@ File (label = “Output directory”, style = “directory”) output
#@ String (label = “File suffix”, value = “.lif”) suffix

And afterwards run your script. Now I don’t get it, what to change to make it work.
I would be very glad, if you could help me with that.

greets,
phagocyte

Hi @phagocyte,

the following adaptation of the original macro should do the job if you include the outpout directory specification in your save commands in the macro. I haven’t finally tested this, but I guess it should run.

EDIT: UPDATED

//@File (label = "Input directory", style = "directory") chosenInputDir
//@File (label = "Output directory", style = "directory") chosenOutputDir
//@String (label = "File suffix", value = ".lif") fileExtension


inputDir = chosenInputDir + File.separator;
outputDir = chosenOutputDir + File.separator;

run("Bio-Formats Macro Extensions");

processBioFormatFiles(inputDir);

exit("Done");

function processBioFormatFiles(currentDirectory) {

	fileList = getFileList(currentDirectory);

	for (file = 0; file < fileList.length; file++) {

		if (endsWith(fileList[file], fileExtension)) {
			Ext.setId(currentDirectory + fileList[file]);
			Ext.getSeriesCount(seriesCount);
			
			for (series = 1; series <= seriesCount; series++) {
				//record the Bio-Formats importer with the setup you need if different from below and change accordingly
				run("Bio-Formats Importer", "open=[" + currentDirectory + fileList[file] + "] autoscale color_mode=Composite rois_import=[ROI manager] view=Hyperstack stack_order=XYCZT series_"+series);
				//add your macro code here
				//specify the outputDir in your save commands. First record them and exchange the path for outputDir + .....
			}
			
		} else if (endsWith(fileList[file], "/")) {
			processBioFormatFiles(currentDirectory + fileList[file]);
		}
	}
}

let me know if it runs or if there are any problems to edit the macro here.

Hey biovoxxel,

thanks a lot for your quick reply!
Unfortunately there is an error message popping up:
image

:frowning:
No Debug options, just in the log an annoying stuff like that:

at java.io.RandomAccessFile.open0(Native Method)
at java.io.RandomAccessFile.open(RandomAccessFile.java:316)
at java.io.RandomAccessFile.<init>(RandomAccessFile.java:243)
at loci.common.NIOFileHandle.<init>(NIOFileHandle.java:130)
at loci.common.NIOFileHandle.<init>(NIOFileHandle.java:151)
at loci.common.NIOFileHandle.<init>(NIOFileHandle.java:165)
at loci.common.Location.getHandle(Location.java:522)
at loci.common.Location.getHandle(Location.java:462)
at loci.common.Location.getHandle(Location.java:443)
at loci.common.Location.getHandle(Location.java:426)
at loci.common.Location.checkValidId(Location.java:551)
at loci.formats.ImageReader.getReader(ImageReader.java:178)
at loci.formats.ImageReader.setId(ImageReader.java:840)
at loci.formats.ReaderWrapper.setId(ReaderWrapper.java:650)
at loci.formats.ChannelSeparator.setId(ChannelSeparator.java:293)
at loci.formats.ReaderWrapper.setId(ReaderWrapper.java:650)
at loci.plugins.macro.LociFunctions.setId(LociFunctions.java:427)
... 43 more

Is that the complete error message? It seems that there is something missing on the top…

And… does that appear already in the beginning or after the file chooser dialog poped up and you pressed Ok

It pops up after selecting the input and output directory, clicking ok and then this is the full error message:

java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at loci.plugins.macro.MacroFunctions.handleExtension(MacroFunctions.java:82)
at ij.macro.ExtensionDescriptor.dispatch(ExtensionDescriptor.java:288)
at ij.macro.Functions.doExt(Functions.java:4787)
at ij.macro.Functions.getStringFunction(Functions.java:276)
at ij.macro.Interpreter.getStringTerm(Interpreter.java:1407)
at ij.macro.Interpreter.getString(Interpreter.java:1385)
at ij.macro.Interpreter.doStatement(Interpreter.java:329)
at ij.macro.Interpreter.doBlock(Interpreter.java:671)
at ij.macro.Interpreter.doStatement(Interpreter.java:320)
at ij.macro.Interpreter.doIf(Interpreter.java:1049)
at ij.macro.Interpreter.doStatement(Interpreter.java:296)
at ij.macro.Interpreter.doBlock(Interpreter.java:671)
at ij.macro.Interpreter.doStatement(Interpreter.java:320)
at ij.macro.Interpreter.doFor(Interpreter.java:593)
at ij.macro.Interpreter.doStatement(Interpreter.java:302)
at ij.macro.Interpreter.doBlock(Interpreter.java:671)
at ij.macro.Interpreter.runUserFunction(Interpreter.java:370)
at ij.macro.Interpreter.doStatement(Interpreter.java:281)
at ij.macro.Interpreter.doStatements(Interpreter.java:261)
at ij.macro.Interpreter.run(Interpreter.java:157)
at ij.macro.Interpreter.run(Interpreter.java:91)
at ij.macro.Interpreter.run(Interpreter.java:102)
at ij.plugin.Macro_Runner.runMacro(Macro_Runner.java:161)
at ij.IJ.runMacro(IJ.java:148)
at ij.IJ.runMacro(IJ.java:137)
at net.imagej.legacy.IJ1Helper$3.call(IJ1Helper.java:1108)
at net.imagej.legacy.IJ1Helper$3.call(IJ1Helper.java:1104)
at net.imagej.legacy.IJ1Helper.runMacroFriendly(IJ1Helper.java:1055)
at net.imagej.legacy.IJ1Helper.runMacro(IJ1Helper.java:1104)
at net.imagej.legacy.plugin.IJ1MacroEngine.eval(IJ1MacroEngine.java:147)
at org.scijava.script.ScriptModule.run(ScriptModule.java:160)
at org.scijava.module.ModuleRunner.run(ModuleRunner.java:168)
at org.scijava.module.ModuleRunner.call(ModuleRunner.java:127)
at org.scijava.module.ModuleRunner.call(ModuleRunner.java:66)
at org.scijava.thread.DefaultThreadService.lambda$wrap$2(DefaultThreadService.java:228)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.io.FileNotFoundException: C:\Users[file location removed due to privacy reasons] (The system cannot find the file specified)
at java.io.RandomAccessFile.open0(Native Method)
at java.io.RandomAccessFile.open(RandomAccessFile.java:316)
at java.io.RandomAccessFile.(RandomAccessFile.java:243)
at loci.common.NIOFileHandle.(NIOFileHandle.java:130)
at loci.common.NIOFileHandle.(NIOFileHandle.java:151)
at loci.common.NIOFileHandle.(NIOFileHandle.java:165)
at loci.common.Location.getHandle(Location.java:522)
at loci.common.Location.getHandle(Location.java:462)
at loci.common.Location.getHandle(Location.java:443)
at loci.common.Location.getHandle(Location.java:426)
at loci.common.Location.checkValidId(Location.java:551)
at loci.formats.ImageReader.getReader(ImageReader.java:178)
at loci.formats.ImageReader.setId(ImageReader.java:840)
at loci.formats.ReaderWrapper.setId(ReaderWrapper.java:650)
at loci.formats.ChannelSeparator.setId(ChannelSeparator.java:293)
at loci.formats.ReaderWrapper.setId(ReaderWrapper.java:650)
at loci.plugins.macro.LociFunctions.setId(LociFunctions.java:427)
… 43 more

Although I was using the same directory with your previous script and an other batch script, working fine. Only the combination somehow of both does not work well…

Merci!

I don’t have a lif file at hand to test it but if I change it for another file extension I get the same error. Currently, I am completely clueless, why that happens… :thinking:

@phagocyte,

I found the solution…

Problem is that the //@ File (label = "Input directory", style = "directory") inputDir specification returns the folders without the trailing file/folder separator “/”.

I updated the macro above, so that the wrong macro is directly eliminated and others are not running into the same trap.

1 Like

Yes!
Thanks a lot, it works now.
Beautiful!

Thank you so much!
I would mention you in the script when using it, if you don’t mind.

I appreciate that, thanks!