Use trainable weka segmentation through macro

Hie,

I am trying to write a macro of Trainable Weka Segmentation in order to classify all my images one by one based on one classified model. I found a link on ImageJ website which specifies a Beanshell script that can make this process possible. But when I am trying to run this script its always showing error that modelPath is not set. Does anybody has any experience in this context?

The link to that script is here.

So @neel

I am no expert here at all on this… But my intuition says there is some problem with your @Parameters call(s). Those parameters are listed here at the top of the example 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 

Are you getting the other dialog boxes popping up and what to select the input/output directories, etc.?? This is where the modelpath is getting initially assigned.

Hope this gives a little insight…

eta :slight_smile:

Thanks for the reply @etadobson

Frankly speaking I have no idea where to specify the inputDir and other parameters in this script. But everytime when I run this beanshell script it just shows the error ‘modelPath is required but not set’. So, I am getting no idea how to call my images one by one and run the saved classifier model on those images to get the segmented result.

@neel

Can you post the script you are using? Or are you just applying this example as-is?

Too - read up quickly on Script Parameters… your issue with specifying the inputDir and all will make more sense then. These @Parameters will make your life so much easier !!! Trust me. :slight_smile:

eta

Currently, I am using following script:

// @File(label="C:\Users\Neel\Desktop\fiji_analysis\trial\", description="Select the directory with input images", style="directory") inputDir
// @File(label="C:\Users\Neel\Desktop\fiji_analysis\trial_result\", description="Select the output directory", style="directory") outputDir
// @File(label="C:\Users\Neel\Desktop\fiji_analysis\classifier\classifier_501.model", description="Select the Weka model to apply") modelPath
// @String(label="Labels",choices={"Labels","Probabilities"}) resultMode
 
import trainableSegmentation.WekaSegmentation;
import ij.io.FileSaver;
import ij.IJ;
import ij.ImagePlus;
 
// starting time
startTime = System.currentTimeMillis();
 
// caculate probabilities?
getProbs = resultMode.equals( "Labels" );
 
// 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 = new ImagePlus( listOfFiles[i].getCanonicalPath() );
        if( image != null )
        {       
            // create segmentator
            segmentator = new WekaSegmentation( image );
            // load classifier
            segmentator.loadClassifier( modelPath.getCanonicalPath() );
            // apply classifier and get results
            segmentator.applyClassifier( getProbs );
            result = segmentator.getClassifiedImage();
            // 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)
            segmentator = null;
            result = null; 
            image = null;
            System.gc();
        }
    }
}
// print elapsed time
estimatedTime = System.currentTimeMillis() - startTime;
IJ.log( "** Finished processing folder in " + estimatedTime + " ms **" );

and I am getting following error:

Sourced file: null : Attempt to resolve method: equals() on undefined variable or class name: resultMode : at Line: 15 : in file: : resultMode .equals ( “Labels” )

at bsh.UtilEvalError.toEvalError(Unknown Source)
at bsh.UtilEvalError.toEvalError(Unknown Source)
at bsh.BSHMethodInvocation.eval(Unknown Source)
at bsh.BSHPrimaryExpression.eval(Unknown Source)
at bsh.BSHPrimaryExpression.eval(Unknown Source)
at bsh.BSHAssignment.eval(Unknown Source)
at bsh.Interpreter.eval(Unknown Source)
at org.scijava.plugins.scripting.beanshell.BeanshellScriptEngine.eval(BeanshellScriptEngine.java:80)
at org.scijava.script.ScriptModule.run(ScriptModule.java:174)
at org.scijava.module.ModuleRunner.run(ModuleRunner.java:167)
at org.scijava.module.ModuleRunner.call(ModuleRunner.java:126)
at org.scijava.module.ModuleRunner.call(ModuleRunner.java:65)
at org.scijava.thread.DefaultThreadService$2.call(DefaultThreadService.java:191)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)

Suggest me how to solve it.

Hello @neel,

Here you are the problem:

As explained in the wiki, the label of the parameter is just the string showing up in the menu when you call the script. You have written there the path to your file instead. For that, you have the value keyword:

// @File(label="Input directory", description="Select the directory with input images", style="directory", value="C:\Users\Neel\Desktop\fiji_analysis\trial\") inputDir
// @File(label="Output directory", description="Select the output directory", style="directory", value="C:\Users\Neel\Desktop\fiji_analysis\trial_result\") outputDir
// @File(label="Weka model", description="Select the Weka model to apply", value="C:\Users\Neel\Desktop\fiji_analysis\classifier\classifier_501.model") modelPath
// @String(label="Result mode",choices={"Labels","Probabilities"}) resultMode

In any case, I recommend you run the original script from the Script Editor and choose manually the input and output folders and the path to the model file.

Let me know if you need more help!

3 Likes

Hello @iarganda

I did what you advised. I ran the original script in BeanShell language. A dialog box appeared to choose manually input and output folders. When I selected them and clicked, it is still showing the error. It is

Sourced file: null : Attempt to resolve method: equals() on undefined variable or class name: resultMode : at Line: 15 : in file: : resultMode .equals ( “Probabilities” )

