137 lines
5.1 KiB
Plaintext
137 lines
5.1 KiB
Plaintext
// See https://github.com/OHIF/Viewers/blob/94a9067fe3d291d30e25a1bda5913511388edea2/platform/core/src/utils/metadataProvider/getPixelSpacingInformation.js
|
||
|
||
export default function getPixelSpacingInformation(instance) {
|
||
// See http://gdcm.sourceforge.net/wiki/index.php/Imager_Pixel_Spacing
|
||
|
||
// TODO: Add Ultrasound region spacing
|
||
// TODO: Add manual calibration
|
||
|
||
// TODO: Use ENUMS from dcmjs
|
||
const projectionRadiographSOPClassUIDs = [
|
||
'1.2.840.10008.5.1.4.1.1.1', // CR Image Storage
|
||
'1.2.840.10008.5.1.4.1.1.1.1', // Digital X-Ray Image Storage – for Presentation
|
||
'1.2.840.10008.5.1.4.1.1.1.1.1', // Digital X-Ray Image Storage – for Processing
|
||
'1.2.840.10008.5.1.4.1.1.1.2', // Digital Mammography X-Ray Image Storage – for Presentation
|
||
'1.2.840.10008.5.1.4.1.1.1.2.1', // Digital Mammography X-Ray Image Storage – for Processing
|
||
'1.2.840.10008.5.1.4.1.1.1.3', // Digital Intra – oral X-Ray Image Storage – for Presentation
|
||
'1.2.840.10008.5.1.4.1.1.1.3.1', // Digital Intra – oral X-Ray Image Storage – for Processing
|
||
'1.2.840.10008.5.1.4.1.1.12.1', // X-Ray Angiographic Image Storage
|
||
'1.2.840.10008.5.1.4.1.1.12.1.1', // Enhanced XA Image Storage
|
||
'1.2.840.10008.5.1.4.1.1.12.2', // X-Ray Radiofluoroscopic Image Storage
|
||
'1.2.840.10008.5.1.4.1.1.12.2.1', // Enhanced XRF Image Storage
|
||
'1.2.840.10008.5.1.4.1.1.12.3', // X-Ray Angiographic Bi-plane Image Storage Retired
|
||
];
|
||
|
||
const {
|
||
PixelSpacing,
|
||
ImagerPixelSpacing,
|
||
SOPClassUID,
|
||
PixelSpacingCalibrationType,
|
||
PixelSpacingCalibrationDescription,
|
||
EstimatedRadiographicMagnificationFactor,
|
||
SequenceOfUltrasoundRegions,
|
||
} = instance;
|
||
|
||
const isProjection = projectionRadiographSOPClassUIDs.includes(SOPClassUID);
|
||
|
||
const TYPES = {
|
||
NOT_APPLICABLE: 'NOT_APPLICABLE',
|
||
UNKNOWN: 'UNKNOWN',
|
||
CALIBRATED: 'CALIBRATED',
|
||
DETECTOR: 'DETECTOR',
|
||
};
|
||
|
||
if (!isProjection) {
|
||
return PixelSpacing;
|
||
}
|
||
|
||
if (isProjection && !ImagerPixelSpacing) {
|
||
// If only Pixel Spacing is present, and this is a projection radiograph,
|
||
// PixelSpacing should be used, but the user should be informed that
|
||
// what it means is unknown
|
||
return {
|
||
PixelSpacing,
|
||
type: TYPES.UNKNOWN,
|
||
isProjection,
|
||
};
|
||
} else if (
|
||
PixelSpacing &&
|
||
ImagerPixelSpacing &&
|
||
PixelSpacing === ImagerPixelSpacing
|
||
) {
|
||
// If Imager Pixel Spacing and Pixel Spacing are present and they have the same values,
|
||
// then the user should be informed that the measurements are at the detector plane
|
||
return {
|
||
PixelSpacing,
|
||
type: TYPES.DETECTOR,
|
||
isProjection,
|
||
};
|
||
} else if (
|
||
PixelSpacing &&
|
||
ImagerPixelSpacing &&
|
||
PixelSpacing !== ImagerPixelSpacing
|
||
) {
|
||
// If Imager Pixel Spacing and Pixel Spacing are present and they have different values,
|
||
// then the user should be informed that these are "calibrated"
|
||
// (in some unknown manner if Pixel Spacing Calibration Type and/or
|
||
// Pixel Spacing Calibration Description are absent)
|
||
return {
|
||
PixelSpacing,
|
||
type: TYPES.CALIBRATED,
|
||
isProjection,
|
||
PixelSpacingCalibrationType,
|
||
PixelSpacingCalibrationDescription,
|
||
};
|
||
} else if (!PixelSpacing && ImagerPixelSpacing) {
|
||
let CorrectedImagerPixelSpacing = ImagerPixelSpacing;
|
||
if (EstimatedRadiographicMagnificationFactor) {
|
||
// Note that in IHE Mammo profile compliant displays, the value of Imager Pixel Spacing is required to be corrected by
|
||
// Estimated Radiographic Magnification Factor and the user informed of that.
|
||
// TODO: should this correction be done before all of this logic?
|
||
CorrectedImagerPixelSpacing = ImagerPixelSpacing.map(
|
||
(pixelSpacing) =>
|
||
pixelSpacing / EstimatedRadiographicMagnificationFactor
|
||
);
|
||
} else {
|
||
console.warn(
|
||
'EstimatedRadiographicMagnificationFactor was not present. Unable to correct ImagerPixelSpacing.'
|
||
);
|
||
}
|
||
|
||
return {
|
||
PixelSpacing: CorrectedImagerPixelSpacing,
|
||
isProjection,
|
||
};
|
||
} else if (
|
||
SequenceOfUltrasoundRegions &&
|
||
typeof SequenceOfUltrasoundRegions === 'object'
|
||
) {
|
||
const { PhysicalDeltaX, PhysicalDeltaY } = SequenceOfUltrasoundRegions;
|
||
const USPixelSpacing = [PhysicalDeltaX * 10, PhysicalDeltaY * 10];
|
||
|
||
return {
|
||
PixelSpacing: USPixelSpacing,
|
||
};
|
||
} else if (
|
||
SequenceOfUltrasoundRegions &&
|
||
Array.isArray(SequenceOfUltrasoundRegions) &&
|
||
SequenceOfUltrasoundRegions.length > 1
|
||
) {
|
||
console.warn(
|
||
'Sequence of Ultrasound Regions > one entry. This is not yet implemented, all measurements will be shown in pixels.'
|
||
);
|
||
} else if (isProjection === false && !ImagerPixelSpacing) {
|
||
// If only Pixel Spacing is present, and this is not a projection radiograph,
|
||
// we can stop here
|
||
return {
|
||
PixelSpacing,
|
||
type: TYPES.NOT_APPLICABLE,
|
||
isProjection,
|
||
};
|
||
}
|
||
|
||
console.warn(
|
||
'Unknown combination of PixelSpacing and ImagerPixelSpacing identified. Unable to determine spacing.'
|
||
);
|
||
}
|