Macro problems: paste results table to excel file; run loop that closes image, opens next image, and repeats macro commands

Hello,

I am working on a macro that will perform the Mean Linear Intercept method on several hundred lung tissue images. At the moment, my macro only works on one image that I open, but I need it to continue to open and analyze each image within a folder.

I would also like the macro to paste the data from each image automatically onto an excel spreadsheet. I am working with the Excel Writer plugin (created by Kurt de Vos), but the coding language does not appear when I use the “recording” option.

The macro I have right now is pasted below. At the moment, it does not paste the data from an image onto an excel spreadsheet, nor does it work on all of my images at once. I do not have any coding experience, and I have not written a macro through Image J before.

run("Set Scale...", "distance=2.2934 known=1 pixel=1 unit=micron global");
open("E:\\Oleg Stereology Methods\\horizontal lines grid.tif");
selectImage(1);
pic1=getTitle();
run("Invert");
imageCalculator("Multiply create", pic1,"horizontal lines grid.tif");
selectImage(3);
run("Set Measurements...", "area standard perimeter feret's  redirect=None decimal=2");
run("Analyze Particles...", "size=1-Infinity circularity=0.00-1.00 show=Outlines display exclude size clear record");
selectWindow("Results");
String.copyResults();

Thank you,

Gabby

Hey @gab20

Let’s see if I can help get you started on a few things… will do my best. :slight_smile:

You can check out these other forum threads: this guy, this one too… There is code in those posts that will help you process images within a folder. :slight_smile:

So for saving info that is printed in the results window… you just need to add some code to your macro to save that info, such as:

//saves results for all images in a single file
saveAs("Results", output + "/calculated_results.tsv"); 

So all together - you code will look something like this (***YOU MAY NEED TO MODIFY THIS - since I don’t have your images/data - I could not run/test it properly.***):

// @File(label = "Input directory", style = "directory") input
// @File(label = "Output directory", style = "directory") output
// @String(label = "File suffix", value = ".tif") suffix

processFolder(input); // calls the function below

// function to scan folders/subfolders/files to find files with correct suffix
// you can change the suffix above according to the type of image file you want to process
function processFolder(input) {
	list = getFileList(input);
	for (i = 0; i < list.length; i++) {
		if(File.isDirectory(input + list[i]))
			processFolder("" + input + list[i]); 
		if(endsWith(list[i], suffix))
			yourMacroCode(input, output, list[i]); // calls your macro code below
	}
}

// this function runs your inserted macro code (you can rename the function)
function yourMacroCode(input, output, file) {
        // YOUR MACRO CODE 
        run("Set Scale...", "distance=2.2934 known=1 pixel=1 unit=micron global");
        // open image using Bio-Formats
	run("Bio-Formats", "open=[" + input + "/" + file +"] autoscale color_mode=Default rois_import=[ROI manager] view=Hyperstack stack_order=XYCZT");
        run("Invert");
        imageCalculator("Multiply create", file,"horizontal lines grid.tif");
        selectImage(3); // this call might not work as-is... i'm not sure who you need to select and when...
        run("Set Measurements...", "area standard perimeter feret's  redirect=None decimal=2");
        run("Analyze Particles...", "size=1-Infinity circularity=0.00-1.00 show=Outlines display exclude size clear record");
        saveAs("Results", output + "/" + file + "/calculated_results.tsv"); 
}

Hope this helps. Again THE FINAL CODE HERE MAY NOT WORK… YOU’LL HAVE TO PLAY A BIT WITH IT TO GET THINGS WORKING AS YOU NEED.

If you find using this script too intimidating still… once you have your small macro working, you can always use the ‘easy option’ to process a folder of images. Either should get the job done.

eta :slight_smile:

2 Likes

Thank you so much! I haven’t tried your code yet because I am experiencing some issues. I am trying to work on the macro from my MacBook Pro, which does not have the “E” drive. So the open(“E:\Oleg Stereology Methods\horizontal lines grid.tif”); command is not working. I get the message “File is not in a supported format, a reader plugin is not available, or it was not found”. I believe the issue here is that my laptop does not have the E drive, instead my flash drive simply shows up with its name “GABBY”. Do you know how I can edit that statement so that the file can be reached?

