ImageDev

- Getting Started
- ImageDev Python
- ImageDev C#
- ImageDev C++
- Licensing Information
- Redistributable Files
- Processing
- Image Manipulation
- - Synthetic Images
  - - RandomImage2d
    - RandomImage3d
    - RandomGaussianImage2d
    - RandomGaussianImage3d
    - RadialFunctionImage2d
    - RadialFunctionImage3d
    - OrientedLinesImage2d
    - OrientedLinesImage3d
    - RandomSphereImage3d
    - BoxGridImage2d
    - BoxGridImage3d
    - WedgeMaskImage3d
    - PointSpreadFunctionImage3d
  - Image Editing
  - - ConvertImage
    - ResetImage
    - CopyImage
    - PasteImage2d
    - PasteImage3d
    - CropImage2d
    - CropImage3d
    - SampleImage2d
    - SampleImage3d
    - InterlaceFrames2d
    - DeinterlaceFrames2d
  - Stack Operations
  - - SequenceConcatenation
    - SequenceToMultispectral
    - SequenceToVolume
    - VolumeToSequence
    - MultispectralToSequence
    - GetSliceFromVolume3d
    - SetSliceToVolume3d
    - GetObliqueSliceFromVolume3d
    - ImageStackProjection3d
    - VolumeProjection3d
- Geometry And Matching
- - Geometric Transforms
  - - Shearing3d
    - TranslateImage2d
    - TranslateImage3d
    - Flip2d
    - Flip3d
    - FlipImage2d
    - FlipImage3d
    - TransposeImage2d
    - TransposeImage3d
    - SwapQuadrants
    - Rotate2d
    - Rotate3d
    - RotationGenerator3d
    - Resize2d
    - Resize3d
    - RescaleByFactor
    - RescaleImageByFactor
    - ResampleAffine2d
    - ResampleAffine3d
    - ResampleElastic2d
    - SurfaceUnfolding3d
  - Pattern Recognition
  - - BinaryCorrelation2d
    - CrossCorrelation2d
    - CorrelationByDifference2d
    - CorrelationBySignChange2d
  - Registration
  - - ImagePrealignment3d
    - AffineRegistration
    - ElasticRegistration2d
- Arithmetic And Logic
- - Arithmetical Operations
  - - AbsoluteValue
    - AbsoluteMaximumWithImage
    - ArithmeticOperationWithImage
    - ArithmeticOperationWithValue
    - BlendWithImage
    - BlendWithValue
    - DirectionalBlending2d
    - CombineByMask
    - ImageFormula
    - EigenDecomposition2d
    - EigenDecomposition3d
  - Logical Operations
  - - MaskImage
    - LogicalOperationWithImage
    - LogicalOperationWithValue
    - LogicalNot
    - InvertImage
    - BitShift
