Generalising splitting image + image calculator macro

Hi everyone,

I’m having a hard time trying to generalise the following macro. What we want to do is to take two open images and split them both up into 9 sections each. Then, using the Image Calculator, we subtract corresponding sections from each other (e.g. we take the top-left corner section of Image 1 and subtract that with the top-left corner section of Image 2). After that, we want to measure the standard deviation of each of the resulting difference images and save the results as a csv file. This is what we have so far:

open("C:/Users/TheAntri/Desktop/Master's Project/Data/February/11 Feb/ISO 200/15000exoff.iso.200.V2,92image000.png");
open("C:/Users/TheAntri/Desktop/Master's Project/Data/February/11 Feb/ISO 200/15000exoff.iso.200.V2,92image001.png");
run("Install...", "install=[C:/Users/TheAntri/Desktop/Master's Project/ImageJs/ImageJ/macros/splitimage.txt]");

// Here, I'm splitting them up into 9 sections.

selectWindow("15000exoff.iso.200.V2,92image000.png");
//run the splitimage macro on Pic 1
selectWindow("15000exoff.iso.200.V2,92image001.png");
//run the splitimage macro on Pic 2

//I am left with 9 sections from each Pic 1 and Pic 2. They are labelled by the (x,y) coordinates. For example, the top-left corner is labelled as (0,0). 
//I select the corresponding regions and subtract them from each other.
//For example, I select Region (0,0) from Pic 1 and, using the ImageCalculator I subtract it from Region (0,0) from Pic 2. 
imageCalculator("Subtract create 32-bit", "15000exoff.iso.200.V2,92image000.png[0,0]","15000exoff.iso.200.V2,92image001.png[0,0]");
//I measure the standard variance of the difference image 
selectWindow("Result of 15000exoff.iso.200.V2,92image000.png[0,0]");
run("Measure");

//I repeat this for all other sections
imageCalculator("Subtract create 32-bit", "15000exoff.iso.200.V2,92image000.png[1,0]","15000exoff.iso.200.V2,92image001.png[1,0]");
selectWindow("Result of 15000exoff.iso.200.V2,92image000.png[1,0]");
run("Measure");
imageCalculator("Subtract create 32-bit", "15000exoff.iso.200.V2,92image000.png[2,0]","15000exoff.iso.200.V2,92image001.png[2,0]");
selectWindow("Result of 15000exoff.iso.200.V2,92image000.png[2,0]");
run("Measure");
imageCalculator("Subtract create 32-bit", "15000exoff.iso.200.V2,92image000.png[0,1]","15000exoff.iso.200.V2,92image001.png[0,1]");
selectWindow("Result of 15000exoff.iso.200.V2,92image000.png[0,1]");
run("Measure");
imageCalculator("Subtract create 32-bit", "15000exoff.iso.200.V2,92image000.png[1,1]","15000exoff.iso.200.V2,92image001.png[1,1]");
selectWindow("Result of 15000exoff.iso.200.V2,92image000.png[1,1]");
run("Measure");
imageCalculator("Subtract create 32-bit", "15000exoff.iso.200.V2,92image000.png[2,1]","15000exoff.iso.200.V2,92image001.png[2,1]");
selectWindow("Result of 15000exoff.iso.200.V2,92image000.png[2,1]");
run("Measure");
imageCalculator("Subtract create 32-bit", "15000exoff.iso.200.V2,92image000.png[0,2]","15000exoff.iso.200.V2,92image001.png[0,2]");
selectWindow("Result of 15000exoff.iso.200.V2,92image000.png[0,2]");
run("Measure");
imageCalculator("Subtract create 32-bit", "15000exoff.iso.200.V2,92image000.png[1,2]","15000exoff.iso.200.V2,92image001.png[1,2]");
selectWindow("Result of 15000exoff.iso.200.V2,92image000.png[1,2]");
run("Measure");
imageCalculator("Subtract create 32-bit", "15000exoff.iso.200.V2,92image000.png[2,2]","15000exoff.iso.200.V2,92image001.png[2,2]");
selectWindow("Result of 15000exoff.iso.200.V2,92image000.png[2,2]");
run("Measure");

