Custom Analysis
This example shows how to set the attributes of a measurement and how to create a new measurement from a user defined formula.
Several native measurements of ImageDev can be customized by setting some parameters. For instance, the
orientation of the Feret diameters to be computed can be user-defined. By default, the Feret diameter
measurement contains 10 orientations with a pitch of 18 degrees.
This example shows first how to reduce these orientations to 0 and 90 degrees by selecting two diameters and resampling the distribution between 0 and 180 degrees. The setOrientation method can also be used for this purpose, especially if the expected distribution is not uniform.
Then, this example shows how to create a new measurement from a user-defined formula corresponding to a circularity factor. The validity of the formula is checked, and the new measurement is selected in the analysis.
See also
This example shows first how to reduce these orientations to 0 and 90 degrees by selecting two diameters and resampling the distribution between 0 and 180 degrees. The setOrientation method can also be used for this purpose, especially if the expected distribution is not uniform.
Then, this example shows how to create a new measurement from a user-defined formula corresponding to a circularity factor. The validity of the formula is checked, and the new measurement is selected in the analysis.
#include <ImageDev/ImageDev.h>
#include <ioformat/IOFormat.h>
#include <string.h>
using namespace imagedev;
using namespace ioformat;
using namespace iolink;
int
main( int argc, char* argv[] )
{
int status = 0;
try
{
// ImageDev library initialization if not done
if ( isInitialized() == false )
imagedev::init();
// Open a grayscale image from a tif file
auto imageInput = readImage( std::string( IMAGEDEVDATA_IMAGES_FOLDER ) + "objects.tif" );
// Threshold and label the binary input
auto imageBin = thresholdingByCriterion( imageInput,
ThresholdingByCriterion::ComparisonCriterion::GREATER_THAN_OR_EQUAL_TO,
40 );
auto imageLab = labeling2d( imageBin, Labeling2d::LABEL_8_BIT, Labeling2d::CONNECTIVITY_8 );
// Change the number of Feret diameter to 2 (0 and 90 degrees)
MeasurementAttributes::feret2d()->setOrientationCount( 2 );
MeasurementAttributes::feret2d()->resample();
std::cout << "FeretDiameter[0] = " + std::to_string( MeasurementAttributes::feret2d()->orientation( 0 ) )
<< std::endl;
std::cout << "FeretDiameter[1] = " + std::to_string( MeasurementAttributes::feret2d()->orientation( 1 ) )
<< std::endl;
// Create a circularity factor between 0 and 1
std::string myFormula( "4*Pi*" + NativeMeasurements::area2d->name() + "/" +
NativeMeasurements::polygonePerimeter2d->name() + "**2" );
if ( !checkMeasurementFormula( myFormula ) )
// Raise an exception if the formula is not valid
throw imagedev::Exception( "Invalid formula: " + myFormula );
const auto* myCircularity = AnalysisMsr::registerCustomMeasurement( "MyCircularity",
myFormula,
"A circularity factor between 0 and 1." );
// Define the analysis features to be computed
AnalysisMsr::Ptr analysis = std::make_shared< AnalysisMsr >();
analysis->select( NativeMeasurements::feretDiameter2d );
analysis->select( myCircularity );
// Launch the feature extraction on the segmented image
labelAnalysis( imageLab, imageInput, analysis );
// Export the analysis in a dataframe and save it in a csv file
auto dataframe = analysis->toDataFrame();
writeView( dataframe, "T04_04_analysis.csv" );
std::cout << "This example ran successfully." << std::endl;
}
catch ( const imagedev::Exception& error )
{
// Print potential exception in the standard output
std::cerr << "T04_05_CustomAnalysis exception: " << error.what() << std::endl;
status = -1;
}
// ImageDev library finalization
imagedev::finish();
// Check if we must ask for an enter key to close the program
if ( !( ( argc == 2 ) && strcmp( argv[1], "--no-stop-at-end" ) == 0 ) )
std::cout << "Press Enter key to close this window." << std::endl, getchar();
return status;
}
using System;
using ImageDev;
using IOLink;
using IOFormat;
namespace T04_05_CustomAnalysis
{
class Program
{
static void Main( string[] args )
{
int status = 0;
try
{
// Initialize the ImageDev library if not done
if ( Initialization.IsInitialized() == false )
Initialization.Init();
// Open a grayscale image from a tif file
ImageView imageInput = ViewIO.ReadImage( "Data/images/objects.tif" );
// Threshold and label the binary input
var imageBin = Processing.ThresholdingByCriterion(
imageInput, ThresholdingByCriterion.ComparisonCriterion.GREATER_THAN_OR_EQUAL_TO, 40 );
var imageLab = Processing.Labeling2d( imageBin );
// Change the number of Feret diameter to 2 (0 and 90 degrees)
MeasurementAttributes.feret2d().orientationCount = 2;
MeasurementAttributes.feret2d().Resample();
Console.WriteLine( "FeretDiameter[0] = " + MeasurementAttributes.feret2d().Orientation( 0 ) );
Console.WriteLine( "FeretDiameter[1] = " + MeasurementAttributes.feret2d().Orientation( 1 ) );
// Create a circularity factor between 0 and 1
string myFormula = "4*Pi*" + NativeMeasurements.Area2d.name + "/" +
NativeMeasurements.PolygonePerimeter2d.name + "**2";
if ( !Processing.CheckMeasurementFormula( myFormula ) )
// Raise an exception if the formula is not valid
throw new Exception( "Invalid formula: " + myFormula );
var myCircularity = AnalysisMsr.RegisterCustomMeasurement( "MyCircularity",
myFormula,
"A circularity factor between 0 and 1." );
// Define the analysis features to be computed
AnalysisMsr analysis = new AnalysisMsr();
analysis.Select( NativeMeasurements.FeretDiameter2d );
analysis.Select( myCircularity );
// Launch the feature extraction on the segmented image
Processing.LabelAnalysis( imageLab, imageInput, analysis );
// Export the analysis in a dataframe and save it in a csv file
DataFrameView dataframe = analysis.ToDataFrame();
ViewIO.WriteView( dataframe, "T04_05_analysis.csv" );
// Notify the garbage collector that the created images can be freed
imageInput.Dispose();
imageBin.Dispose();
imageLab.Dispose();
Console.WriteLine( "This example ran successfully." );
}
catch ( Exception error )
{
// Print potential exception in the standard output
System.Console.WriteLine( "T04_05_CustomAnalysis exception: " + error.ToString() );
status = -1;
}
// ImageDev library finalization
Initialization.Finish();
// Check if we must ask for an enter key to close the program
if ( !( ( args.Length >= 1 ) && ( args[0] == "--no-stop-at-end" ) ) )
{
System.Console.WriteLine( "Press Enter key to close this window." );
System.Console.ReadKey();
}
System.Environment.Exit( status );
}
}
}
import imagedev
import imagedev_data
import ioformat
try:
# Initialize the ImageDev library if not done
if not imagedev.is_initialized(): imagedev.init()
# Open a grayscale image from a tif file
image_input = ioformat.read_image(imagedev_data.get_image_path('objects.tif'))
# Threshold and label the binary input
image_bin = imagedev.thresholding_by_criterion(image_input, comparison_value=40)
image_lab = imagedev.labeling_2d(image_bin, imagedev.Labeling2d.LabelType.LABEL_8_BIT)
# Change the number of Feret diameter to 2 (0 and 90 degrees)
imagedev.MeasurementAttributes.feret2d.orientation_count = 2
imagedev.MeasurementAttributes.feret2d.resample()
print(f'FeretDiameter[0] = {imagedev.MeasurementAttributes.feret2d.orientation(0)}')
print(f'FeretDiameter[1] = {imagedev.MeasurementAttributes.feret2d.orientation(1)}')
# Create a circularity factor between 0 and 1
my_formula = '4*Pi*' + imagedev.native_measurements.Area2d.name + '/' + \
imagedev.native_measurements.PolygonePerimeter2d.name + '**2'
if not imagedev.check_measurement_formula(my_formula):
# Raise an exception if the formula is not valid
raise Exception('Invalid formula ' + my_formula)
my_circularity = imagedev.AnalysisMsr.register_custom_measurement('MyCircularity', my_formula,
'A circularity factor between 0 and 1.')
# Define the analysis features to be computed
analysis = imagedev.AnalysisMsr()
analysis.select(imagedev.native_measurements.FeretDiameter2d)
analysis.select(my_circularity)
# Launch the feature extraction on the segmented image
imagedev.label_analysis(image_lab, image_input, analysis)
# Print the analysis in the standard output
print(analysis.to_data_frame())
print("This example ran successfully.")
except Exception as error:
# Print potential exception in the standard output
print("T04_05_CustomAnalysis exception: " + str(error))
# ImageDev library finalization
imagedev.finish()
See also