Percentage results of an image stack

Result%20Picture

Hello,

I try to analyze the percentage of the leaf which is covered in disease symptoms, which works pretty well with Trainable weka segmentation. (I attached pictures, sorry for the bad quality they are just for testing). My Macro code is:

getRawStatistics(nPixels, mean, min, max); 

setBatchMode( true );
run("Set Measurements...", "area_fraction redirect=None decimal=3");

for( i=min, n=0; i <= max; i++, n++ )
{	
	selectWindow("Classified image");
	run("Duplicate...", "title=[to-be-thresholded]");
	selectWindow("to-be-thresholded");
	setThreshold( i, i );
	run("Convert to Mask");
	run("Measure");
	setResult("Label", n, i ); 
	close();
}

Improvements are welcome.
However, this code is only able to calculate the percentage of the one result image where I clicked on recording, but actually they are in a stack (images to stack). Is there a way to calculate the percentage of disease symptoms:healthy leaf:background of the whole stack at once (maybe transfering them to one excel file)?
If this question is trivial I am sorry, my english is not the best so the instructions are not easy to understand.
Thank you for your suggestions!!

PS: If someone has an idea how to remove the background from the calculation I’m eager to learn…

With the code:

getRawStatistics(nPixels, mean, min, max); 
run("Set Measurements...", "area_fraction redirect=None decimal=3");
for (s = 1;  s <= nSlices(); s++){
        setSlice(s);
        run("Measure");
} 	

i am able to calculate the percentage of the background and the leaf together for the whole stack, which is not really helpful.
Has somebody a Idea how to include all my (three) labels and show them seperatly?

Hello @san and welcome to the ImageJ forum!

I’m sorry for the late replay. Di you have a look at this post already?

No Problem!
Yes I actually did, If you Look closely it’s exactly your code in This Post i used. It works perfectly finde, just not on an image stack

@san

Do you merge your images to a stack then? Why not just process each image as you go? You can save your results to a single Results Table.

You can use this script example (which comes with Fiji…):

/*
 * Macro template to process multiple images in a folder
 */

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

// See also Process_Folder.py for a version of this code
// in the Python scripting language.

processFolder(input);

// function to scan folders/subfolders/files to find files with correct suffix
function processFolder(input) {
	list = getFileList(input);
	list = Array.sort(list);
	for (i = 0; i < list.length; i++) {
		if(File.isDirectory(input + File.separator + list[i]))
			processFolder(input + File.separator + list[i]);
		if(endsWith(list[i], suffix))
			processFile(input, output, list[i]);
	}
}

function processFile(input, output, file) {
	// Do the processing here by adding your own code.
	// Leave the print statements until things work, then remove them.
	print("Processing: " + input + File.separator + file);
	print("Saving to: " + output);
}

To access it… just open the Script Editor and go to Templates > ImageJ 1.x > Batch > Process Folder (IJ1 Macro). There is also a great BeanShell script that will batch process for Trainable Weka - applying a classifier to all images in a folder.

Yes I merged them into a stack. Thought it might save time :slight_smile: But I will definitly try your method, thank you so much!! If the beanshell script works for me I think it could be perfect. I will try it out when I have time.

1 Like

@san

If you have specific questions after moving forward - don’t hesitate to ask! We are here to help. :slight_smile:

so the BeanShell script actually works really well and is exactly what I needed, so thank you.
Now I just have to figure out where to add the code for calculating the different percentages of the labels and to save them. Right now it justs gives me the result images. Will have to look at this tomorrow.

@san

Well - you can run the Beanshell script to generate images to be used as input for another script (the other code example I included above)… that one can focus on your calculations (that code gets inserted into the processFile() function - read those comments). Give it a try and if you need more help - let us know.

thank you again, you are really helpful! So I tried to use the code you gave me, however it always complains about “no images in line …”. Now I just use the Multi Image Processor (for some reason I never noticed that options) and its works perfectly.
So thanks again for your suggestion about the Beanshell script!

My second code after the Beanshell script for the Multi Image Processor is now:

getRawStatistics(nPixels, mean, min, max); 
                    imageTitle=getTitle();

setBatchMode( true );
run("Set Measurements...", "area_fraction redirect=None decimal=3");
for( i=min, n=0; i <= max; i++, n++ )
{	
selectWindow(imageTitle);
	run("Duplicate...", "title=[to-be-thresholded]");
	selectWindow("to-be-thresholded");
                     setThreshold( i, i );
	run("Convert to Mask");
	run("Measure");
	setResult("Label", n, imageTitle);
	close();
}

I just have one little question. The results look like this:

Results.csv (159 Bytes)

