Skip to content

DOC: Add See Also entries for alternatives to LabelGeometryImageFilter#4624

Merged
dzenanz merged 1 commit intoInsightSoftwareConsortium:masterfrom
dzenanz:labelGeometryFilterSA
Apr 29, 2024
Merged

DOC: Add See Also entries for alternatives to LabelGeometryImageFilter#4624
dzenanz merged 1 commit intoInsightSoftwareConsortium:masterfrom
dzenanz:labelGeometryFilterSA

Conversation

@dzenanz
Copy link
Member

@dzenanz dzenanz commented Apr 29, 2024

This filter is buggy, and sometimes produces wrong results. Follow-up to: #4530.

PR Checklist

  • No API changes were made (or the changes have been approved)
  • No major design changes were made (or the changes have been approved)
  • Updated API documentation (or API not changed)

@dzenanz dzenanz requested a review from blowekamp April 29, 2024 19:13
@github-actions github-actions bot added the type:Documentation Documentation improvement or change label Apr 29, 2024
This filter is buggy, and sometimes produces wrong results. Follow-up to:
InsightSoftwareConsortium#4530
@dzenanz dzenanz force-pushed the labelGeometryFilterSA branch from 5ac8718 to f1015cf Compare April 29, 2024 19:14
@dzenanz dzenanz changed the title DOC: Add "see also" entries for alternative filters DOC: Add See Also entries for alternatives to LabelGeometryImageFilter Apr 29, 2024
@dzenanz
Copy link
Member Author

dzenanz commented Apr 29, 2024

Today I realized its IntegratedIntensity is buggy too. Should we deprecate this filter?

@dzenanz dzenanz merged commit f408b77 into InsightSoftwareConsortium:master Apr 29, 2024
@dzenanz dzenanz deleted the labelGeometryFilterSA branch April 29, 2024 21:49
@blowekamp
Copy link
Member

Today I realized its IntegratedIntensity is buggy too. Should we deprecate this filter?

Yes, I have been a proponent of that for nearly 10 years.

@dzenanz
Copy link
Member Author

dzenanz commented Apr 30, 2024

@blowekamp do you want to propose a PR which does that? Then we can decide when to do the deprecation. Most likely right after release? And should we go future legacy remove route? Or direct deprecation?

@blowekamp
Copy link
Member

We could add the depreciation warning now, and move it to Compatibility/Deprecated for ITKv5.

@cookpa
Copy link
Contributor

cookpa commented May 3, 2024

Hi, Thanks for the heads up on the bugginess of this filter.

I've been working on replacing LabelGeometryImageFilter in ANTs tools. The suggested replacements work well for most functions, but I have not been able to find an equivalent for the "Eccentricity" and the "WeightedCentroid". Are there options for this in any other ITK filters?

@dzenanz
Copy link
Member Author

dzenanz commented May 3, 2024

Perhaps Roundness from ShapeLabelObject, which get produced by LabelImageToShapeLabelMapFilter? I don't know of a replacement for WeightedCentroid.

@blowekamp
Copy link
Member

Hi, Thanks for the heads up on the bugginess of this filter.

I've been working on replacing LabelGeometryImageFilter in ANTs tools. The suggested replacements work well for most functions, but I have not been able to find an equivalent for the "Eccentricity" and the "WeightedCentroid". Are there options for this in any other ITK filters?

The other filters to mention is the LabelImageToStatisticsLabelMapFilter and relates BinaryToStatisticLabelMapFilter and StatisticsLabelMapFilter. The take a label image and an intensity image to compute the attributes here: https://itk.org/Doxygen/html/classitk_1_1StatisticsLabelObject.html

@cookpa
Copy link
Contributor

cookpa commented May 3, 2024

Thanks @dzenanz and @blowekamp. I switched the shape measures over to LabelImageToStatisticsLabelMapFilter, and the the grayscale measures to LabelStatisticsImageFilter.

@blowekamp
Copy link
Member

Thanks @dzenanz and @blowekamp. I switched the shape measures over to LabelImageToStatisticsLabelMapFilter, and the the grayscale measures to LabelStatisticsImageFilter.

