Behavior of Mask Images in ITK

There are quite a number of filters and algorithms in ITK which use the concept of a mask image. They are frequently used to specify a boolean value of where an algorithm should be applied. There are several different ways a true value for a mask can be determined:

  1. (pixelValue != 0) or equivalently bool( pixelValue )
  • works with mask images defined by {0, 255} from outputs of thresholds
  • works with mask images defined by {0, 1}
  1. (pixelValue == maskValue), where maskValue is a parameter defined by the algorithm
  • works with multi-label images and selecting an single label

Additionally the default maskValue is not consistent:

  • maskValue defaults to 1
  • maskValue defaults to NumericTrais<>::max()

Here is a list of image filters which utilize a “MaskImage”, from SimpleITK and grepping in ITK:

  • ConnectedComponentImageFilter - uses MaskImageFilter, #2 with hidden MaskingValue=0
  • ScalarConnectedComponentImageFilter - uses MaskImageFilter, #2 with hidden MaskingValue=0
  • LabelMapMaskImageFilter - #2 with Label=1, keeps label pixel by default
  • MaskImageFilter - #2 with default MaskingValue=0, non-zero pixels are kept
  • MaskNegatedImageFilter - #2 with default MaskingValue=0, keeps only zero pixel
  • N4BiasFieldCorrectionImageFilter - #1, with option for #2 with MaskLabel
  • NormalizedCorrelationImageFilter - #1
  • HistogramThresholdImageFilter - from MaskedImageToHistogramFilter; #2 with MaskValue=Traits::max()
    • HuangThresholdImageFilter
    • IntermodesThresholdImageFilter
    • IsoDataThresholdImageFilter
    • KittlerIllingworthThresholdImageFilter
    • LiThresholdImageFilter.json
    • MaximumEntropyThresholdImageFilter
    • MomentsThresholdImageFilter
    • OtsuThresholdImageFilter
    • RenyiEntropyThresholdImageFilter
    • ShanbhagThresholdImageFilter
    • TriangleThresholdImageFilter
    • YenThresholdImageFilter

Additionally the Image Registration classes also use a mask.

  • ImageRegistrationMethodv4
    • ImageToImageMetricv4
  • ImageMaskSpatialObject

I will update this list with additional filters and algorithms. I am also going to update this post with a classification of the definition of the masks for the filters/algorithms.

It would be good to have consistency behavior of mask images in ITK. This would involve define the convention clearly in Doxygen and the Software guide, and updates some filters default behavior to be compliant with this definition.

I would like to propose that the default mask image behavior should work with mask images of 0’s and 1’s. This could be implemented by just utilizing the behavior of #1 or we could allow the behavior of #1 and #2 with maskValue defaulting to 1.

Thoughts and any support for this change?

Common behavior for masks in ITK, and a good behavior to standardize on, is

  • Outside mask: pixelValue == 0
  • Inside mask: pixelValue != 0

Masks are often stored as unsigned char with a value of 0 and 255. These values are the default output of the threshold filters and in the morphological filters. The output of these filters are often used as masks – they can then be used directly without further processing. A mask value of 255 makes quick visualization possible, because there is contrast in the image. This behavior also works for masks with values of 0 and 1.

4 Likes

@matt.mccormick

I have updated the initial post with information describing the filters behavior. A table might be more clear, but I think this works for now.

Your post is a clear summary which matches my expectations. It also matches the default behavior of the MaskImageFilter where masking_value default to 0:

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

From this examination of code only the NormalizedCorrelationImageFilter directly implements the logic expected.

The odd ball for behavior is the HistogramThresholdImageFilter. Perhaps this class should be updated to be more conforming?

Also, I’d like to point out the variety of names used for the mask value: “Label”, “MaskingValue”, “MaskLabel”, and “MaskValue”. These are not very consistent!

2 Likes

We should probably retain the old behavior with LEGACY_ENABLED (or whatever is the flag).

Now is an excellent time to rectify that injustice :smile:

Anyone working on making this consistent?

If not just because a decision has not been made, do we have any preference about the naming? What do you think is the most appropriate? Does it depend on the filter?

The problem is that the behavior of these filters are not consistent. Does the set label define where the mask is true or false?

The behavior of the MaskImageFilter is a little convoluted. The default behavior is that the pixels under the “true” valued mask are preserved. But that conceptual model does not hold where you set the MaskValue.

I honestly don’t know what to do with out breaking many of the filters compatibility.

Opened an issue to keep track of this:
https://insightsoftwareconsortium.atlassian.net/browse/ITK-3639

1 Like