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:
(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}
(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.
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.
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:
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!
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.