//Save the results as a csv file
saveAs("Results", "C:/Users/TheAntri/Desktop/Master's Project/Data/11 Feb/Results.csv");

We split the images using the following macro:

n = getNumber("How many divisions (e.g., 2 means quarters)?", 3);
id = getImageID();
title = getTitle();
getLocationAndSize(locX, locY, sizeW, sizeH);
width = getWidth();
height = getHeight();
tileWidth = width / n;
tileHeight = height / n;
for (y = 0; y < n; y++) {
offsetY = y * height / n;
 for (x = 0; x < n; x++) {
offsetX = x * width / n;
selectImage(id);
 call("ij.gui.ImageWindow.setNextLocation", locX + offsetX, locY + offsetY);
tileTitle = title +  "[" + x + "," + y + "]";
 run("Duplicate...", "title=" + tileTitle);
makeRectangle(offsetX, offsetY, tileWidth, tileHeight);
 run("Crop");
}
}
selectImage(id);
close();

When we record the macro, we encounter two problems:

  1. The macro is specific to the file name. Ideally, we want our macro to be general such that no matter what two images we have open, the functions above will still run.
  2. The macro recorder doesn’t record us running the splitimage macro on both our images. In what we have so far, I’ve commented where we have run the splitimage macro.

We’d appreciate any help whatsoever! We’re both new to Fiji/ImageJ so we’re just tackling hurdles one after the other!

Thanks,
Jacklin & Antri

I’ve attached the pictures that we used here:
Example images.zip (1.7 MB)

And here are some hopefully helpful screenshots of our process…
This is us running the macro that splits up our images. We want each image to be split up into 9 equal sections, so we input ‘3’ as the number of divisions.

This is the result we get after we split up our images.

@Jacklin_and_Antri

I’d point you to this previous post to start:

That code can easily be modified/adapted to do what you need… but for sure - to make things more generalizable - use Script Parameters and variables! They are your new best friends!

Too - perhaps you can make your split macro into a function instead? Then you can easily just pass the necessary input parameters from within the script and run it.

Thanks for the help! This is what we have so far. But we weirdly get an index error when we try to run it and we have no idea why.

input1 = "/Users/jacklinkwan/Desktop/Image0";
input2 = "/Users/jacklinkwan/Desktop/Image1";

list1 = getFileList(input1);
list2 = getFileList(input2);

for (i = 0; i < list1.length; i++) //going to assume same number of images in both folders

	file1 = input1+list1[i];
	file2 = input2+list2[i];
	
	open(file1);
	imageTitle1 = getTitle();
	open(file2);
	imageTitle2 = getTitle();
	
	run("Install...", "install=/Users/jacklinkwan/Desktop/splitimage.txt");

	// Here, I'm splitting them up into 9 sections.

	selectWindow(imageTitle1);
	run("splitimage")
	selectWindow(imageTitle2);
	run("splitimage")

	//I am left with 9 sections from each Pic 1 and Pic 2. They are labelled by the (x,y) coordinates. For example, the top-left corner is labelled as (0,0). 
	//I select the corresponding regions and subtract them from each other.
	//For example, I select Region (0,0) from Pic 1 and, using the ImageCalculator I subtract it from Region (0,0) from Pic 2. 
	imageCalculator("Subtract create 32-bit", imageTitle1+"[0,0]",imageTitle2+"[0,0]");
	//I measure the standard variance of the difference image 
	selectWindow("Result of "+imageTitle1+"[0,0]");
	run("Measure");

	//I repeat this for all other sections
	imageCalculator("Subtract create 32-bit", imageTitle1+"[1,0]",imageTitle2+"[1,0]");
	selectWindow("Result of "+imageTitle1+"[1,0]");
	run("Measure");
	imageCalculator("Subtract create 32-bit", imageTitle1+"[2,0]",imageTitle2+"[2,0]");
	selectWindow("Result of "+imageTitle1+"[2,0]");
	run("Measure");
	imageCalculator("Subtract create 32-bit", imageTitle1+"[0,1]",imageTitle2+"[0,1]");
	selectWindow("Result of "+imageTitle1+"[0,1]");
	run("Measure");
	imageCalculator("Subtract create 32-bit", imageTitle1+"[1,1]",imageTitle2+"[1,1]");
	selectWindow("Result of "+imageTitle1+"[1,1]");
	run("Measure");
	imageCalculator("Subtract create 32-bit", imageTitle1+"[2,1]",imageTitle2+"[2,1]");
	selectWindow("Result of "+imageTitle1+"[2,1]");
	run("Measure");
	imageCalculator("Subtract create 32-bit", imageTitle1+"[0,2]",imageTitle2+"[0,2]");
	selectWindow("Result of "+imageTitle1+"[0,2]");
	run("Measure");
	imageCalculator("Subtract create 32-bit", imageTitle1+"[1,2]",imageTitle2+"[1,2]");
	selectWindow("Result of "+imageTitle1+"[1,2]");
	run("Measure");
	imageCalculator("Subtract create 32-bit", imageTitle1+"[2,2]",imageTitle2+"[2,2]");
	selectWindow("Result of "+imageTitle1+"[2,2]");
	run("Measure");

	//Save the results as a csv file
	saveAs("Results", "/Users/jacklinkwan/Desktop/Results"+i".csv");
	
	close();
	close();