So I managed to give the first picture its file name, which I cant do for the other ones.
So three “%Area” always belong together, Its not important that the three labels (fungi, leaf, backgorund) are seperated but the file names would be great.

Sorry for the many different questions

@san

So the issue is that labels are missing for the images in the table? Just make sure to also select “Display labels” in Set Measurements as well… so the code call should be run("Set Measurements...", "area_fraction display redirect=None decimal=3");.

Hope this does it!

Its getting really akward but well…
I already tried your code beforhand because I read it somewhere else, but than it looks like this:
(ignore the bold letters)

8.tif 0.480
8.tif 14.464
8.tif 85.056
to-be-thresholded 0.471
to-be-thresholded 15.363
to-be-thresholded 84.166
to-be-thresholded 0.027
to-be-thresholded 17.624
to-be-thresholded 82.350
to-be-thresholded 0.792
to-be-thresholded 10.549
to-be-thresholded 88.659

so 8.tif is the file name, which I need for every picture, but somehow it only names this one.
so I want it to look like this, with every x.tif being the actually file name of the picture.

8.tif 0.480
8.tif 14.464
8.tif 85.056
5.tif 0.471
5.tif 15.363
5.tif 84.166
4.tif 0.027
4.tif 17.624
4.tif 82.350
3.tif 0.792
3.tif 10.549
3.tif 88.659

I guess it has something to do with this part:

run("Duplicate...", "title=[to-be-thresholded]");
selectWindow("to-be-thresholded");

but I dont know how to get rid of it without crashing the whole code.

Many thanks for your help until now!! I also will continue to look for a solution myself.

@san
It would be easier if you could show me your code… if you can share it? Or at least share a minimal working example to highlight this issue you are having?

Well… You are renaming the image when you Duplicate… There is no need for this really. You can use the window’s unique id’s to select them… so using code calls like:

imageID = getImageID();
selectImage(imageID);

Or you can ask for the image title… and do something like:

imageTitle = getTitle();
run("Duplicate...", "title=[" + imageTitle + "_to-be-thresholded]");
selectWindow(imageTitle + "_to-be-thresholded");

Then at least you have the image title in the name still… to identify it later on.

the working process is as following:

  1. I have (for example) this four pictures (after adjusting the size etc.)

  2. I apply the classifier to all of them using the Beanshell script:

// @File(label="Input directory", description="Select the directory with input images", style="directory") inputDir
// @File(label="Output directory", description="Select the output directory", style="directory") outputDir
// @File(label="Weka model", description="Select the Weka model to apply") modelPath
// @String(label="Result mode",choices={"Labels","Probabilities"}) resultMode
 

import trainableSegmentation.WekaSegmentation;
import trainableSegmentation.utils.Utils;
import ij.io.FileSaver;
import ij.IJ;
import ij.ImagePlus;
  
// starting time
startTime = System.currentTimeMillis();
  
// caculate probabilities?
getProbs = resultMode.equals( "Probabilities" );
 
// create segmentator
segmentator = new WekaSegmentation();
// load classifier
segmentator.loadClassifier( modelPath.getCanonicalPath() );
  
// get list of input images
listOfFiles = inputDir.listFiles();
for ( i = 0; i < listOfFiles.length; i++ )
{
    // process only files (do not go into sub-folders)
    if( listOfFiles[ i ].isFile() )
    {
        // try to read file as image
        image = IJ.openImage( listOfFiles[i].getCanonicalPath() );
        if( image != null )
        {                   
            // apply classifier and get results (0 indicates number of threads is auto-detected)
            result = segmentator.applyClassifier( image, 0, getProbs );
            
 
            if( !getProbs )
                // assign same LUT as in GUI
                result.setLut( Utils.getGoldenAngleLUT() );
             
            // save result as TIFF in output folder
            outputFileName = listOfFiles[ i ].getName().replaceFirst("[.][^.]+$", "") + ".tif";
            new FileSaver( result ).saveAsTiff( outputDir.getPath() + File.separator + outputFileName );
  
            // force garbage collection (important for large images)
            result = null; 
            image = null;
            System.gc();
        }
    }
}
// print elapsed time
estimatedTime = System.currentTimeMillis() - startTime;
IJ.log( "** Finished processing folder in " + estimatedTime + " ms **" );
  1. the result images are saved in another file with these names (x.tif) (there not perfect, just for testing)

3.tif (674.5 KB) 5.tif (674.5 KB) 8.tif (674.5 KB) 11.tif (674.5 KB)

  1. with Process > Multiple Image processor you can use a macro on all of them which would be this:

imageTitle = getTitle();
getRawStatistics(nPixels, mean, min, max); 
             

setBatchMode( true );
run("Set Measurements...", "area_fraction display redirect=None decimal=3");

