Connected components in python

Hello all,

I am very new to SimpleITK. I am trying to get all the connected components from a 3D binary image (including the pixel locations of the various components) with multiple masks. The 3D binary image is of “Image” type and was itself obtained after thresholding. I tried using ConnectedComponentImageFilter and BinaryImageToLabelMapFilter, but couldn’t find methods that would give the actual locations of the pixels belonging to the components. How would I do this?

Thanks

1 Like

Hello @Krishna_Nanda,

Welcome to SimpleITK!

Not exactly sure what you want to do but here goes:

  1. You have a binary volume with multiple objects (connected regions with value 1).
  2. Use ConnectedComponentImageFilter to mark each region/object with a unique label.
  3. Use LabelShapeStatisticsImageFilter to obtain information on the shape of each object, then use the method GetCentroid which will give you the 3D “location” of each object based on the label you provide (you got these in previous step).

If you need the 3D location of a specific pixel/voxel in an image you can use the Image’s TransformIndexToPhysicalPoint.

As you are new to SimpleITK I recommend that your read about the Fundamental Concepts and the Common Conventions used by the toolkit. Also, possibly take a look at the toolkit’s Jupyter Notebook repository which illustrates these and shows various usage cases.

2 Likes

hello,
I want to get centroid of all the roi including all labels, getcentroid of simpleitk works for specific labels, but to find the centroid of summing all labels?

Hello @Snehal_Rajput,

Please see code below:

import SimpleITK as sitk

# Our multi-label image
multi_label_image = sitk.Image([3]*3, sitk.sitkUInt8)
multi_label_image[0,0,0] = 1
multi_label_image[0,1,0] = 2
multi_label_image[0,0,1] = 2
multi_label_image[0,1,1] = 1
multi_label_image[0,2,1] = 3
multi_label_image[0,0,2] = 3

label_shape_filter = sitk.LabelShapeStatisticsImageFilter()

# Get the centroid per label
print('Multiple labels and their centroids:')
label_shape_filter.Execute(multi_label_image)
for label in range(1, label_shape_filter.GetNumberOfLabels()+1):
    print(f'label{label}: centroid {label_shape_filter.GetCentroid(label)}')

# Get the centroid treating all labels as a single entity, assuming
# zero is the background label
background_label = 0
print('Multiple labels treated as a single label and its centroid:')
label_shape_filter.Execute(multi_label_image!=background_label)
for label in range(1, label_shape_filter.GetNumberOfLabels()+1):
    print(f'label{label}: centroid {label_shape_filter.GetCentroid(label)}')

3 Likes

thanks for the code.
imageName = flair_path

        maskName = seg_path

        image = sitk.ReadImage(imageName)

        stats = sitk.LabelShapeStatisticsImageFilter()

        mask = mask = sitk.ReadImage(maskName)

        stats.Execute(mask)

        try:

            centroid = stats.GetCentroid(1)

            

            z.update({'cent_ncr_x':centroid[0],'cent_ncr_y':centroid[1],'cent_ncr_z':centroid[2]})

            centroid_ed= stats.GetCentroid(2)

            z.update({'cent_ed_x':centroid_ed[0],'cent_ed_y':centroid_ed[1],'cent_ed_z':centroid_ed[2]})

            centroid_at= stats.GetCentroid(4)

            z.update({'cent_at_x':centroid_at[0],'cent_at_y':centroid_at[1],'cent_at_z':centroid_at[2]})

            background_label = 0
            print('Multiple labels treated as a single label and its centroid:')
            
            stats.Execute(mask!=background_label)
            for label in range(1, stats.GetNumberOfLabels()+1):
                centroidofwb=stats.GetCentroid(label)
                print("centroidofwb",centroidofwb)
                print(f'label{label}: centroid {stats.GetCentroid(label)}')
                z.update({'cent_wb_x':centroidofwb[0],'cent_wb_y':centroidofwb[1],'cent_wb_z':centroidofwb[2]})

there are three labels in 3d image, 1,2 and 4 now to get centroid of roi including 1,2,4 i have used your code. is it fine?

Hello @Snehal_Rajput,

Question isn’t clear to me, as it is up to you to confirm that the code does what you want in a correct fashion. The code I provided illustrated how to (1) Get the centroid on a per label basis. (2) convert the per label mask to a single label mask and get the centroid of that.

If that is what you want your code looks ok, though there are some strange lines:
mask = mask = sitk.ReadImage(maskName)

Again to clarify, when the mask/segmentation has multiple labels and you want the statistics for the object that consists of all labels we simply create a binary mask that represents it, mask!=background_label. If you want to combine a specific subset of labels into a single label, you can use the ChangeLabelImageFilter to change the subset of labels into a single label and then compute the statistics on that.

2 Likes

yes it worked, thanks for decoding code for me, i wanted to combine all labels and get the centroid of it. Please resolve my doubt that while calculating centroid for particular label ,do the function getcentroid() consider the dimension of particular label or whole image?

Hello @Snehal_Rajput,

The centroid is in physical coordinates, in the same coordinate system in which the image is defined.

To gain further insight, please go over the fundamental concepts page which discusses the concept of images as spatial objects in ITK/SimpleITK.

1 Like

hello zivy,
can we find centroid using numpy value? my image is 3d brain image and all the non brain area set to 0, I got brain volume using size_brain=np.sum(np.nonzero(img)) , now i want to get centroid of brain area. so i have to get array from image or can assign mask as np.sum(np.nonzero(img))?

can we create binary mask here also ? whole brain pixel vs background pixels which is set to 0?
background_label = 0

            print('whole brain area treated as a single label and its centroid:')

            

            stats.Execute(mask>background_label)

            for label in range(1, stats.GetNumberOfLabels()+1):

                centroidofwb=stats.GetCentroid(label)

                print("centroidofwb",centroidofwb)

Hello @Snehal_Rajput,

You should not use numpy for these types of computations. Medical images are most often non-isotropic and they are in a specific location in physical space. When using numpy all of this information is lost as it treats the data as an isotropic array with the origin at [0,0,0].

hello @zivy , please tell me how sitk calculates centroid of each label is calculated across x, y, z axis?

Hello @Snehal_Rajput,

The centroid is just summing the coordinates of the label voxels divided by the number of voxels, \left(\frac{\Sigma x_i}{n}, \frac{\Sigma y_i}{n},\frac{\Sigma z_i}{n}\right). This is in physical space.

1 Like