86355174_2589103491202678_6940996424003747840_n

Hi @Jacklin_and_Antri

I think that your goal can be accomplished in a simpler way.

What I propose is that:

  1. you can perform the image subtraction before dividing into sections
  2. there’s no need to actually divide the image, just to measure SD on those areas (ROIs). For bonus points, I’d perform 1 & 2 in batchmode, so no image flicker is visible.
  3. finally, I’ll add @etadobson’s suggestion to the mix: make the “divide” script into a function, but with a change: given that we’re not doing an actual image division, I’d create a function that wraps 1, 2 & 3. This will allow for simpler debugging, and for a cleaner loop.

In a second iteration, instead of making a csv I’d also suggest adding a single line to a custom table, which can be left to the user to save at the end. Additionally, I’d suggest the incorporation of script parameters, to simplify the task of selecting folders and number of divisions, and to further extend the scripting possibilities, but I’ll leave that out for the moment.

With that in mind, here’s my remixed script:

n = getNumber("How many divisions (e.g., 2 means quarters)?", 3);

input1 = "/Users/jacklinkwan/Desktop/Image0/"; //backlash added at the end!
input2 = "/Users/jacklinkwan/Desktop/Image1/";
output = "/Users/jacklinkwan/Desktop/";

list1 = getFileList(input1);
list2 = getFileList(input2);

setBatchMode(true);
for (i = 0; i < list1.length; i++) { //going to assume same number of images in both folders

	file1 = input1+list1[i];
	file2 = input2+list2[i];
	
	open(file1);
	imageTitle1 = getTitle();
	open(file2);
	imageTitle2 = getTitle();

	sectionsDiffStdDev(imageTitle1, imageTitle2, n); // call the function.

	//Save the results as a csv file
	saveAs("Results", output+"Results"+i".csv");
	
	close();
	close();
	}
setBatchMode(false);

function sectionsDiffStdDev(image1, image2, n_divs){
	run("Set Measurements...", "standard display"); // this ensures that the SD is actually measured, also the image & roi info is present
	imageCalculator("Subtract create 32-bit", image1, image2);
	rename("Result "+image1+" - "+image2); // use both names in the diff image
	width = getWidth();
	height = getHeight();
	tileWidth = width / n;
	tileHeight = height / n;
	for (y = 0; y < n; y++) {
		offsetY = y * height / n;
		for (x = 0; x < n; x++) {
			offsetX = x * width / n;
			makeRectangle(offsetX, offsetY, tileWidth, tileHeight);
			run("Properties... ", "name=[[" + x + "," + y + "]]"); // rename the roi, double brackets so that the inner pair makes it through
			run("Measure");
			}
		}
	close();
	}

Let me know if this helps,

Cheers,
Nico

2 Likes

Hi Nico,

We just tried running it this morning and it works like a dream! Thank you for your kind help :smiley:

Cheers,
Jacklin and Antri

2 Likes