- Image Filtering
- - Grayscale Transforms
  - - RescaleIntensity
    - StackRescaleIntensity
    - MatchContrast
    - HistogramEqualization
    - Clahe2d
    - Clahe3d
    - AdaptiveHistogramEqualization
    - ApplyGrayscaleLut
    - BackgroundImage2d
    - RadialBackgroundImage2d
    - ShadingCorrection
    - Exponential
    - Logarithm
    - Square
    - SquareRoot
    - RingArtifactRemoval3d
    - BeamHardeningCorrection3d
  - Color Transforms
  - - ColorToLightness
    - GetColorChannel
    - ColorToGrayscale
    - GrayscaleToColor
    - ColorSpaceConversion
    - ColorAntialiasing2d
    - BayerToRgb2d
    - DecorrelationStretch2d
    - BlendAlphaChannelWithImage
    - BlendAlphaChannelWithValue
  - Smoothing And Denoising
  - - BoxFilter2d
    - BoxFilter3d
    - MedianFilter2d
    - MedianFilter3d
    - GaussianFilter2d
    - GaussianFilter3d
    - ExponentialFilter2d
    - RecursiveExponentialFilter2d
    - RecursiveExponentialFilter3d
    - NonLocalMeansFilter2d
    - NonLocalMeansFilter3d
    - CurvatureDrivenDiffusion
    - BilateralFilter2d
    - BilateralFilter3d
    - MajorityFilter2d
    - MajorityFilter3d
    - SigmaFilter2d
    - SigmaFilter3d
    - Despeckle2d
    - Despeckle3d
    - NagaoFilter2d
    - NagaoFilter3d
    - SnnFilter2d
    - SnnFilter3d
    - FlowInpainting
  - Sharpening
  - - Deblurring2d
    - Delineate2d
    - Delineate3d
    - UnsharpMasking2d
    - UnsharpMasking3d
    - Shade2d
    - RichardsonLucyDeconvolution
  - Texture Filters
  - - MeanFilter2d
    - MeanFilter3d
    - VarianceFilter2d
    - VarianceFilter3d
    - SkewnessFilter2d
    - SkewnessFilter3d
    - KurtosisFilter2d
    - KurtosisFilter3d
    - ContrastFilter2d
    - ContrastFilter3d
    - VariationFilter2d
    - VariationFilter3d
    - EnergyFilter2d
    - EnergyFilter3d
    - EntropyFilter2d
    - EntropyFilter3d
    - AutocorrelationFilter
    - LocalAutocorrelationFilter2d
    - ImageCurvature2d
    - ImageCurvature3d
    - StructureEnhancementFilter2d
    - StructureEnhancementFilter3d
    - ScaleSpaceLogFilter2d
    - ScaleSpaceLogFilter3d
  - Frequency Domain
  - - ComplexFft
    - ComplexFftInverse
    - ComplexCenteredFft
    - ComplexCenteredFftInverse
    - CartesianToPolar2d
    - PolarToCartesian2d
    - ConvolutionWithImage
    - ConvolutionWithImage2d
    - RadialFrequencyFilter2d
    - GaborFiltering2d
- Edge Detection
- - Gradient
  - - GradientOperator2d
    - GradientOperator3d
    - VectorToMagnitude2d
    - VectorToMagnitude3d
    - GradientVector2d
    - GradientVector3d
    - GradientMagnitude2d
    - GradientMagnitude3d
    - MorphologicalGradient2d
    - MorphologicalGradient3d
    - RadialGradientCentered2d
    - RadialGradientCentered3d
    - RadialGradientContour2d
    - RadialGradientContour3d
    - RadialGradientLabel2d
    - RadialGradientLabel3d
  - Laplacian
  - - DobFilter2d
    - DobFilter3d
    - MorphologicalLaplacian
    - RecursiveLaplacian2d
    - RecursiveLaplacian3d
  - Other Derivatives
  - - GaussianDerivative2d
    - GaussianDerivative3d
    - GaussianHessianMatrix2d
    - GaussianHessianMatrix3d
    - GaussianGradientTensor2d
    - GaussianGradientTensor3d
  - Edge Marking
  - - ImageLocalMaxima2d
    - ImageLocalMaxima3d
    - RidgeDetection
    - ZeroCrossings2d
    - DijkstraShortestPath2d
    - EigenvaluesToStructureness2d
    - EigenvaluesToStructureness3d
    - TensorVoting2d
    - CannyEdgeDetector2d
    - CannyEdgeDetector3d
- Image Segmentation
- - Binarization
  - - Thresholding
    - ThresholdingByCriterion
    - AutoThresholdingBright
    - AutoThresholdingDark
    - ColorThresholding
    - TopHat
    - FeatureAdaptiveThresholding
    - AdaptiveThresholding2d
    - AdaptiveThresholding3d
    - HysteresisThresholding
  - Labeling
  - - Labeling2d
    - Labeling3d
    - ReorderLabels
    - AssignLabel
    - AddObjectToLabel
    - GroupCloseLabelsl2d
  - Feature Selection
  - - KillBorder2d
    - KillBorder3d
    - RemoveSmallSpots
    - ObjectBoundaries
    - BinarySmoothing2d
    - BinarySmoothing3d
    - LabelInterfaces
  - Separating And Filling
  - - FillHoles2d
    - FillHoles3d
    - RemoveSmallHoles
    - FillImageBorder3d
    - ExpandLabelBoundaries
    - SeparateObjects
    - HExtremaWatershed
    - SeparateObjectsByBlock
    - HExtremaWatershedByBlock
    - ConvexHull2d
  - Region Growing
  - - MarkerBasedWatershed2d
    - MarkerBasedWatershed3d
    - MarkerBasedWatershedByBlock
    - MarkerBasedWatershedBasinsByBlock
    - ExpandLabelsOnBackground
    - FloodFillThreshold2d
    - FloodFillThreshold3d
    - Waterpixel
  - Computational Geometry
  - - PolylineResampler2d
    - PolylineResampler3d
    - PolylineExtrusion3d
    - SurfaceFitting3d