If you could post specifics of the metrics migration, it could help writing a migration guide.

@cookpa
Copy link
Contributor

cookpa commented May 3, 2024

Specifically, we were calling these LabelGeometryImageFilter functions to get shape statistics:

GetAxesLength
GetBoundingBox
GetCentroid
GetEccentricity
GetElongation
GetOrientation

LabelImageToShapeLabelMapFilter provides a LabelMap which in turn has ShapeLabelObject objects for each unique label, which provide

GetBoundingBox
GetCentroid
GetElongation

Of these, only BoundingBox was the same in my tests. GetCentroid differs and appears to provide the centroid in physical space. GetElongation returns different numbers, I've not verified which is correct.

There's no GetEccentricity, but there is GetRoundness, which appears to be a more general way of measuring something inversely proportional to eccentricity.

AFAIK, there's not a replacement for GetAxesLength or GetOrientation.

For grayscale statistics, LabelGeometryMeasures has

GetIntegratedIntensity
GetWeightedCentroid

I replaced GetIntegratedIntensity with GetSum from the LabelStatisticsImageFilter, which appears to be the same. I don't have a replacement for GetWeightedCentroid.

@cookpa
Copy link
Contributor

cookpa commented May 5, 2024

Update, I was able to use ShapeLabelObject::GetPrincipalMoments() to reproduce axes length as

axesLengths[idx] = 4.0 * std::sqrt(principalMoments[idx]);

giving the same result as LabelGeometryImageFilter for unit voxels (EDIT: LabelGeometryImageFilter does not scale axes length with the spacing, so the same label will show different axes lengths if the voxel spacing changes).

The moments can also be used to define eccentricity and elongation, and in 2D, orientation. From LabelGeometryImageFilter

// The following three features are currently only meaningful in 2D.
mapIt->second.m_Eccentricity =
std::sqrt((eigenvalues[ImageDimension - 1] - eigenvalues[0]) / eigenvalues[ImageDimension - 1]);
mapIt->second.m_Elongation = axesLength[ImageDimension - 1] / axesLength[0];
RealType orientation =
std::atan2(eig.get_eigenvector(ImageDimension - 1)[1], eig.get_eigenvector(ImageDimension - 1)[0]);
// Change the orientation from being between -pi to pi to being from 0 to pi.
// We can add pi because the orientation of the major axis is symmetric about the origin.
mapIt->second.m_Orientation = orientation < 0.0 ? orientation + itk::Math::pi : orientation;

Eccentricity is defined as

mapIt->second.m_Eccentricity =
      std::sqrt((eigenvalues[ImageDimension - 1] - eigenvalues[0]) / eigenvalues[ImageDimension - 1]);

which simplifies to sqrt( 1 - V_0 / V_1). This differs from the ellipsoid formula sqrt(1 - {V_0}^2 / {V_1}^2).

In 3D there is no single definition but I decided to use the ratio of the largest to smallest eigenvalues, ie eccentricity = sqrt(1 - {V_0}^2 / {V_2}^2).

For elongation, LabelGeometryImageFilter uses

mapIt->second.m_Elongation = axesLength[ImageDimension - 1] / axesLength[0];

Which is (4 * sqrt(V_1)) / (4 * sqrt(V_0)) = sqrt(V_1 / V_0).

itkShapeLabelMapFilter uses

if (Math::NotAlmostEquals(principalMoments[ImageDimension - 2], typename VectorType::ValueType{}))
{
const double elongationRatio = principalMoments[ImageDimension - 1] / principalMoments[ImageDimension - 2];
elongation = 0.0;
if (elongationRatio > 0.0)
{
elongation = std::sqrt(elongationRatio);
}
}
}

which is the same in 2D but in 3D, elongation becomes sqrt(V_2 / V_1) rather than sqrt(V_2 / V_0). This is arguably better for some applications, for example looking at cortical regions we expect V_2 >= V_1 >> V_0, and might be more interested in the elongation of the first and second moments. So I guess the difference is just an implementation choice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type:Documentation Documentation improvement or change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants