when reading DICOM images with ITK, rescaleIntercept / Slope is forcefully applied. MetaImage provides similar tags (ElementToIntensityFunctionSlope/Offset), but currently, they are ignored and they don’t even appear in the MetaDataDictionary of the metaImageIO - so they are lost while reading.
Any comments? Is this intended?
@Stephen_Aylward might have some insight into MetaIO design decisions and defaults.
That info should be included in ITK’s MetaDataDictionary for the image. It should be stored using the same key fields as are used by DICOM images, so that they can be applied consistently within a program regardless of the image being stored as dicom or metaIO.
I’m a bit surprised that the DICOM reader “forcefully applies” the slope and intercept values. That should be at the application’s discretion, imo.
If these values were added to the MetaDataDictionary, would that resolve this problem sufficiently for you?
DICOM reader applies the slope and intercept values by default. That is normal and expected behavior. If you want to explicitly handle it, take a look at this code fragment:
thanks for the info so far. I understand that a .mhd image can include custom tags that are read into ITK’s MetaDataDictionary for the ImageIOBase and then later handled by the application, perfectly fine (even though the current code for metaIO reading seems to ignore all user tags that are written below the ElementDataFile line in the mhd. So that workaround would work in case…
- rescaleIntercept/Slope are given as custom metadata attributes with e.g. the key “rescaleIntercept”/“rescaleSlope”, or with their corresponding DICOM key
- If these tags are listed above the ElementDataFile line in the .mhd (again, they seem to be ignored otherwise) - I can dig out more information if needed.
I was more interested in the two dedicated mod-tags ElementToIntensityFunctionSlope/Offset, which are seem to provide the same functionality, but which are listed in metaIO as dedicated tags for the image type. They are not forwarded as custom tags to ITK, so they are lost when reading an image with ITK, even though according to metaIO’s documentation, they are implemented for the exact same reason.
And, again, in case of DICOM, rescaleIntercept are applied while reading bulk data (voxels), see itkGDCMImageIO.cxx, line 327 ff., so this is not handled by the application but by ITK.
With this information, is there any further advice/comments on these three aspects (order of tags in the .mhd file / ElementToIntensityFunctionSlope / different behaviour for DICOM)?
By design, tags below ElementDataFile are ignored. Certain tags in MetaIO are “terminating” tags - they indicate the end of an object definition. In this way, MetaIO can actually support multiple objects being defined within the same file. If the reader is used correctly (see MetaSpatialObjectReader) then any tags after a terminating tag are applied to the next object in the file. ITK’s MetaIO image reader are only setup to read a single image from a MetaIO file, so yes, tags after the first occurrence of ElementDataFile are ignored.
It is probably best to apply the intercept and scale from DICOM, as long as they can be inverted when writing to disk (and handled well, in general - e.g., pixel type in memory might need to change from the pixel type used in the file). I believe that GDCM+ITK handles this correctly. My thought was not to apply it with MetaIO because MetaIO’s philosophy is to keep things simple by operating as a human editable tagged-file-format data container, rather than as a comprehensive image solution. So, it doesn’t provide many conversions (i.e., it only provides conversions for byte ordering). The rest is up to the application. In this case, perhaps ITK should apply the slope and intercept after MetaIO reads the image? Until then, I’ll look into making certain those tags are read into the MetaDataDictionary.
Hopefully this isn’t the code that you meant to show me. The tag 0028|1050 and 0028|1051 are for mapping recorded values to displayed intensities. The function of window and level is quite different than tags 0028|1052 and 0028|1053 that map disk-stored values to recorded values.
1052 and 1053 are ok to apply to convert disk data to image data (e.g., to map unsigned shorts to signed housfield units for CT).
1050 and 1051 should only be used to control how an image is displayed for a human reader. These values are typically set to pre-defined values or are set by the imaging technician to make it easier to see an object of interest - but they are subjective and do not really have a unit (ignoring perceptual linearization of displays and other overly complex issues ).
Just my $0.02,
Thanks for the explanations. Indeed, it would be great if the ElementToIntensityFunctionSlope/Offset would be added to the MetaDataDictionary. Since they are not used frequently (at least not by ITK and I guess also not VTK), it might make sense to have a compatibility-breaking change and rename them to RescaleIntercept / RescaleSlope?
I would agree that MetaIO should not by default apply them to the data. In fact, many image processing algorithms do not require true intensity values, so enforced rescaling would be processing overhead and increase the memory footprint of an application. Actually, I would even think that GDCM + ITK should not do this by default but that this should be optional somehow…