- Mathematical Morphology
- - Erosion And Dilation
  - - Erosion2d
    - Erosion3d
    - Dilation2d
    - Dilation3d
    - ErosionDisk2d
    - ErosionDisk3d
    - ErosionBall3d
    - DilationDisk2d
    - DilationDisk3d
    - DilationBall3d
    - ErosionLine2d
    - ErosionLine3d
    - DilationLine2d
    - DilationLine3d
    - ErosionColor2d
    - DilationColor2d
    - SelectiveErosion2d
    - SelectiveErosion3d
    - SelectiveDilation2d
    - SelectiveDilation3d
  - Opening And Closing
  - - Opening2d
    - Opening3d
    - Closing2d
    - Closing3d
    - OpeningDisk2d
    - OpeningDisk3d
    - OpeningBall3d
    - ClosingDisk2d
    - ClosingDisk3d
    - ClosingBall3d
    - OpeningLine2d
    - OpeningLine3d
    - ClosingLine2d
    - ClosingLine3d
    - OpeningLineMaximum
    - ClosingLineMinimum
    - OpeningColor2d
    - ClosingColor2d
    - OpeningByReconstruction2d
    - OpeningByReconstruction3d
    - ClosingByReconstruction2d
    - ClosingByReconstruction3d
    - OpeningDiskByReconstruction2d
    - OpeningBallByReconstruction3d
    - ClosingDiskByReconstruction2d
    - ClosingBallByReconstruction3d
    - SelectiveOpening2d
    - SelectiveOpening3d
    - SelectiveClosing2d
    - SelectiveClosing3d
  - Hit Or Miss And Skeleton
  - - Skeleton
    - Centerline3d
    - InfluenceZones
    - Centroid2d
    - EndPoints2d
    - EndPoints3d
    - Pruning2d
    - Pruning3d
    - IsolatedPoints2d
    - IsolatedPoints3d
    - TriplePoints2d
    - InteriorPoints2d
    - ApplyMorphologicalLut2d
    - ApplyMorphologicalLut3d
  - Geodesic Transformations
  - - ReconstructionFromMarkers2d
    - ReconstructionFromMarkers3d
    - GrayscaleReconstruction2d
    - GrayscaleReconstruction3d
    - GrayscaleFillHoles2d
    - GrayscaleFillHoles3d
    - HExtrema2d
    - HExtrema3d
    - RegionalExtrema2d
    - RegionalExtrema3d
    - UltimateErosion
  - Distance Maps
  - - DistanceMap2d
    - DistanceMap3d
    - EuclideanDistanceMap3d
    - EuclideanDistanceMap2d
    - GeodesicDistanceMap
    - ClosestBoundaryPoints2d
    - ClosestBoundaryPoints3d
    - TimeMap
    - LocalThicknessMap3d
    - GeodesicPropagation2d
    - GeodesicMaxima
    - GeodesicMinima
