Proposals:Consistent usage of label and binary images: Difference between revisions
No edit summary |
|||
Line 2: | Line 2: | ||
Currently, a label image or a binary image can be different things in the toolkit. This proposal give some clear and consistant definition of a label and a binary image, and a way to use them without breaking (immediately) the backward compatibility. | Currently, a label image or a binary image can be different things in the toolkit. This proposal give some clear and consistant definition of a label and a binary image, and a way to use them without breaking (immediately) the backward compatibility. | ||
==Background== | ==Background== | ||
Label images and binary images are not consistently defined in the toolkit currently: the definition is dependent of | Label images and binary images are not consistently defined in the toolkit currently: the definition is dependent of the class which manipulate the image. For example, ConnectedComponentImageFilter consider that binary objects are | ||
connected set of non-zero pixels, while BinaryDilateImageFilter use a value setted by the user to manipulate the binary object. Also, while we can consider as label any value allowed by a type, some filters may fail if those values are negative. | connected set of non-zero pixels, while BinaryDilateImageFilter use a value setted by the user to manipulate the binary object. Also, while we can consider as label any value allowed by a type, some filters may fail if those values are negative. | ||
Most of the time, what is a binary image or a label image is not defined in the docstring of the class, and the user has to test, or to read the code of the class to know how those notions are used in a particular class. | |||
It clearly increase the complexity of the toolkit, and sometime makes the behavior of such ar such class difficult to understand. | It clearly increase the complexity of the toolkit, and sometime makes the behavior of such ar such class difficult to understand. | ||
Revision as of 12:01, 12 October 2006
Summary
Currently, a label image or a binary image can be different things in the toolkit. This proposal give some clear and consistant definition of a label and a binary image, and a way to use them without breaking (immediately) the backward compatibility.
Background
Label images and binary images are not consistently defined in the toolkit currently: the definition is dependent of the class which manipulate the image. For example, ConnectedComponentImageFilter consider that binary objects are connected set of non-zero pixels, while BinaryDilateImageFilter use a value setted by the user to manipulate the binary object. Also, while we can consider as label any value allowed by a type, some filters may fail if those values are negative. Most of the time, what is a binary image or a label image is not defined in the docstring of the class, and the user has to test, or to read the code of the class to know how those notions are used in a particular class. It clearly increase the complexity of the toolkit, and sometime makes the behavior of such ar such class difficult to understand.
A binary image is an image containing a background and a foreground. It is perfectly possible to represent it with a bool as pixel type, however, most of the time, we will prefer an integral type such as unsigned char. Unsigned char type has an important advantage over the bool type: it allows to have several objects with different pixel values, or labels.
The notion of binary image and label image are closely related, but are different. It must be clearly defined the wich one is used in a class.
Definitions
Both binary and label images have integral pixel type.
Binary image
A binary image is defined by a single foreground value, y default, the maximum possible value of the pixel type . The other values found in the image are in the background of the image. With that definition, the user can easily manipulate each object in the image individually. Example of usage: dilate only one object in a labeled image. Example: a mask is a binary image, not a label image.
Label image
A label image is defined by a single background value, by default, the minimum pixel value of the type, or even no background. The other values found in the images are the labels. With that definition, the user can easily manipulate all the objects of an image. Example of usage: give some markers to perform a watershed (a background is needed). Other example: give a label to all the pixels of the images, with a classification algorithm for example (a background is not needed).
Naming convention
A filter which manipulate binary images should be prefixed with Binary if it manipulates binary images, or with Label if it manipulates label images.
For example, a filter wich remove (move to background) all the objects smaller than a given size in a binary image (a classical binary area opening) should be called BinaryAreaOpeningImageFilter; a filter which remove all the objects smaller than a given size in a label image should be called LabelAreaOpeningImageFilter. Note that the 2 filters would not perform the same operations: BinaryAreaOpeningImageFilter first has to found the connected components, and then perform the area opening, while LabelAreaOpeningImageFilter would consider each pixel with the same value as a single object, and so wouldn't have to search the connected components. Also, while a label image contains only a single background value, a binary image can have several background value. It imply that the background value to use in the binary case can be given by the user.
The grayscale equivalent shouldn't be prefixed by grayscale, to shorten the name. An area opening working on grayscale images should be called AreaOpeningImageFilter.
Preserving background values in binary images
As much as possible, the classes which are transforming the binary images should try to keep the background value unchanged. A binary dilation for example, should only dilate the foreground object, and keep the background values unaffected. It is sometime not possible to keep the background values unchanged, for example, when the size of the image is modified, or when the results depend of 2 binary images. In that case, the background value should be specified by the user.
Boolean operations
Boolean operations are usable only with binary images, not the label ones.
Currently in the toolkit, the boolean operations are the ones defined in c++, and so are not well suited to be used with binary images as defined above.
itk::AndImageFilter itk::OrImageFilter itk::XorImageFilter itk::NotImageFilter
Those filters can be useful as they are, so some new filters should be implemented. The Binary prefix is consistent with the naming convention above.
itk::BinaryAndImageFilter itk::BinaryOrImageFilter itk::BinaryXorImageFilter itk::BinaryNotImageFilter
None of those filters should be able to keep the background values.
Converting label image to binary image, and binary image to label image
The convertion from label image to binary image is very simple: a binary threshold which keep only the background value outside, and all the other values inside. If the label image doesn't use backbround value, the convertion is not (immediately) possible. To make things even simpler, a LabelToBinaryImageFilter class can be created.
The convertion from binary to label image is more difficult. A way to do that is to use the ConnectedComponentImageFilter to give a label to each connected component of the binary image.
Changing foreground value in a binary image and the background value in a label image
It should be very easy to change the foreground value in a binary image, or the background value in a label image with the ChangeLabelImageFilter.
Backward compatibility
While using the definitions above should be easy, it should be tricky to keep the backward compatibility.
Breaking the backward compatibility
This is the most simple way to go. With a major release of ITK, we change the behavior of the filters. It is consitent with the common usage of versions in open source, but may not be acceptable for ITK.
A soft transition
Instead of breaking immediately the backward compatibility, we can keep the current behavior as the default one, with a deprecation warning to incite the user to use the new standardized one. After some releases, the default behavior can be changed to the new one, and the old one still kept some time before being definitively removed to clean the code.
The behavior should be selectable on all filters, with a default value which can be set by the user. The default value can be stored in a static field of a class, for example m_Standardized in LabelAndBinaryBehavior. The main problem here is the amount of code required to have the 2 behaviors, and to test the 2 behaviors.
The problem of the naming convention is a lot much easier: the class can be renamed, and a subclass can be created with the old name to keep the backward compatibility. The class with the old name should produce a deprecation warnning when used.
Concerned classes
Algorithm
Here is a list of filter which are not using the definitions above. This list may not be complete.
itk::ApproximateSignedDistanceMapImageFilter itk::DanielssonDistanceMapImageFilter itk::SignedDanielssonDistanceMapImageFilter itk::SignedMaurerDistanceMapImageFilter itk::ConnectedComponentImageFilter itk::AntiAliasBinaryImageFilter itk::MaskImageFilter itk::MaskNegatedImageFilter itk::ConnectedComponentImageFilter
Naming
The filters with a useless "Grayscale" prefix in there name.
itk::GrayscaleDilateImageFilter itk::GrayscaleGeodesicDilateImageFilter itk::GrayscaleMorphologicalClosingImageFilter itk::GrayscaleConnectedOpeningImageFilter itk::GrayscaleFillholeImageFilter itk::GrayscaleConnectedClosingImageFilter itk::GrayscaleGeodesicErodeImageFilter itk::GrayscaleGrindPeakImageFilter itk::GrayscaleFunctionErodeImageFilter itk::GrayscaleErodeImageFilter itk::GrayscaleMorphologicalOpeningImageFilter itk::GrayscaleFunctionDilateImageFilter