How to remove CT bed/shadows in a CT image

I am working with 3D CT images and trying to remove the lines from the bed. I am reading my images with sitk and I know I do not need to convert to Hounsfield Units (I am not sure if thresholding is applicable for my purpose).
Original Image looks as follows:
image
I created a mask of the region I needed:

def remove_noise(image): 
    segmentation = morphology.dilation(image, np.ones((1, 1, 1)))
    labels, label_nb = ndimage.label(segmentation)
    
    label_count = np.bincount(labels.ravel().astype(int))#
    label_count[0] = 0

    mask = labels == label_count.argmax()
 
    mask = morphology.dilation(mask, np.ones((1, 1, 1)))
    mask = ndimage.morphology.binary_fill_holes(mask)
    mask = morphology.dilation(mask, np.ones((1, 1, 1)))
    masked_image = mask * image
    return masked_image

image

Mask is a binary array with 0 & 1 values only, but the original image has intensities ranging from -1024 to 3071 (I don’t want to normalize original image here). With masked_image = mask * original_image this is what I get (looks like intensities have changed):

image

But, the image I need is as follows (without the lines under the CT scan):
image

This might not be directly related to sitk, but I couldn’t find an answer anywhere for this and I was hoping maybe there is an easy way in sitk to remove artifacts. Any help would be appreciated.

It is a very good property of CT images that voxel values can have a physical meaning, so I would do all processing in Hounsfield units. When you write the processing result back to DICOM, the writer may use a different range for the stored voxel values than the original image but that should not matter, as long as the scales values in Hounsfield unit remain the same.

Note for table removal: After the erosion that removes a table, you need to not just dilate but also fill all the remaining holes in the mask. Any kind of convex hull algorithm should suffice for this. I’m not sure if ITK has any, but if not then you can use VTK for that step.

You can find a complete implementation of a fully automatic CT table removal algorithm in 3D Slicer’s Sandbox extension. It uses shrinkwrapping algorithm to fill all the holes in the mask. You can use the tool with a convenient GUI in Slicer or you can run it from a Python script in Slicer’s virtual Python environment.

2 Likes

You might be displaying masked_image with different view settings from the original image. Are you sure you use the same window and level (intensity range) for viewing?

Thank you so much for the detailed information. I will give Slicer a try. In the meantime, I filled the remaining holes in the mask and now the image looks as follows:

image

The background intensity of the original image is -1024 and in the resulting image its 0 (since the mask is binary). How can I change the background intensity so that it’s black?

I tried the following, but didn’t work:

mask_resampled = sitk.Resample(mask_image, orginal_image, defaultPixelValue=corners_median_intensity_original)

Hello @DushiFdo,

Assuming the foreground is defined by a binary mask image:

background_intensity = -1024
image*mask + sitk.InvertIntensity(mask, maximum=1)*background_intensity
1 Like

Hi @Zivy,

Thank you, but the foreground is not binary. It has intensities ranging from -1024 to 3071. Only the mask is binary (It actually has values ‘True’ and ‘False’. So I did output = np.where(mask==False, -1024, original) and now it works.

1 Like