- Image Analysis
- - Image Measurements
  - - BinaryAnalysis
    - Area2d
    - Area3d
    - IntensityIntegral2d
    - IntensityIntegral3d
    - ObjectCount
    - DistanceMean2d
    - EulerNumber2d
    - EulerNumber3d
    - FractalDimension
    - CurvatureIntegrals3d
  - Image Statistics
  - - IntensityExtrema
    - IntensityStatistics
    - IntensityMaskedStatistics
    - IntensityHistogram
    - IntensityBinHistogram
    - AutoThresholdingValue
    - CompareImage
    - CompareValue
    - SimilarityMetricValue
    - SsimValue2d
    - SsimValue3d
    - RegionSimilarity
    - RadialIntensityProfile2d
    - RadialIntensityProfile3d
    - CylindricalIntensityProfile3d
    - RadialAutocorrelationProfile
    - Cooccurrence2d
    - MeasureGaussianNoise
    - LocalMaxima2d
    - LocalMaxima3d
    - PeakExtractor
    - LocalDensityMap2d
    - LocalDensityMap3d
    - SegmentationMetrics
  - Individual Measurements
  - - VolumeFractionByLabel
    - LabelCountByRegion
    - VolumeFractionByRegion
    - LabelAnalysis
    - LabelFiltering
    - LabelFilteringAnalysis
    - FilterAnalysis
    - MeasurementToImage
    - FilterByMeasurement
    - SieveLabeling
  - Moments And Orientations
  - - MomentsOfInertia2d
    - MomentsOfInertia3d
    - InertiaMoment2d
    - Eccentricity2d
    - OrientationMapFourier3d
    - OrientationMatchingFourier3d
  - Morphometry
  - - ObjectVolume
    - TotalImageVolume
    - ObjectBoundaryArea
    - TotalImageBoundaryArea
    - AverageObjectAreaPerSlice3d
    - AverageObjectCountPerSlice3d
    - ObjectImageRatio
    - ObjectSpecificSurface
    - ObjectSurfaceDensity
    - PorosityPercentage3d
    - FragmentationIndex
    - StructureModelIndex3d
    - AverageObjectThickness3d
    - AverageSpaceThickness3d
    - ObjectLinearDensity3d
    - DegreeOfAnisotropy
  - Propagation
  - - AxisPropagationBinary3d
    - AxisPropagationBinaryWithSeeds3d
    - AxisPropagationLabel3d
    - AxisPropagationLabelWithSeeds3d
    - AxisPropagationDistance3d
    - EstimateShortestPath3d
    - PercolationThreshold3d
    - AxisConnectivity3d
    - CentroidPathTortuosity3d
- Machine Learning
- - Classification
  - - AutoSegmentation3Phases
    - AutoIntensityClassification
    - SupervisedTextureClassification2d
    - SupervisedTextureClassification3d
    - TextureClassificationCreate
    - TextureClassificationTrain
    - TextureClassificationApply
  - Deep learning
  - - OnnxPredictionFiltering2d
    - OnnxPredictionFiltering3d
    - OnnxPredictionSegmentation2d
    - OnnxPredictionSegmentation3d
    - OnnxPredictionTwoOutputs2d
    - OnnxPredictionTwoOutputs3d
- Business Application
- - Dental
  - - DentalWallSegmentation3d
    - DentalMeshExtraction3d
    - DentalUnfolding3d
- IO
- - Image Data
  - - ReadVipImage
    - WriteVipImage
  - Algebraic Data
  - - ReadArrayXd
    - ReadArrayXi64
    - WriteArrayXd
    - WriteArrayXi64
  - Model
  - - ReadOnnxModel
- CUDA
- - Geometry And Matching
  - - CudaCrossCorrelation2d
    - CudaTemplateMatching3d
  - Image Filtering
  - - CudaBoxFilter2d
    - CudaMedianFilter2d
    - CudaGaussianFilter3d
    - CudaAdaptiveManifoldNlmFilter
  - Mathematical Morphology
  - - CudaErosion2d
    - CudaDilation2d
    - CudaOpening2d
    - CudaClosing2d
- Utilities
- Initialization
- Processing
- Syntax Check
- Visualization
- Data Object
- Image Data
- Kernels
- - MorphologicalKernel2d
  - MorphologicalKernel3d
  - MorphologicalLut2d
  - MorphologicalLut3d
- Model
- - TextureClassificationModel
  - OnnxModel
