ANTsX / ANTs

Advanced Normalization Tools (ANTs)
Apache License 2.0
1.21k stars 381 forks source link

ENH: Update LabelGeometryMeasures to not use deprecated filter #1737

Closed cookpa closed 6 months ago

cookpa commented 6 months ago

Not a fix but part of the way to fixing #1733

I replaced the filter and added some new features including computing mean and median intensities of gray images.

Some attributes don't have an exact analog. I changed some headers to be general over 2D / 3D

New columns are

Label NumberOfVoxels PhysicalSize - area in 2D (mm^2) or volume in 3D (mm^3) Perimeter - perimeter in 2D or surface area in 3D Elongation - Note this differs from old implementation Roundness - new Flatness - new Centroid_x - Note this differs from old implementation Centroid_y Centroid_z BoundingBoxLower_x - reordered (open to changing this) BoundingBoxLower_y BoundingBoxLower_z BoundingBoxUpper_x BoundingBoxUpper_y BoundingBoxUpper_z MeanIntensity - Grayscale stats if intensity image provided SigmaIntensity MedianIntensity MinIntensity MaxIntensity

Eccentricity, Orientation have been removed as they don't exist in the new filter. Also, I didn't add the "WeightedCentroid" for gray images, I don't think that exists in LabelStatisticsImageFilter.

To check the centroid, I compared to SimpleITK:

#!/usr/bin/env python

import SimpleITK as sitk
import sys

def main():
    if len(sys.argv) < 2:
        print("Usage:", sys.argv[0], "<InputImage>")
        return

    # Read the image file
    image_path = sys.argv[1]
    image = sitk.ReadImage(image_path)

    # Convert to a binary image, assuming the image might not be perfectly binary
    binary_image = image > 0

    # Calculate the centroid using the LabelShapeStatisticsImageFilter
    label_shape_filter = sitk.LabelShapeStatisticsImageFilter()
    label_shape_filter.Execute(binary_image)

    # Assuming the label of interest is '1' (common for binary images)
    centroid = label_shape_filter.GetCentroid(1)
    print(f"Centroid of the binary object: {centroid}")

if __name__ == "__main__":
    main()

which agrees with my definition but note that it differs from the old filter and also what c3d reports (I am not sure what filter it uses)

ntustison commented 6 months ago

Awesome. Thanks @cookpa

cookpa commented 6 months ago

Can't convert to draft from my phone but don't merge yet I will make a couple of changes to maintain backwards compatibility in column names as requested by @stnava

cookpa commented 6 months ago

In the latest commit, I've added "Eccentricity" and "Axes Length" back, both derived from the label principal moments.

Axes length agrees with the old definition, which suggests that the moments are the same. But eccentricity differs.

cookpa commented 6 months ago

More discussion of the numbers here

https://github.com/InsightSoftwareConsortium/ITK/pull/4624#issuecomment-2094818795