modules containing shape measures
More...
|
| | Formula |
| | Formula measures associated to a formula string.
|
| |
| | Geometry |
| | modules containing shape measures based on geometry
|
| |
| | Intensity |
| | modules containing shape measures based on intensity
|
| |
modules containing shape measures
This page presents some material to get start with shape analysis and measurement framework :
Introduction
Shape analysis framework allows to compute measures on a collection of shapes (also named blobs, connected components, particles, ...). It allows for example to measure indicators such as :
- area of shapes
- mean intensity
- number of holes
- etc.
It is associated to following algorithms :
A high level representation of this processing is given by following figure :
Shape analysis processing will usually takes on input :
- a collection of shape resulting from a segmentation process
- an input image allowing intensity measurements
- a collection of measures to be proceeded
On output each cupple measure/shape will be associated to a measurement result. This result is usually a single value (floating point, interger or boolean), but can also be a collection of values or even a custom result type.
These measure results can be individually accessed via some extraction function such as ipsdk::shape::analysis::extractValueResults or written to a 'csv' file using ipsdk::shape::analysis::saveCsvMeasureFile. For more informations on shape analysis measure results, please see Measure result.
Getting started with shape analysis
Usual case
The most classical case of usage for shape analysis framework is a case where user provide as input :
- a grey level image
- a shape collection issued from a segmentation process
Note that classical case of usage for shape analysis and measurement can uses package algorithm Label Analysis 2d and Label Analysis 3d. These algorithms simply allow to mask to user the shape extraction step and can replace Shape Analysis 2d and Shape Analysis 3d.
In the following we will supposed that these inputs are available.
Here is a code sample in 2d case :
Python code Example
inGreyImg = PyIPSDK.loadTiffImageFile(inputGreyImgPath)
inShape2dColl, bResRead = PyIPSDK.readFromXmlFile(inputShape2dCollPath)
unitTestMonitor.checkEqual(bResRead.getResult(), True)
inMeasureInfoSet2d = PyIPSDK.createMeasureInfoSet2d()
PyIPSDK.createMeasureInfo(inMeasureInfoSet2d, "PolygonArea2dMsr")
PyIPSDK.createMeasureInfo(inMeasureInfoSet2d, "MeanMsr")
outMeasureSet = shapeanalysis.shapeAnalysis2d(inGreyImg, inShape2dColl, inMeasureInfoSet2d)
PyIPSDK.saveCsvMeasureFile(csvOutputPath, outMeasureSet)
outArea2dMsr = outMeasureSet.getMeasure("PolygonArea2dMsr")
outMeanMsr = outMeasureSet.getMeasure("MeanMsr")
outArea2dValues = PyIPSDK.extractReal64Results(outArea2dMsr)
outMeanValues = PyIPSDK.extractReal64Results(outMeanMsr)
print("First label area 2d measurement equal " + str(outArea2dValues[1]))
print("First label mean intensity measurement equal " + str(outMeanValues[1]))
C++ code Example
const MeasureConstPtr& pArea2dOutMsr = pOutMeasureSet->getMeasure(
"PolygonArea2dMsr");
const std::vector<ipReal64>& area2dResults = extractValueResults<ipReal64>(pArea2dOutMsr);
const MeasureConstPtr& pMeanOutMsr = pOutMeasureSet->getMeasure(
"MeanMsr");
const std::vector<ipReal64>& meanResults = extractValueResults<ipReal64>(pMeanOutMsr);
In this sample user provides an input image pInGreyImg2d and an input shape 2d collection pShape2dColl and defines an input collection of measures to be proceeded pMeasureInfoSet composed of :
- an area 2d computation see Area2d
- an mean intensity computation over shape pixels see Mean
Once computation proceeded via call to ipsdk::imaproc::shape::analysis::shapeAnalysis2d function, user will be able to manipulate associated results :
Handling geometric calibration
Starting from previous example, we can add a geometrical calibration which will allows to convert geometric measurement from image gauge to user gauge.
Here is a code sample in 2d case :
Python code Example
inGreyImg = PyIPSDK.loadTiffImageFile(inputGreyImgPath)
inShape2dColl, bResRead = PyIPSDK.readFromXmlFile(inputShape2dCollPath)
unitTestMonitor.checkEqual(bResRead.getResult(), True)
geometricCalibration = PyIPSDK.createGeometricCalibration2d(0.01, 0.02, "mm");
inMeasureInfoSet2d = PyIPSDK.createMeasureInfoSet2d(geometricCalibration)
PyIPSDK.createMeasureInfo(inMeasureInfoSet2d, "PolygonArea2dMsr")
PyIPSDK.createMeasureInfo(inMeasureInfoSet2d, "Perimeter2dMsr")
PyIPSDK.createMeasureInfo(inMeasureInfoSet2d, "MeanMsr")
PyIPSDK.createMeasureInfo(inMeasureInfoSet2d, "InertiaOrientation2dMsr")
outMeasureSet = shapeanalysis.shapeAnalysis2d(inGreyImg, inShape2dColl, inMeasureInfoSet2d)
PyIPSDK.saveCsvMeasureFile(csvOutputPath, outMeasureSet)
outArea2dMsr = outMeasureSet.getMeasure("PolygonArea2dMsr")
outPerimeter2dMsr = outMeasureSet.getMeasure("Perimeter2dMsr")
outMeanMsr = outMeasureSet.getMeasure("MeanMsr")
outInertiaOrientation2dMsr = outMeasureSet.getMeasure("InertiaOrientation2dMsr")
outArea2dValues = PyIPSDK.extractReal64Results(outArea2dMsr)
outPerimeter2dValues = PyIPSDK.extractReal64Results(outPerimeter2dMsr)
outMeanValues = PyIPSDK.extractReal64Results(outMeanMsr)
outInertiaOrientation2dValues = PyIPSDK.extractReal64Results(outInertiaOrientation2dMsr)
print("First label area 2d measurement equal " + str(outArea2dValues[1]))
print("First label perimeter 2d measurement equal " + str(outPerimeter2dValues[1]))
print("First label mean intensity measurement equal " + str(outMeanValues[1]))
print("First label orientation (based on inertia) measurement equal " + str(outInertiaOrientation2dValues[1]))
C++ code Example
MeasureInfoSetPtr pMeasureInfoSet = MeasureInfoSet::create2dInstance(pGeometricCalibration);
const MeasureConstPtr& pArea2dOutMsr = pOutMeasureSet->getMeasure(
"PolygonArea2dMsr");
const std::vector<ipReal64>& area2dResults = extractValueResults<ipReal64>(pArea2dOutMsr);
const MeasureConstPtr& pPerimeter2dOutMsr = pOutMeasureSet->getMeasure(
"Perimeter2dMsr");
const std::vector<ipReal64>& perimeter2dResults = extractValueResults<ipReal64>(pPerimeter2dOutMsr);
const MeasureConstPtr& pMeanOutMsr = pOutMeasureSet->getMeasure(
"MeanMsr");
const std::vector<ipReal64>& meanResults = extractValueResults<ipReal64>(pMeanOutMsr);
const MeasureConstPtr& pInertiaOrientation2dOutMsr = pOutMeasureSet->getMeasure(
"InertiaOrientation2dMsr");
const std::vector<ipReal64>& InertiaOrientation2dResults = extractValueResults<ipReal64>(pInertiaOrientation2dOutMsr);
In this sample user add following measures to input collection of measures :
User also defines a geometric calibration used during measurements with the following settings :
- a 0.01 pixel size along x axis
- a 0.02 pixel size along y axis
- a base measurement unit equals to