- Global Measurements
- - Image Measurements
  - - Area2dMsr
    - Area3dMsr
    - IntensityIntegral2dMsr
    - IntensityIntegral3dMsr
    - ObjectCountMsr
    - DistanceMeanMsr
    - Euler2dMsr
    - Euler3dMsr
    - FractalMsr
    - CurvatureIntegralsMsr
  - Image Statistics
  - - IntensityExtremaMsr
    - StatisticsMsr
    - IntensityHistogramMsr
    - IntensityBinHistogramMsr
    - CompareMsr
    - SimilarityMetricValueMsr
    - SsimValueMsr
    - RegionSimilarityMsr
    - SegmentationMetricsObjectMsr
    - SegmentationMetricsImageMsr
    - CylindricalIntensityProfileMsr
    - RadialIntensityProfileMsr
    - CorrelationMsr
    - CoocurrrenceMsr
    - GaussianNoiseMsr
    - LocalMaximaMsr
    - PeakExtractorMsr
  - Individual Measurements
  - - VolumeFractionByLabelMsr
    - LabelCountByRegionMsr
    - VolumeFractionByRegionMsr
  - Moments And Orientations
  - - MomentsOfInertia2dMsr
    - MomentsOfInertia3dMsr
    - MeanInertiaMomentMsr
    - Eccentricity2dMsr
    - LocalOrientation3dMsr
  - Morphometry
  - - ObjectVolumeMsr
    - ImageVolumeMsr
    - ObjectBoundaryAreaMsr
    - ImageBoundaryAreaMsr
    - AverageObjectAreaPerSliceMsr
    - AverageObjectCountPerSliceMsr
    - ObjectImageRatioMsr
    - ObjectSpecificSurfaceMsr
    - ObjectSurfaceDensityMsr
    - PorosityPercentageMsr
    - FragmentationMsr
    - StructureModelIndexMsr
    - AverageObjectThicknessMsr
    - AverageSpaceThicknessMsr
    - ObjectLinearDensityMsr
    - AnisotropyDegreeMsr
  - Propagation
  - - AxisPropagationBinary3dMsr
    - AxisPropagationLabel3dMsr
    - AxisPropagationDistance3dMsr
    - PercolationThreshold3dMsr
    - CentroidTortuosity3dMsr
  - Geometry And Matching
  - - CrossCorrelation2dMsr
  - Edge Detection
  - - CannyEdgeDetectorMsr
  - Image Segmentation
  - - AutoThresholdingMsr
    - AutoSegmentation3PhasesMsr
  - Mathematical Morphology
  - - ApplyMorphologicalLutMsr
- Analysis Measurements
- - AnalysisMsr
  - Measurement
  - Native Measurements
  - - Geometry
    - Feret
    - Intensity
    - Histogram
    - Inertia
    - Locate
    - Segment
    - Cooccurrence
  - CustomMeasurement
  - MeasurementAttributes
  - - Quantile
    - Histogram
    - Feret2d
    - Feret3d
    - NeighborCount
    - Cooccurrence
    - Breadth3d
  - MeasurementGroup
- Measurement Information
- - FieldInformation
  - CustomMeasurementInfo
- CUDA
- - CudaContext
- User Guide
- First Steps
- - Hello ImageDev
  - Initialize ImageDev
- Image Management
- - Create 2D Image
  - Create 3D Image
  - Data Transfer
- Standard Processing
- - Denoising
  - Thresholding
- Image Analysis
- - Global Analysis
  - Label Analysis
  - Measurement Browsing
  - Measurement Group
  - Custom Analysis
- Advanced Processing
- - Algorithm Tracking
- Typical Use Cases
- - Particle Analysis
  - Pore Analysis

# Particle Analysis

This example chains several classic image processing algorithms, and extracts features of particles contained in a grayscale image.
The first step of this example consists in binarizing the input grayscale image. The ThresholdingByCriterion algorithm is used to set all pixels with an intensity greater than 128 to 1 and the rest to 0.
Then the SeparateObjects algorithm is applied to disconnect the connected particles. This method computes a watershed on the distance map to detect isthmuses joining adjacent particles.
Many particles are touching the border of the image field. Since their entire shapes are unknown, these objects would generate a bias when measuring individual features on the particles. Therefore, the BorderKill algorithm is used to remove these objects.
Last, a labelization step is performed to assign a unique value to each set of connected pixels. In this way all particles are identified.

(a) | (b)
(c) | (d)

Figure 1. Particle segmentation (a) the initial image, (b) the thresholding result, (c) watershed based separation and (d) final image after rejecting border objects and labelization
Once this segmentation phase is done, the analysis algorithm is launched after having selected four measurements to compute:

- The X and Y center positions of the particles (the origin is the image top-left corner).
- The equivalent diameter of the particles (that is, the diameter of disks of same area).
- Their mean intensity in the original image.

The measurement results are finally printed in the console to show how to access each computed feature.

