Batch process directory of numbered images with directory of numbered masks

Hi, I have just joined the forum, I have searched around for a few days and played with templates but I’m new to macro programming and seem to be struggling - hence the post.

I have two folders:

  1. images to be cropped - “raw (i).tiff” where ‘i’ is a sequential number
  2. masks to crop the above images - “raw (i).tiff” again with sequential numbers

Each numbered image has to be cropped using the mask of the same number.

I defined two input directories and build two file lists - however while the macro applies the different masks sequentially, it always applies to the same image.

I had some success forcing windows to be selected using the selectWindow function but not sure if that is helping anymore - macro code below:

outputDir = getDirectory(“Choose output folder”);
inputDir1 = getDirectory(“Choose folder containing raw images”);
inputDir2 = getDirectory(“Choose folder containing masks”);
fileList1 = getFileList(inputDir1);
for (i = 0; i < fileList1.length; i++) {
file1 = fileList1[i];
fileList2 = getFileList(inputDir2);
for (i = 0; i < fileList2.length; i++) {
file2 = fileList2[i];

open(inputDir1+file1);
raw = getImageID();
open(inputDir2+file2);
mask = getImageID();

selectImage(1);
imageCalculator(“Subtract”, raw, mask);
cropped = getImageID();

selectImage(cropped);

saveAs(“Tiff”, outputDir + “/” + "raw " + “(” + i + “)”);

run(“Close All”);

}

Now I’m trying the following:

macro “batch crop to mask”{

setBatchMode(true);

// open directories

// open directory containing raw images and get file list and length

file1 = getDirectory("Choose folder containing cropped raw images");
list1 = getFileList(file1);
n1 = lengthOf(list1);

// open directory containing masks (to be subtracted from raw image)
file2 = getDirectory("Choose folder containing masks");
list2 = getFileList(file2);
n2 = lengthOf(list2);

// choose output directory
file3 = getDirectory("Choose folder to save outputs");

open(file1+list1[1]);
open(file2+list2[1]);

for(i=0;i<n1;i=i+1);
	imageCalculator("Subtract", list1[1], list2[1]);
	saveAs("tiff", file3 + "/" + "raw " + "(" + i + ")");

However all I get is the last image, and it’s all black meaning the imageCalculator function hasn’t worked?

Please I would appreciate some input.

Hi @noisesauce,

You have made a good start on this macro. In this case, the solution is probably easy as in both of your questions, you omit a few brackets. The for loop should be enclosed in {}. Currently, in the last example above, the line for(i=0;i<n1;i=i+1); executes n1 times nothing (just the semicolon, which in this case is ‘the empty statement’).
Teach yourself to use indentation and brackets, this will make your life easier; this then should be in your second macro:

for(i=0;i<n1;i=i+1){
	imageCalculator("Subtract", list1[1], list2[1]);
	saveAs("tiff", file3 + "/" + "raw " + "(" + i + ")");
}

And if you write down your first macro you will notice the missing of the second closing bracket, which I have put in in the indented version. Not that I tested it for proper working, but it is much easier to check now:

Indented macro
outputDir = getDirectory("Choose output folder");
inputDir1 = getDirectory("Choose folder containing raw images");
inputDir2 = getDirectory("Choose folder containing masks");
fileList1 = getFileList(inputDir1);
for (i = 0; i < fileList1.length; i++) {
	file1 = fileList1[i];
	fileList2 = getFileList(inputDir2);
	for (i = 0; i < fileList2.length; i++) {
		file2 = fileList2[i];

		open(inputDir1+file1);
		raw = getImageID();
		open(inputDir2+file2);
		mask = getImageID();

		selectImage(1);
		imageCalculator("Subtract", raw, mask);
		cropped = getImageID();

		selectImage(cropped);

		saveAs("Tiff", outputDir + "/" + "raw " + "(" + i + ")");

		run("Close All");

	}
}

When posting, in the editor use the </> tool around your code, after you have pasted your code. This should prevent the typographic quotes to appear, and conserves the programming quotes. That in turn enables copy-pasting code into ImageJ’s text editor.

Hi eljonco,

Thank you very much for have got some more features working.

I added the Array.sort() function for all file lists across all previous macos leading up to this step which made sure the correct mask was applied to the correct image.

Here’s the (nearly) finished macro:

macro "batch crop to mask"{

	setBatchMode(true);

outputDir = getDirectory("Choose output folder");
inputDir1 = getDirectory("Choose folder containing raw images");
inputDir2 = getDirectory("Choose folder containing masks");
fileList1 = getFileList(inputDir1);
Array.sort(fileList1);
for (i = 0; i < fileList1.length; i++) {
	file1 = fileList1[i];
	fileList2 = getFileList(inputDir2);
	Array.sort(fileList2);
	for (i = 0; i < fileList1.length; i++) {
		file1 = fileList1[i];
		file2 = fileList2[i];
		open(inputDir1+file1);
		raw = getImageID();
		open(inputDir2+file2);
		mask = getImageID();
		
		imageCalculator("Subtract", raw, mask);
		no = (i + 1);
		saveAs("tiff", outputDir + "/" + "cropped " + "(" + no + ")");

		run("Close All");

	}
}

The only problem I have now is after the function has completed, it gives an error:

Index (70) out of 0-69 range in line 16

file2 = fileList2 (i<]> ;

Any thoughts on that appreciated, but thanks for the help!

A very BIG warning on your loop formation.

  1. Nested loops should have DIFFERENT variables.
for(outerloopindex=0;outerloopindex....{
	for(innerloopindex=0;innerloopindex...{
		statements...
	}
}

You have one input folder with raw images and one input folder with mask images. Yet you have two nested for loops (and bad, bad, bad: you use i for both!). Why is that? I would assume the fileList2 = getFileList(inputDir2); could be moved outside the for loop. Same holds for the array.sort of filelist2. Then use only one for loop. That makes your macro a) more efficient and b) probably work.

So you loop over every input file and take its corresponding mask file, do the stuff and save the file. Or is your processing more involved and do I overlook something?

(In ancient history of computing, i was shorthand for ‘integer’ or ‘index’; a quick and dirty loop counter, j and k being next in alphabet to be used in nested loops. But those were the days of FORTRAN and Basic. These days, you have the freedom of using entire words instead of just letters. Use them :wink: )

Just wondering: Do you want to mask image1 with mask1 and image2 with mask? I that case, one for loop does it. Only if you want to mask image1 with mask1 and mask2, you need a second loop…

Otherwise sorry for the spam :wink:

Hey thank you eljonco and haesleinhuepf.

Despite those major issues pointed out, the macro actually works as intended ( :relaxed: )

open image 1 + mask 1
apply mask 1
save cropped 1
open image 2 + mask 2
apply mask 2
save cropped 2

I tried to get the function to work with a single for loop but it never worked, it would always do this:

open image 1 + mask 1
apply mask 1
save cropped 1
open image 1 + mask 2
apply mask 2
save cropped 2
open image 1 + mask 3
apply mask 3
save cropped 3

i.e. apply masks correctly, but not open the next raw image.

That’s very special :wink:
So this macro below does not work?

Simplified single loop version
macro "batch crop to mask"{
	outputDir = getDirectory("Choose output folder");
	inputDir1 = getDirectory("Choose folder containing raw images");
	inputDir2 = getDirectory("Choose folder containing masks");
	fileList1 = getFileList(inputDir1);
	fileList2 = getFileList(inputDir2);
	Array.sort(fileList1);
	Array.sort(fileList2);
	for (i = 0; i < fileList1.length; i++) {
		file1 = fileList1[i];
		file2 = fileList2[i];
		open(inputDir1+file1);
		raw = getImageID();
		open(inputDir2+file2);
		mask = getImageID();
		imageCalculator("Subtract", raw, mask);
		no = (i + 1);
		saveAs("tiff", outputDir + "/" + "cropped " + "(" + no + ")");
		run("Close All");
	}
}
1 Like