at bsh.UtilEvalError.toEvalError(Unknown Source)
at bsh.UtilEvalError.toEvalError(Unknown Source)
at bsh.BSHMethodInvocation.eval(Unknown Source)
at bsh.BSHPrimaryExpression.eval(Unknown Source)
at bsh.BSHPrimaryExpression.eval(Unknown Source)
at bsh.BSHAssignment.eval(Unknown Source)
at bsh.Interpreter.eval(Unknown Source)
at org.scijava.plugins.scripting.beanshell.BeanshellScriptEngine.eval(BeanshellScriptEngine.java:80)
at org.scijava.script.ScriptModule.run(ScriptModule.java:174)
at org.scijava.module.ModuleRunner.run(ModuleRunner.java:167)
at org.scijava.module.ModuleRunner.call(ModuleRunner.java:126)
at org.scijava.module.ModuleRunner.call(ModuleRunner.java:65)
at org.scijava.thread.DefaultThreadService$2.call(DefaultThreadService.java:191)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)

Now, what should I try to make it work?

It looks like the variable resultMode has not been properly identified at the beginning of the script. Are you sure the following line is at the end of the initial comments of the script?

// @String(label="Result mode",choices={"Labels","Probabilities"}) resultMode

If it is there, this could be a bug in the script parameters in Windows and maybe @ctrueden can give you a hand.

In the meantime, you can replace this line in the script:

getProbs = resultMode.equals( "Probabilities" );

by this one:

getProbs = false;

if you want a segmentation as result, or

getProbs = true;

if you want the probabilities instead.

2 Likes

@iarganda thank you so much. It worked with getProbs = False.

I have one more query. What changes I have to make in the original script if I want to use filter option of maximizing and then skeletonisation in 2D.

What do you mean by maximizing?

@iarganda I am trying to use a Filter called ‘Maximum’ so that I may be able to join broken edges in a binary image. It’s under Process>Filters>Maximum.

From a macro (executing the maximum filter or radius 2.0 and 2D skeletonization in the current image):

run("Maximum...", "radius=2");
setOption("BlackBackground", true);
run("Skeletonize");

From a Beanshell script, assuming your image is called result (as in the original script from above):

import ij.IJ;
IJ.run( result, "Maximum...", "radius=2" );
IJ.run( result, "Skeletonize", "" );
1 Like

@iarganda

It is showing an error with skeletonisation code as this step needs an image to be 8-bit grayscale. I tried a lot but couldn’t figure out the way to convert image of segmentation from 32- bit color to 8-bit grayscale and then further make it binary.

I tried following way:
IJ.run(result, “Type”, “8-bit”);
IJ.run(result, “Make Binary”);

But this is not working. Please suggest the right code.

// apply maximum filter of radius 2.0 to "result" image
IJ.run( result, "Maximum...", "radius=2" );
// set threshold to isolate label 1
IJ.setThreshold( result, 1, 2 );
// apply threshold
IJ.run( result, "Convert to Mask", "" );
// skeletonize label 1
IJ.run( result, "Skeletonize", "" );
1 Like

@iarganda

Last code to first convert the result of segmented image of 32-bit type into 8-bit and then make it binary for skeletonisation is not working well.

The result that I am getting from your last code is posted as first image. And the second image is the desired result.



Please have a look.

Can you post here the result image you obtain from the classifier?

@iarganda

I am trying to upload the image but it’s not getting visible on this webpage. If you try to open the image by Right Click>Open link in new tab, then the image will get downloaded to your system.

See, if it works.

I don’t see any link. You can send me the image by e-mail or post it somewhere else (Dropbox, Google Drive, etc.).

Also, you can try playing with the numbers in setThreshold.

@iarganda

Your code worked with slight modification. I just added one more line that default background should be black and then the results were coming fine.

Thank you so much !!
For future, I am copying the complete script here so anybody can use it.

// @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 ij.io.FileSaver;
import ij.IJ;
import ij.ImagePlus;
 
// starting time
startTime = System.currentTimeMillis();
 
// caculate probabilities?
getProbs = false;
 
// 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 = new ImagePlus( listOfFiles[i].getCanonicalPath() );
        if( image != null )
        {       
            // create segmentator
            segmentator = new WekaSegmentation( image );
            // load classifier
            segmentator.loadClassifier( modelPath.getCanonicalPath() );
            // apply classifier and get results
            segmentator.applyClassifier( getProbs );
            result = segmentator.getClassifiedImage();
            // IJ.run(result, "8-bit");
           // IJ.run( result, "Make Binary" );
            IJ.setThreshold( result, 1, 2 );
            IJ.run( result, "Convert to Mask","");
            IJ.setAutoThreshold( result, "Default dark" );
            IJ.run( result, "Convert to Mask", "");
            IJ.run( result, "Maximum...", "radius=2" );
            IJ.run( result, "Skeletonize", "" );
            // 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)
            segmentator = null;
            result = null; 
            image = null;
            System.gc();
        }
    }
}
// print elapsed time
estimatedTime = System.currentTimeMillis() - startTime;
IJ.log( "** Finished processing folder in " + estimatedTime + " ms **" );
1 Like

@iarganda

I have one more problem in my analysis. If you can find time please see into that too. I posted it as a separate topic: