Using an image as a mask

Hi!
I want to retrieve the original intensities of image but only if the voxel is 1 in the foreground mask

My code looks like this:

# compute foreground image
# -------------------------------------
bg_data = sitk.GetArrayFromImage(background)
fg_data = np.zeros(bg_data.shape)
fg_data[np.where(bg_data == 0)] = 1  # opposite to background
foreground = sitk.GetImageFromArray(fg_data)

# apply mask
#---------------------------------------
sitk.Mask(image, foreground, maskingValue=1, outsideValue=0)

I am getting this error:

RuntimeError: Exception thrown in SimpleITK Mask: Users/runner/work/1/sitk/Code/Common/include/sitkDualMemberFunctionFactory.hxx:178:sitk::ERROR: Pixel type: 16-bit signed integer is not supported in 3D byN3itk6simple15MaskImageFilterE

What should I do?

Hello @Diego_C ,

The code is a bit complicated, not sure what you are trying to achieve with the back and forth via numpy. Below is a simple example which creates a binary mask via thresholding and zeros out all the voxels that are in the background.

import SimpleITK as sitk

image = sitk.ReadImage('training_001_ct.mha')
foreground_mask = image>0
foreground_image = image*sitk.Cast(foreground_mask, image.GetPixelID())
1 Like

When you get this type of error you need to inspect the image inputs to the filter. Look at the image dimensions, pixel types, meta-data etc.

The Mask filter support most sensible combinations for it’s image arguments:

In [1]: import SimpleITK as sitk

In [2]: img = sitk.Image([16]*3,sitk.sitkFloat32)

In [3]: mask = sitk.Image([16]*3, sitk.sitkInt16)

In [4]: sitk.Mask(img, mask)
Out[4]: <SimpleITK.SimpleITK.Image; proxy of <Swig Object of type 'std::vector< itk::simple::Image >::value_type *' at 0x7fab28ba8d50> >

Unlike when the multiplication operator which requires the images to be the same type ( thus why the Cast was needed.

For you case I suspect that there is a mismatch in number of dimensions in the images after converting to and fro NumPy. Unfortunately, since your code is not self contained I can not reproduce it. If you initialized the background and image with something like background = sitk.Image([32]*2, sitk.sitkFloat32) the could would be self contained.

Hi @blowekamp

No mismatch in number of dimensions between input and foreground (filter inputs).

I managed to fix the problem like this:

sitk.Mask(image, sitk.Cast(foreground,sitk.sitkInt8), maskingValue=1, outsideValue=0)

So it looks like I needed to specify the pixel type of the numpy array I was using to build the foreground mask.

Masking Behaviour

I am a bit confused though about the mask masking in or masking out behaviour?

My foreground mask is 1 for the head and 0 for the background, so I was expecting as a result of using the masking filter to see only the “head” voxels using:

  sitk.Mask(image, sitk.Cast(foreground,sitk.sitkInt8), maskingValue=1, outsideValue=0)

but this is what I obtained:

In contrast, if I change the instruction to:

sitk.Mask(image, sitk.Cast(foreground,sitk.sitkInt8), maskingValue=0, outsideValue=0)

Then I obtain the expected result:

So I thought that the maskingValue parameter referred to the intensity value in the mask that the filter would use to select voxels in from the original input. But I am seeing this is not the case.

What is maskingValue?

Thanks,

Diego

1 Like

From the sitk::MaskImageFilter doxygen page:

if pixel_from_mask_image != masking_value
 pixel_output_image = pixel_input_image
else
 pixel_output_image = outside_value

The current brief documentation for the filter is: “Mask an image with a mask.” Suggestions for a brief line to better describe this behavior are welcome.

This is the behavior I expect, but not one I get.
label_np = np.zeros([5, 5, 5])
label_np[4, 0, 0] = 120
image = sitk.GetImageFromArray(label_np)

    masked_image = sitk.Mask(image, image >0, maskingValue=1)

    get_max(masked_image)
    >> 0

I would expect this to be 1 with the foreground mask being set to the maskingValue. Am I misreading, and what is the canonical way to achieve that? Thanks.

The logic for the MaskImageFilter is:

if pixel_from_mask_image != masking_value:
 pixel_output_image = pixel_input_image
else:
 pixel_output_image = outside_value

So the default maskValue of 0 should work. The default behavior is for the non-zero locations to preserve or keep those values in the input image.

I guess the definition is what it is… which is different from the textbook definition of image masking

Newly added in SimpleITK is support for images as masked with the setitem method. So you find it more explicit to do something like:
image[image<=0] = 0

I am not clear what your initial expectations were, but the above syntax should make it more clean what you are trying to do.