Number of particles = 58
Particle | BarycenterX | BarycenterY | EquivalentDiameter | IntensityMean
1 | 395.75 | 39.01 | 49.46 | 206.28
2 | 105.89 | 48.58 | 50.75 | 225.12
3 | 248.53 | 56.56 | 61.04 | 227.68
4 | 192.00 | 63.94 | 52.13 | 212.79
5 | 469.05 | 74.31 | 63.93 | 229.77

Note:
More than 250 other measurements are also available and described in the Native Measurements section of the ImageDev Reference Guide.

    #include <ImageDev/ImageDev.h>
    #include <ioformat/IOFormat.h>
    #include <iolink/view/ImageViewProvider.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 ( imagedev::isInitialized() == false )
                imagedev::init();

            // Open a standard tif file and display the image properties
            auto imageInput = readImage( std::string( IMAGEDEVDATA_IMAGES_FOLDER ) + "polystyrene.tif" );

            // Threshold the grayscale image
            auto imageThr =
                thresholdingByCriterion( imageInput, ThresholdingByCriterion::ComparisonCriterion::GREATER_THAN, 128 );

            // Separate connected particles
            auto imageSep = separateObjects( imageThr,
                                             2,
                                             SeparateObjects::OutputType::SEPARATED_OBJECTS,
                                             SeparateObjects::AlgorithmMode::REPEATABLE,
                                             SeparateObjects::Neighborhood::CONNECTIVITY_26 );
            imageThr.reset();

            // Remove particles touching image borders
            auto imageBdk = killBorder2d( imageSep, KillBorder2d::Neighborhood::CONNECTIVITY_8 );
            imageSep.reset();

            // Connected component labeling of a binary image
            auto imageLab =
                labeling2d( imageBdk, Labeling2d::LabelType::LABEL_8_BIT, Labeling2d::Neighborhood::CONNECTIVITY_8 );

            // The number of particles is the maximum label
            auto extrema = intensityExtrema( imageLab, 0 );
            int particleCount = ( int )extrema->maximum( 0, 0, 0 );

            // Define the analysis features to be computed
            AnalysisMsr::Ptr analysis = std::make_shared< AnalysisMsr >();
            auto centerX = analysis->select( NativeMeasurements::barycenterX );
            auto centerY = analysis->select( NativeMeasurements::barycenterY );
            auto diameter = analysis->select( NativeMeasurements::equivalentDiameter );
            auto intensity = analysis->select( NativeMeasurements::intensityMean );

            // Launch the feature extraction on the segmented image
            labelAnalysis( imageLab, imageInput, analysis );
            std::cout << "Number of particles = " << particleCount << std::endl;
            std::cout << "Particle\t" << centerX->name() << "\t" << centerY->name() << "\t"
                      << diameter->name() + "\t" + intensity->name() << std::endl;
            // Print the analysis results for 10% of the particles
            for ( int i = 0; i < ( int )( particleCount / 10 ); i++ )
            {
                std::cout << ( i + 1 ) << "\t\t" << centerX->value( i ) << "\t\t" << centerY->value( i ) << "\t\t"
                          << diameter->value( i ) << "\t\t\t" << intensity->value( i ) << std::endl;
            }

            // Save the created image with IOFormat
            writeView( imageLab, "T06_01_output.png" );

            std::cout << "This example ran successfully." << std::endl;
        }
        catch ( const imagedev::Exception& error )
        {
            // Print potential exception in the standard output
            std::cerr << "ImageDev 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 T06_01_ParticleAnalysis
    {
        class Program
        {
            static void Main(string[] args)
            {
                int status = 0;

                try
                {
                    // ImageDev library initialization
                    Initialization.Init();

                    // Open a standard tif file and display the image properties
                    ImageView imageInput = ViewIO.ReadImage("Data/images/polystyrene.tif");

                    // Threshold the grayscale image
                    ImageView imageThr = Processing.ThresholdingByCriterion(
                        imageInput, ThresholdingByCriterion.ComparisonCriterion.GREATER_THAN, 128);

                    // Separate connected particles
                    ImageView imageSep = Processing.SeparateObjects(imageThr, 2);
                    imageThr.Dispose();

                    // Remove particles touching image borders
                    ImageView imageBdk = Processing.KillBorder2d(imageSep);
                    imageSep.Dispose();

                    // Connected component labeling of a binary image
                    var imageLab = Processing.Labeling2d(imageBdk,
                                                          Labeling2d.LabelType.LABEL_8_BIT,
                                                          Labeling2d.Neighborhood.CONNECTIVITY_8);

                    // The number of particles is the maximum label
                    var extrema = Processing.IntensityExtrema(imageLab, 0) as IntensityExtremaMsr;
                    int particleCount = (int)extrema.maximum(0, 0, 0);

                    // Define the analysis features to be computed
                    AnalysisMsr analysis = new AnalysisMsr();
                    var centerX = analysis.Select(NativeMeasurements.BarycenterX);
                    var centerY = analysis.Select(NativeMeasurements.BarycenterY);
                    var diameter = analysis.Select(NativeMeasurements.EquivalentDiameter);
                    var intensity = analysis.Select(NativeMeasurements.IntensityMean);

                    // Launch the feature extraction on the segmented image
                    Processing.LabelAnalysis(imageLab, imageInput, analysis);
                    Console.WriteLine("Number of particles = " + particleCount);
                    Console.WriteLine("Particle\t" + centerX.Name() + "\t" + centerY.Name() + "\t" + diameter.Name() + "\t" +
                                       intensity.Name());
                    // Print the analysis results for 10% of the particles
                    for (int i = 0; i < (int)(particleCount / 10); i++)
                    {
                        Console.WriteLine((i + 1) + "\t\t" + centerX.Value(i).ToString("0.00") + "\t\t" +
                                           centerY.Value(i).ToString("0.00") + "\t\t" +
                                           diameter.Value(i).ToString("0.00") + "\t\t\t" +
                                           intensity.Value(i).ToString("0.00"));
                    }

                    // Save the created image with IOFormat
                    ViewIO.WriteView(imageBdk, "T06_01_output.png");

                }
                catch (Exception error)
                {
                    // Print potential exception in the standard output
                    System.Console.WriteLine("HelloImageDev 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

    # Open and display a tif file
    image_input = ioformat.read_image(imagedev_data.get_image_path("polystyrene.tif"))

    # Threshold the grayscale image
    image_thr = imagedev.thresholding_by_criterion(\
      image_input, imagedev.ThresholdingByCriterion.ComparisonCriterion.GREATER_THAN, 128)

    # Separate connected particles
    image_sep = imagedev.separate_objects(image_thr, 2)
    image_thr = None

    # Remove particles touching image borders
    image_bdk = imagedev.kill_border_2d(image_sep)
    image_sep = None

    # Connected component labeling of a binary image
    image_lab = imagedev.labeling_2d(\
      image_bdk, imagedev.Labeling2d.LabelType.LABEL_8_BIT, imagedev.Labeling2d.Neighborhood.CONNECTIVITY_8)

    # The number of particles is the maximum label
    extrema = imagedev.intensity_extrema(image_lab, 0)
    particle_count = int(extrema.maximum(0, 0, 0))

    # Define the analysis features to be computed
    analysis = imagedev.AnalysisMsr()
    center_x = analysis.select(imagedev.native_measurements.BarycenterX)
    center_y = analysis.select(imagedev.native_measurements.BarycenterY)
    diameter = analysis.select(imagedev.native_measurements.EquivalentDiameter)
    intensity = analysis.select(imagedev.native_measurements.IntensityMean)

    # Launch the feature extraction on the segmented image
    imagedev.label_analysis(image_lab, image_input, analysis)
    print("Number of particles = " + str(particle_count))
    print("Particle\t" + center_x.name + "\t" + center_y.name + "\t" + diameter.name + "\t" + intensity.name)
    # Print the analysis results for 10% of the particles
    for i in range(int(particle_count/10)):
      print(str(i+1) + '\t\t\t' + "{:.2f}".format(center_x.value(i)) +'\t\t' + "{:.2f}".format(center_y.value(i)) +\
        '\t\t' + "{:.2f}".format(diameter.value(i)) + '\t\t\t\t' + "{:.2f}".format(intensity.value(i)))

    # Save the created image with IOFormat
    ioformat.write_view(image_lab, "T06_01_output.png")

See also

- ThresholdingByCriterion
- SeparateObjects
- KillBorder2d
- Labeling2d
- LabelAnalysis

© 2025 Thermo Fisher Scientific Inc. All rights reserved.