no worries at all ! I’m glad to help. :slight_smile:

// @File(label = "Select a file") imageTitle

just add this line (including comments) to the top of your script. these things are called Script Parameters and will make your life WAY easier! you won’t have to hard-code any paths to image files anymore (you can delete your open(...) calls). you will then automatically be prompted with a GUI to pick an image file (any one that you want on your system). then that image file is saved by the variable imageTitle

eta

1 Like

That got me all the way through line 5 in my macro! But there is an error in line 6 because I also have the “horizontal lines grid.tif” file in it. How should I adjust that?

sorry… i’m not sure.

can you post your new code? that might help me see where the problem is…

//@File(Label="Select a file") imageTitle;
run("Set Scale...", "distance=2.2934 known=1 pixel=1 unit=micron global");
selectImage(1);
pic1=getTitle();
run("Invert");
imageCalculator("Multiply create", pic1, imageTitle);
selectImage(3);
run("Set Measurements...", "area standard perimeter feret's  redirect=None decimal=2");
run("Analyze Particles...", "size=1-Infinity circularity=0.00-1.00 show=Outlines display exclude size clear record");
selectWindow("Results");
String.copyResults();

sorry @gab20

i’m getting tired on this friday afternoon - my brain is slowing down…

what exactly are the steps you are trying to do? just describe them to me. Because i’m not quite getting why you are selecting two images… where are those coming from?

and if you need to select more than one image… you can always add another Script Parameter call:

//@File(Label="Select a file") imageTitle01;
//@File(Label="Select a file") imageTitle02;

eta

So the “horizontal lines” file must open, along with a lung tissue image. These two images are “multiplied” together so that the measurements can occur. I tried using your code and made some adjustments, but it is not working. Here is my code at the moment:

// @File(label = "Input directory", style = "directory") input
// @File(label = "Output directory", style = "directory") output
// @String(label = "File suffix", value = ".tif") suffix
input = getDirectory("/Volumes/GABBY/Mean Linear Intercept/MLI Processed Images/Mouse 1");

output = getDirectory("/Users/gabbywojdyla/Desktop/Test/");


processFolder(input); // calls the function below

// function to scan folders/subfolders/files to find files with correct suffix
// you can change the suffix above according to the type of image file you want 
//toprocess
function processFolder(input) {
	list = getFileList(input);
	for (i = 0; i < list.length; i++) {
		processData(input,list[i]);
	}
}

