Create Training Data from Binary Mask

Hi guys,

I’ve been doing some scripting of the Trainable Weka Segmentation, such as applying a classifier to a folder of images. I want to use a binary mask for many images to generate .arff training data for only the positive label (white polygons shown in the mask below). I guess if that wasn’t possible then I could obtain a training data file with the positive and negative labels and then manually delete the negative (time consuming for many files) because they’re useless due to being a mixture of classes.

Could someone help me out with the beanshell script for this? I have used the “define training samples with binary labels” script but that has a different purpose compared to what I want to achieve.

Any help would be appreciated,

Cheers, Sam

I smacked some code together which seems to do what I want. Although, I don’t know how to specify the class names. At the moment I believe class two is where the white pixels in the mask are??

// @File(label=“Training images”, description=“Stack or a single 2D image”, style=“directory”) imageDir
// @File(label=“Label images”, description=“Image of same size as training image containing binary class labels”, style=“directory”) labelDir
// @File(label=“Output directory”, description=“Select the output directory”, style=“directory”) outputDir

import trainableSegmentation.*;
import ij.io.FileSaver;
import ij.IJ;
import ij.ImagePlus;
import hr.irb.fastRandomForest.FastRandomForest;

// starting time
startTime = System.currentTimeMillis();

// input train image
imageDir = imageDir;
labelDir = labelDir;

// get list of input images
listOfFiles = imageDir.listFiles();
listOfMasks = labelDir.listFiles();
for ( i = 0; i < listOfFiles.length; i++ )
{

numSamples = 10000;

// seg.setMembranePatchSize(11);  


// 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() );
    label = IJ.openImage( listOfMasks[i].getCanonicalPath() );
    if( image != null )
    {                   
        // apply classifier and get results (0 indicates number of threads is auto-detected)
        // create Weka Segmentation object
		seg = new WekaSegmentation( image );

		// maximum filter radius
		seg.setMaximumSigma(8.0f); 

			// Selected attributes (image features)
		boolean[] enableFeatures = new boolean[]{
		            true,   /* Gaussian_blur */
		            true,   /* Sobel_filter */
		            false,   /* Hessian */
		            false,   /* Difference_of_gaussians */
		            true,   /* Membrane_projections */
		            true,  /* Variance */
		            true,  /* Mean */
		            false,  /* Minimum */
		            false,  /* Maximum */
		            false,  /* Median */
		            false,  /* Anisotropic_diffusion */
		            false,  /* Bilateral */
		            true,  /* Lipschitz */
		            false,  /* Kuwahara */
		            false,  /* Gabor */
		            false,  /* Derivatives */
		            true,  /* Laplacian */
		            true,  /* Structure */
		            true,  /* Entropy */
		            false   /* Neighbors */
		};
		
		// Enable features in the segmentator
		seg.setEnabledFeatures( enableFeatures );

		// Classifier
		// In this case we use a Fast Random Forest
		//rf = new FastRandomForest();
		// Number of trees in the forest
		//rf.setNumTrees(25);
		          
		// Number of features per tree
		//rf.setNumFeatures(0);  
		// Seed  
		//rf.setSeed( (new java.util.Random()).nextInt() );    
		// set classifier  
		//seg.setClassifier(rf); 

		//class_name = new String[]{ "bare", "rest" };

		// Add new class
		//seg.addClass();
		//seg.addClass();
		
		// Set class names
		//seg.setClassLabels( class_name );

		// for the first slice, add white pixels as labels for class 2 and 
		// black pixels as labels for class 1
		//seg.addBinaryData( image, label,  "class 2", "class 1" );

        seg.addRandomBalancedBinaryData( image, label, "class 2", "class 1" , numSamples ); // "class 2", "class 1" ,

        // Initialize feature stack (no features yet)
		// featureStackArray = new FeatureStackArray(image.getImageStackSize(), enabledFeatures);

		// seg.trainClassifier(); 
     
        // generate good filename for arff
        outputFileName = listOfMasks[ i ].getName().replaceFirst("[.][^.]+$", "") + ".arff";
        // new FileSaver( result ).saveAsTiff( outputDir.getPath() + File.separator + outputFileName );
        
        // save data into a ARFF file
		seg.saveData( outputDir + "\\"  +  outputFileName );
		image = null;

        System.gc();
    }
}

}

// print elapsed time
estimatedTime = System.currentTimeMillis() - startTime;
IJ.log( “** Finished processing folder in " + estimatedTime + " ms **” );

Hello @Sam_Davidson,

You can add samples to any existing class using any of the options specified in the scripting site of TWS.

if you do this

seg.addRandomBalancedBinaryData( image, label, "class 2", "class 1" , numSamples );

“class 2” would be the white class, yes. Have a look at the API for that method.

1 Like