Using a calibration will products the following effects on output (with comparison to Usual case):
- the appearance of measurement units on second line of results
- geometric measurements results are computed taking into account provided calibration
- intensity measurements are not impacted by geometric calibration
Please refers to Measure unit type and to Image calibration concepts in IPSDK for more informations on geometric calibration.
Working with measure parameters
In this section, we will demonstrate how to modify measure parameters to alter computation behavior of some measures.
We will use the following image and shape collection to illustrate this case :
Taking a look for example to documentation of measure Area2d, user can see that this measure can be parametered using an object of type ipsdk::imaproc::shape::analysis::HolesBasicPolicyMsrParams. This parameter allows in case of this measure to define whether computation should :
- ignore holes inside shapes, which means that area of shape are computed taking only exterior polygon into account.
- take care of holes which means that area of holes will not be taken into account when processing global shape area.
Here is a code sample in 2d case :
Python code Example
inShape2dColl, bResRead = PyIPSDK.readFromXmlFile(inputShape2dCollPath)
unitTestMonitor.checkEqual(bResRead.getResult(), True)
inMeasureInfoSet2d = PyIPSDK.createMeasureInfoSet2d()
PyIPSDK.createMeasureInfo(inMeasureInfoSet2d, "AreaMinusHoles", "PolygonArea2dMsr", shapeanalysis.createHolesBasicPolicyMsrParams(True))
PyIPSDK.createMeasureInfo(inMeasureInfoSet2d, "AreaWithHoles", "PolygonArea2dMsr", shapeanalysis.createHolesBasicPolicyMsrParams(False))
outMeasureSet = shapeanalysis.shapeAnalysis2d(inMeasureInfoSet2d, inShape2dColl)
PyIPSDK.saveCsvMeasureFile(csvOutputPath, outMeasureSet)
outAreaMinusHolesMsr = outMeasureSet.getMeasure("AreaMinusHoles")
outAreaWithHolesMsr = outMeasureSet.getMeasure("AreaWithHoles")
outAreaMinusHolesValues = PyIPSDK.extractReal64Results(outAreaMinusHolesMsr)
outAreaWithHolesValues = PyIPSDK.extractReal64Results(outAreaWithHolesMsr)
print("First label area minus holes measurement equal " + str(outAreaMinusHolesValues[1]))
print("First label area with holes measurement equal " + str(outAreaWithHolesValues[1]))
C++ code Example
const MeasureConstPtr& pAreaMinusHolesOutMsr = pOutMeasureSet->getMeasure(
"AreaMinusHoles");
const std::vector<ipReal64>& areaMinusHolesResults = extractValueResults<ipReal64>(pAreaMinusHolesOutMsr);
const MeasureConstPtr& pAreaWithHolesOutMsr = pOutMeasureSet->getMeasure(
"AreaWithHoles");
const std::vector<ipReal64>& areaWithHolesResults = extractValueResults<ipReal64>(pAreaWithHolesOutMsr);
In this example, we defined two measures from area 2d measure :
- a measure which doesn't take holes into account and which will be named "AreaMinusHoles"
- a measure which take care of holes and which will be named "AreaWithHoles"
Handling color measurements
Shape analysis framework allows to deal with input color image (see Color models).
We will use the following image and shape collection to illustrate this case :
In this example, we define two measures :
- a geometric measure Area2d for which results do not depend on a specific color plan
- an intensity measure Mean for which each color plan is associated to a dedicated result
Here is a code sample in 2d case :
Python code Example
inColorImg = PyIPSDK.loadTiffImageFile(inputColorImgPath)
inShape2dColl, bResRead = PyIPSDK.readFromXmlFile(inputShape2dCollPath)
unitTestMonitor.checkEqual(bResRead.getResult(), True)
inMeasureInfoSet2d = PyIPSDK.createMeasureInfoSet2d()
PyIPSDK.createMeasureInfo(inMeasureInfoSet2d, "PolygonArea2dMsr")
PyIPSDK.createMeasureInfo(inMeasureInfoSet2d, "MeanMsr")
outMeasureSet = shapeanalysis.shapeAnalysis2d(inColorImg, inShape2dColl, inMeasureInfoSet2d)
PyIPSDK.saveCsvMeasureFile(csvOutputPath, outMeasureSet)
outArea2dMsr = outMeasureSet.getMeasure("PolygonArea2dMsr")
outMeanMsr = outMeasureSet.getMeasure("MeanMsr")
outArea2dValues = PyIPSDK.extractReal64Results(outArea2dMsr)
outMeanValuesRed = PyIPSDK.extractReal64Results(outMeanMsr, 0)
outMeanValuesGreen = PyIPSDK.extractReal64Results(outMeanMsr, 1)
outMeanValuesBlue = PyIPSDK.extractReal64Results(outMeanMsr, 2)
print("First label area measurement equal " + str(outArea2dValues[1]))
print("First label mean intensity along red channel measurement equal " + str(outMeanValuesRed[1]))
print("First label mean intensity along green channel measurement equal " + str(outMeanValuesGreen[1]))
print("First label mean intensity along blue channel measurement equal " + str(outMeanValuesBlue[1]))
C++ code Example
const MeasureConstPtr& pArea2dOutMsr = pOutMeasureSet->getMeasure(
"PolygonArea2dMsr");
const std::vector<ipReal64>& area2dResults = extractValueResults<ipReal64>(pArea2dOutMsr);
const MeasureConstPtr& pMeanOutMsr = pOutMeasureSet->getMeasure(
"MeanMsr");
const std::vector<ipReal64>& meanResultsRed = extractValueResults<ipReal64>(pMeanOutMsr, 0);
const std::vector<ipReal64>& meanResultsGreen = extractValueResults<ipReal64>(pMeanOutMsr, 1);
const std::vector<ipReal64>& meanResultsBlue = extractValueResults<ipReal64>(pMeanOutMsr, 2);
The following results illustrate the fact that an intensity measure result is spanned according to input image color plans while a geometric measure is not.
Advanced usage of shape analysis framework
This section described advanced usage of shape analysis framework, please be sure to have a look to IPSDKIPLShapeAnalysisGettingStarted section before to read it.
Working with preprocessed images
Sometimes it can be interesting to work with preprocessed images rather that provided input image to compute measure results. This is for example the case if some gradient information are needed to make a separation between classes of shapes.
We will use the following image and shape collection to illustrate this case :
In this image we can distinguish three class of shapes (homogeneous, vertically tiled and horizontally tiled).
In this example, we will use measure configuration to measure a mean intensity over each shape on :
- input image
- x gradient of input image
- y gradient of input image
Here is a code sample in 2d case :
Python code Example
inGreyImg = PyIPSDK.loadTiffImageFile(inputGreyImgPath)
inShape2dColl, bResRead = PyIPSDK.readFromXmlFile(inputShape2dCollPath)
unitTestMonitor.checkEqual(bResRead.getResult(), True)
gradSigma = 1.5
inMeasureInfoSet2d = PyIPSDK.createMeasureInfoSet2d()
PyIPSDK.createMeasureInfo(inMeasureInfoSet2d, "MeanInputMsr", "MeanMsr")
PyIPSDK.createMeasureInfo(inMeasureInfoSet2d, "SumSquareGradXMsr", "SumSquareMsr", shapeanalysis.createXGaussGradMsrCfg2d(gradSigma))
PyIPSDK.createMeasureInfo(inMeasureInfoSet2d, "SumSquareGradYMsr", "SumSquareMsr", shapeanalysis.createYGaussGradMsrCfg2d(gradSigma))
outMeasureSet = shapeanalysis.shapeAnalysis2d(inGreyImg, inShape2dColl, inMeasureInfoSet2d)
PyIPSDK.saveCsvMeasureFile(csvOutputPath, outMeasureSet)
outMeanMsr = outMeasureSet.getMeasure("MeanInputMsr")
outSumSquareGradXMsr = outMeasureSet.getMeasure("SumSquareGradXMsr")
outSumSquareGradYMsr = outMeasureSet.getMeasure("SumSquareGradYMsr")
outMeanValues = PyIPSDK.extractReal64Results(outMeanMsr)
outSumSquareGradXValues = PyIPSDK.extractReal64Results(outSumSquareGradXMsr)
outSumSquareGradYValues = PyIPSDK.extractReal64Results(outSumSquareGradYMsr)
print("First label mean intensity measurement equal " + str(outMeanValues[1]))
print("First label x gradient sum of squares measurement equal " + str(outSumSquareGradXValues[1]))
print("First label y gradient sum of squares measurement equal " + str(outSumSquareGradYValues[1]))
C++ code Example
const MeasureConstPtr& pMeanInputOutMsr = pOutMeasureSet->getMeasure(
"MeanInputMsr");
const std::vector<ipReal64>& meanInputResults = extractValueResults<ipReal64>(pMeanInputOutMsr);
const MeasureConstPtr& pSumSquareGradXOutMsr = pOutMeasureSet->getMeasure(
"SumSquareGradXMsr");
const std::vector<ipReal64>& sumSquareGradXResults = extractValueResults<ipReal64>(pSumSquareGradXOutMsr);
const MeasureConstPtr& pSumSquareGradYOutMsr = pOutMeasureSet->getMeasure(
"SumSquareGradYMsr");
const std::vector<ipReal64>& sumSquareGradYResults = extractValueResults<ipReal64>(pSumSquareGradYOutMsr);
The following results illustrate the fact that shape analysis framework preprocessing capabilities can be used to bring additional informations on measured shapes. In this case, statistics on gradient values along x and y axis can be used to distinguish several shape classes :
Handling multiple inputs
In some cases it can be interesting to use multiple shape collections or multiple images as input of shape analysis processing.
This happens for example in case where we want use two images with different resolution representing the same shapes (with multi modal acquisitions for example).
We will use the following image and shape collection to illustrate this case :
These two images combined allow to distinguish between 4 classes of objects while first one only allows to distinguish 3 classes (see Working with preprocessed images)
The two input images have different resolution and will so be associated to different shape collections.
- Note
- Note that shape analysis framework impose a constant number of shapes into input shape collections
In this example, we will use measure configuration to measure a mean intensity over each shape on :
- first input image
- x gradient of first input image
- y gradient of first input image
- second input image
Here is a code sample in 2d case :
Python code Example
inGreyImg1 = PyIPSDK.loadTiffImageFile(inputGreyImgPath1)
inGreyImg2 = PyIPSDK.loadTiffImageFile(inputGreyImgPath2)
inShape2dColl1, bResRead1 = PyIPSDK.readFromXmlFile(inputShape2dCollPath1)
unitTestMonitor.checkEqual(bResRead1.getResult(), True)
inShape2dColl2, bResRead2 = PyIPSDK.readFromXmlFile(inputShape2dCollPath2)
unitTestMonitor.checkEqual(bResRead2.getResult(), True)
gradSigma = 1.5
inMeasureInfoSet2d = PyIPSDK.createMeasureInfoSet2d()
PyIPSDK.createMeasureInfo(inMeasureInfoSet2d, "MeanInput1Msr", "MeanMsr")
PyIPSDK.createMeasureInfo(inMeasureInfoSet2d, "SumSquareGradX1Msr", "SumSquareMsr", shapeanalysis.createXGaussGradMsrCfg2d(gradSigma))
PyIPSDK.createMeasureInfo(inMeasureInfoSet2d, "SumSquareGradY1Msr", "SumSquareMsr", shapeanalysis.createYGaussGradMsrCfg2d(gradSigma))
PyIPSDK.createMeasureInfo(inMeasureInfoSet2d, "MeanInput2Msr", "MeanMsr", PyIPSDK.createMeasureConfig(PyIPSDK.eMsrInputImageId.eMIII_Image2,
PyIPSDK.eMsrInputShapeCollId.eMISCI_ShapeColl2))
outMeasureSet = shapeanalysis.shapeAnalysis2d(inMeasureInfoSet2d,
inShape2dColl1,
InOptGreyMsrImg1=inGreyImg1,
InOptLabelsShape2=inShape2dColl2,
InOptGreyMsrImg2=inGreyImg2)
PyIPSDK.saveCsvMeasureFile(csvOutputPath, outMeasureSet)
outMean1Msr = outMeasureSet.getMeasure("MeanInput1Msr")
outSumSquareGradX1Msr = outMeasureSet.getMeasure("SumSquareGradX1Msr")
outSumSquareGradY1Msr = outMeasureSet.getMeasure("SumSquareGradY1Msr")
outMean2Msr = outMeasureSet.getMeasure("MeanInput2Msr")
outMean1Values = PyIPSDK.extractReal64Results(outMean1Msr)
outSumSquareGradX1Values = PyIPSDK.extractReal64Results(outSumSquareGradX1Msr)
outSumSquareGradY1Values = PyIPSDK.extractReal64Results(outSumSquareGradY1Msr)
outMean2Values = PyIPSDK.extractReal64Results(outMean2Msr)
print("First label mean intensity measurement in first image equal " + str(outMean1Values[1]))
print("First label x gradient sum of squares in first image measurement equal " + str(outSumSquareGradX1Values[1]))
print("First label y gradient sum of squares in first image measurement equal " + str(outSumSquareGradY1Values[1]))
print("First label mean intensity measurement in second image equal " + str(outMean2Values[1]))
C++ code Example
eMsrInputShapeCollId::eMISCI_ShapeColl2));
shapeAnalysis2dOptParams._pInOptGreyMsrImg1 = pInGreyImg2d1;
shapeAnalysis2dOptParams._pInOptLabelsShape2 = pShape2dColl2;
shapeAnalysis2dOptParams._pInOptGreyMsrImg2 = pInGreyImg2d2;
const MeasureConstPtr& pMeanInput1OutMsr = pOutMeasureSet->getMeasure(
"MeanInput1Msr");
const std::vector<ipReal64>& meanInput1Results = extractValueResults<ipReal64>(pMeanInput1OutMsr);
const MeasureConstPtr& pSumSquareGradX1OutMsr = pOutMeasureSet->getMeasure(
"SumSquareGradX1Msr");
const std::vector<ipReal64>& sumSquareGradX1Results = extractValueResults<ipReal64>(pSumSquareGradX1OutMsr);
const MeasureConstPtr& pSumSquareGradY1OutMsr = pOutMeasureSet->getMeasure(
"SumSquareGradY1Msr");
const std::vector<ipReal64>& sumSquareGradY1Results = extractValueResults<ipReal64>(pSumSquareGradY1OutMsr);
const MeasureConstPtr& pMeanInput2OutMsr = pOutMeasureSet->getMeasure(
"MeanInput2Msr");
const std::vector<ipReal64>& meanInput2Results = extractValueResults<ipReal64>(pMeanInput2OutMsr);
The following results illustrate the usage of multiple input images and shape collections to bring additional informations on measured shapes. In this case, statistics on gradient values along x and y axis mixed with information of second input image can be used to distinguish four shape classes :