// this function runs your inserted macro code (you can rename the function)
function processData(input, file) {
        run("Set Scale...", "distance=2.2934 known=1 pixel=1 unit=micron global");
	
	open(input + "/" + file);

	selectImage(1);
	pic1=getTitle();
	run("Invert");
	open("/Volumes/GABBY/Oleg Stereology Methods/horizontal lines grid.tif");
	imageCalculator("Multiply create", pic1, "horizontal lines grid.tif");
	//selectImage(3);
	run("Set Measurements...", "area standard perimeter feret's  redirect=None decimal=2");
	run("Analyze Particles...", "size=1-Infinity circularity=0.00-1.00 show=Outlines display exclude size clear record");
	saveAs(“Results”, output + "/" + file + “/calculated_results.tsv");
	
}

Please let me know if you notice any issues.

Thank you,
Gabby

So… again - as I said in my previous comment… you are best to add an additional @Parameter at the top of your code to select your horizontal lines image… so something like this:

(AND - you do not need those getDirectory() calls anymore… you can use the Script Parameters instead. I edited the code accordingly.)

// @File(label = "Input directory", style = "directory") input
// @File(Label="Select a 'horizontal lines' image") horizontal
// @File(label = "Output directory", style = "directory") output
// @String(label = "File suffix", value = ".tif") suffix

processFolder(input); // calls the function below

// function to scan folders/subfolders/files to find files with correct suffix
// you can change the suffix above according to the type of image file you want 
//toprocess
function processFolder(input) {
	list = getFileList(input);
	for (i = 0; i < list.length; i++) {
		processData(input,list[i]);
	}
}

// this function runs your inserted macro code (you can rename the function)
function processData(input, file) {
        run("Set Scale...", "distance=2.2934 known=1 pixel=1 unit=micron global");
	
	open(input + "/" + file);

	selectImage(1);
	pic1=getTitle();
	run("Invert");
	imageCalculator("Multiply create", pic1, horizontal);
	//selectImage(3);
	run("Set Measurements...", "area standard perimeter feret's  redirect=None decimal=2");
	run("Analyze Particles...", "size=1-Infinity circularity=0.00-1.00 show=Outlines display exclude size clear record");
	saveAs("Results", output + "/" + file + "/calculated_results.tsv");
}

Again - since I do not have your data, etc. I cannot run this code.

As before, this code might not be working properly.

Just play with it a bit - edit things and see when/if you get what you need. I cannot do that for you - I at least gave you the building-blocks…

And don’t forget - you can always use the ‘easy option’ to process a folder of images just using your simple macro that you have working.

I really hope it helps.

eta :slight_smile:

1 Like

Hi eta,

Thank you so much for all of your help! I got my macro to work, I only have one issue now. Instead of saving all of the data from every photo into excel, it seems to only save the data from the last photo in the folder. Below is my current code.

// @File(label = "Input directory", style = "directory") input
// @File(label = "Output directory", style = "directory") output
// @String(label = "File suffix", value = ".tif") suffix
input = getDirectory("/Volumes/GABBY/Mean Linear Intercept/MLI Processed Images/Practice Images");

output = getDirectory("/Users/gabbywojdyla/Desktop/Test/");


processFolder(input); // calls the function below

// function to scan folders/subfolders/files to find files with correct suffix
// you can change the suffix above according to the type of image file you want 
//toprocess
function processFolder(input) {
	list = getFileList(input);
	for (i = 0; i < list.length; i++) {
		processData(input,list[i]);
	}
}

// this function runs your inserted macro code (you can rename the function)
function processData(input, file) {
         
	open(input + "/" + file);
	run("Set Scale...", "distance=2.2934 known=1 pixel=1 unit=micron global");	selectImage(1);
	pic1=getTitle();
	run("Invert");
	open("/Volumes/GABBY/Oleg Stereology Methods/horizontal lines grid.tif");
	imageCalculator("Multiply create", pic1, "horizontal lines grid.tif");
	run("Set Measurements...", "area standard perimeter feret's  redirect=None decimal=2");
	run("Analyze Particles...", "size=1-Infinity circularity=0.00-1.00 show=Outlines display exclude size clear record");
	//saves results for all images in a single file
saveAs("Results", output + "/calculated_results.csv");
run("Close All");
	
}
1 Like

This is because you overwrite the same file calculated_results.csv in each call of your processData function:

To avoid that, make the name of the csv file dependent on your input file name, e.g.

outputfile = substr(file, 0, lengthOf(file) - 4) + "_Results.csv";
saveAs("Results", output + File.separator + outputfile);

Alternatively, run the Analyze Particles without clearing the results, and save a single file with all the results when the processing is done.

1 Like

Thanks @imagejan … and CONGRATS @gab20 !!! We cracked it in the end - eh!!! :slight_smile:

And next time… you will feel better about scripting your solutions - super !!!

eta :slight_smile:

1 Like

Well, @etadobson, you had it in your macro from the beginning :slight_smile:

@gab20 this will create a new folder named according to the input file, containing the results file.

1 Like

Thank you @imagejan and @etadobson ! I tried this: saveAs(“Results”, output + “/” + file + “/calculated_results.csv”);

This did not work, however.

I’m not quite sure I understand your code @imagejan, do I just paste it right into mine, or do I have to adjust it slightly?