for( i=min, n=0; i <= max; i++, n++ )
{	
	run("Duplicate...", "title=[" + imageTitle + "_result]");
	selectWindow(imageTitle + "_result");
	setThreshold( i, i );
	run("Convert to Mask");
	run("Measure");
    setResult("Label", n, imageTitle);
	close();
}

however, the results look like this now:

8.tif 0.480
8.tif 14.464
8.tif 85.056
3.tif_result 0.471
3.tif_result 15.363
3.tif_result 84.166
5.tif_result 0.027
5.tif_result 17.624
5.tif_result 82.350
8.tif_result 0.792
8.tif_result 10.549
8.tif_result 88.659

the names (x.tif_result) are fine but somehow there are two “8.tif” and the “11.tif” is missing?
(And yes three results together should have the same file name (x.tif) so thats fine)
This is really confusing now…maybe its because the “11.tif” is the first/last one which is processed? Because both “8.tif” have different results, so I imagine one of them has the wrong name since the “result” is missing as well.
Initially I thought this would be a simple task compared what I saw on this site but I’m just to bad at this, I really need to delete my account after this.

And if you delete for example “11.tif” and then run it the results look like this:

8.tif 0.471
8.tif 15.363
8.tif 84.166
5.tif_result 0.027
5.tif_result 17.624
5.tif_result 82.350
8.tif_result 0.792
8.tif_result 10.549
8.tif_result 88.659

Sorry for the delay in responding @san

I’m still working on my Monday-morning coffee… so sorry - but I’m a bit confused by what is occurring in your code as well… I recommend trying a few things - including inserting print(); calls - to test your imageTitle variable as you move through the for loop. Also - I don’t think you need the selectWindow(imageTitle + "_result"); call in the for loop or to even rename the duplicated image (so just use run("Duplicate...", " "); - because you just close it without saving - no?? Also use the print(n); statement to be sure n is incrementing correctly.

Those are all the tests I would do for the moment… Be sure to include @etarena in your reply… then I won’t miss it.

Too @san -

If you don’t want to batch process using the script I posted above (no worries if you don’t want to do it via that script) - I would advise using Process > Batch > Macro… instead of the Multiple Image Processor. “Macro…” is the built-in command… as opposed to an external plugin that is no longer updated, etc.

Too @etarena -

You really have great patience with me, thank you.
So I tried your suggestions, but everytime i touch the run("Duplicate...", " "); call nothing works anymore. Guess the code is just not for folder processing.
However I tried:

// "BatchProcessFolders"
//
// This macro batch processes all the files in a folder and any
// subfolders in that folder. In this example, it runs the Subtract 
// Background command of TIFF files. For other kinds of processing,
// edit the processFile() function at the end of this macro.

   requires("1.33s"); 
   dir = getDirectory("Choose a Directory ");
   setBatchMode(true);
   count = 0;
   countFiles(dir);
   n = 0;
   processFiles(dir);
   //print(count+" files processed");
   
   function countFiles(dir) {
      list = getFileList(dir);
      for (i=0; i<list.length; i++) {
          if (endsWith(list[i], "/"))
              countFiles(""+dir+list[i]);
          else
              count++;
      }
  }

   function processFiles(dir) {
      list = getFileList(dir);
      for (i=0; i<list.length; i++) {
          if (endsWith(list[i], "/"))
              processFiles(""+dir+list[i]);
          else {
             showProgress(n++, count);
             path = dir+list[i];
             processFile(path);
          }
      }
  }

  function processFile(path) {
       if (endsWith(path, ".tif")) {
           open(path);
           imageTitle = getTitle();
getRawStatistics(nPixels, mean, min, max); 

setBatchMode( true );
run("Set Measurements...", "area_fraction display redirect=None decimal=3");

for( i=min, n=0; i <= max; i++, n++ )
{	
	run("Duplicate...", " ");
	setThreshold( i, i );
	run("Convert to Mask");
	run("Measure");
    setResult("Label", n, imageTitle);
	close();
}
           save(path);
           close();
      }
  }
}

which finally gives the correct result format:

1-1.tif 2.920
1-1.tif 33.431
1-1.tif 63.649
10-1.tif 0.165
10-1.tif 27.575
10-1.tif 72.261
3-1.tif 0.583
3-1.tif 19.938

(It also gives the error message: “Statment cannot begin with ‘}’ in line 62” but … that it works despite that and if you remove the } it gives the same damn wrong result format like in my posts above :smiley: )
Hope that does it!!!
Thank you soooo much for your help

@san

So it’s working for you? I think you are missing a { in your last function in that code… i think? it’s hard for me to tell though…