222 lines
8.3 KiB
JavaScript
222 lines
8.3 KiB
JavaScript
import { isImage } from '@ohif/core/src/utils/isImage';
|
|
import sopClassDictionary from '@ohif/core/src/utils/sopClassDictionary';
|
|
import ImageSet from '@ohif/core/src/classes/ImageSet';
|
|
import isDisplaySetReconstructable from '@ohif/core/src/utils/isDisplaySetReconstructable';
|
|
import { id } from './id';
|
|
import getDisplaySetMessages from './getDisplaySetMessages';
|
|
import getDisplaySetsFromUnsupportedSeries from './getDisplaySetsFromUnsupportedSeries';
|
|
|
|
const sopClassHandlerName = 'stack';
|
|
|
|
const isMultiFrame = instance => {
|
|
return instance.NumberOfFrames > 1;
|
|
};
|
|
|
|
const makeDisplaySet = instances => {
|
|
const instance = instances[0];
|
|
const imageSet = new ImageSet(instances);
|
|
|
|
const { value: isReconstructable, averageSpacingBetweenFrames } =
|
|
isDisplaySetReconstructable(instances);
|
|
// set appropriate attributes to image set...
|
|
const messages = getDisplaySetMessages(instances, isReconstructable);
|
|
|
|
imageSet.setAttributes({
|
|
displaySetInstanceUID: imageSet.uid, // create a local alias for the imageSet UID
|
|
SeriesDate: instance.SeriesDate,
|
|
SeriesTime: instance.SeriesTime,
|
|
SeriesInstanceUID: instance.SeriesInstanceUID,
|
|
StudyInstanceUID: instance.StudyInstanceUID,
|
|
SeriesNumber: instance.SeriesNumber || 0,
|
|
FrameRate: instance.FrameTime,
|
|
SOPClassUID: instance.SOPClassUID,
|
|
SeriesDescription: instance.SeriesDescription || '',
|
|
Modality: instance.Modality,
|
|
isMultiFrame: isMultiFrame(instance),
|
|
countIcon: isReconstructable ? 'icon-mpr' : undefined,
|
|
numImageFrames: instances.length,
|
|
SOPClassHandlerId: `${id}.sopClassHandlerModule.${sopClassHandlerName}`,
|
|
isReconstructable,
|
|
messages,
|
|
averageSpacingBetweenFrames: averageSpacingBetweenFrames || null,
|
|
});
|
|
|
|
// Sort the images in this series if needed
|
|
const shallSort = true; //!OHIF.utils.ObjectPath.get(Meteor, 'settings.public.ui.sortSeriesByIncomingOrder');
|
|
if (shallSort) {
|
|
imageSet.sortBy((a, b) => {
|
|
// Sort by InstanceNumber (0020,0013)
|
|
return (parseInt(a.InstanceNumber) || 0) - (parseInt(b.InstanceNumber) || 0);
|
|
});
|
|
}
|
|
|
|
// Include the first image instance number (after sorted)
|
|
/*imageSet.setAttribute(
|
|
'instanceNumber',
|
|
imageSet.getImage(0).InstanceNumber
|
|
);*/
|
|
|
|
/*const isReconstructable = isDisplaySetReconstructable(series, instances);
|
|
|
|
imageSet.isReconstructable = isReconstructable.value;
|
|
|
|
if (isReconstructable.missingFrames) {
|
|
// TODO -> This is currently unused, but may be used for reconstructing
|
|
// Volumes with gaps later on.
|
|
imageSet.missingFrames = isReconstructable.missingFrames;
|
|
}*/
|
|
|
|
return imageSet;
|
|
};
|
|
|
|
const isSingleImageModality = modality => {
|
|
return modality === 'CR' || modality === 'MG' || modality === 'DX';
|
|
};
|
|
|
|
function getSopClassUids(instances) {
|
|
const uniqueSopClassUidsInSeries = new Set();
|
|
instances.forEach(instance => {
|
|
uniqueSopClassUidsInSeries.add(instance.SOPClassUID);
|
|
});
|
|
const sopClassUids = Array.from(uniqueSopClassUidsInSeries);
|
|
|
|
return sopClassUids;
|
|
}
|
|
|
|
/**
|
|
* Basic SOPClassHandler:
|
|
* - For all Image types that are stackable, create
|
|
* a displaySet with a stack of images
|
|
*
|
|
* @param {Array} sopClassHandlerModules List of SOP Class Modules
|
|
* @param {SeriesMetadata} series The series metadata object from which the display sets will be created
|
|
* @returns {Array} The list of display sets created for the given series object
|
|
*/
|
|
function getDisplaySetsFromSeries(instances) {
|
|
// If the series has no instances, stop here
|
|
if (!instances || !instances.length) {
|
|
throw new Error('No instances were provided');
|
|
}
|
|
|
|
const displaySets = [];
|
|
const sopClassUids = getSopClassUids(instances);
|
|
|
|
// Search through the instances (InstanceMetadata object) of this series
|
|
// Split Multi-frame instances and Single-image modalities
|
|
// into their own specific display sets. Place the rest of each
|
|
// series into another display set.
|
|
const stackableInstances = [];
|
|
instances.forEach(instance => {
|
|
// All imaging modalities must have a valid value for sopClassUid (x00080016) or rows (x00280010)
|
|
if (!isImage(instance.SOPClassUID) && !instance.Rows) {
|
|
return;
|
|
}
|
|
|
|
let displaySet;
|
|
|
|
if (isMultiFrame(instance)) {
|
|
displaySet = makeDisplaySet([instance]);
|
|
|
|
displaySet.setAttributes({
|
|
sopClassUids,
|
|
isClip: true,
|
|
numImageFrames: instance.NumberOfFrames,
|
|
instanceNumber: instance.InstanceNumber,
|
|
acquisitionDatetime: instance.AcquisitionDateTime,
|
|
});
|
|
displaySets.push(displaySet);
|
|
} else if (isSingleImageModality(instance.Modality)) {
|
|
displaySet = makeDisplaySet([instance]);
|
|
displaySet.setAttributes({
|
|
sopClassUids,
|
|
instanceNumber: instance.InstanceNumber,
|
|
acquisitionDatetime: instance.AcquisitionDateTime,
|
|
});
|
|
displaySets.push(displaySet);
|
|
} else {
|
|
stackableInstances.push(instance);
|
|
}
|
|
});
|
|
|
|
if (stackableInstances.length) {
|
|
const displaySet = makeDisplaySet(stackableInstances);
|
|
displaySet.setAttribute('studyInstanceUid', instances[0].StudyInstanceUID);
|
|
displaySet.setAttributes({
|
|
sopClassUids,
|
|
});
|
|
displaySets.push(displaySet);
|
|
}
|
|
|
|
return displaySets;
|
|
}
|
|
|
|
const sopClassUids = [
|
|
sopClassDictionary.ComputedRadiographyImageStorage,
|
|
sopClassDictionary.DigitalXRayImageStorageForPresentation,
|
|
sopClassDictionary.DigitalXRayImageStorageForProcessing,
|
|
sopClassDictionary.DigitalMammographyXRayImageStorageForPresentation,
|
|
sopClassDictionary.DigitalMammographyXRayImageStorageForProcessing,
|
|
sopClassDictionary.DigitalIntraOralXRayImageStorageForPresentation,
|
|
sopClassDictionary.DigitalIntraOralXRayImageStorageForProcessing,
|
|
sopClassDictionary.CTImageStorage,
|
|
sopClassDictionary.EnhancedCTImageStorage,
|
|
sopClassDictionary.LegacyConvertedEnhancedCTImageStorage,
|
|
sopClassDictionary.UltrasoundMultiframeImageStorage,
|
|
sopClassDictionary.MRImageStorage,
|
|
sopClassDictionary.EnhancedMRImageStorage,
|
|
sopClassDictionary.EnhancedMRColorImageStorage,
|
|
sopClassDictionary.LegacyConvertedEnhancedMRImageStorage,
|
|
sopClassDictionary.UltrasoundImageStorage,
|
|
sopClassDictionary.UltrasoundImageStorageRET,
|
|
sopClassDictionary.SecondaryCaptureImageStorage,
|
|
sopClassDictionary.MultiframeSingleBitSecondaryCaptureImageStorage,
|
|
sopClassDictionary.MultiframeGrayscaleByteSecondaryCaptureImageStorage,
|
|
sopClassDictionary.MultiframeGrayscaleWordSecondaryCaptureImageStorage,
|
|
sopClassDictionary.MultiframeTrueColorSecondaryCaptureImageStorage,
|
|
sopClassDictionary.XRayAngiographicImageStorage,
|
|
sopClassDictionary.EnhancedXAImageStorage,
|
|
sopClassDictionary.XRayRadiofluoroscopicImageStorage,
|
|
sopClassDictionary.EnhancedXRFImageStorage,
|
|
sopClassDictionary.XRay3DAngiographicImageStorage,
|
|
sopClassDictionary.XRay3DCraniofacialImageStorage,
|
|
sopClassDictionary.BreastTomosynthesisImageStorage,
|
|
sopClassDictionary.BreastProjectionXRayImageStorageForPresentation,
|
|
sopClassDictionary.BreastProjectionXRayImageStorageForProcessing,
|
|
sopClassDictionary.IntravascularOpticalCoherenceTomographyImageStorageForPresentation,
|
|
sopClassDictionary.IntravascularOpticalCoherenceTomographyImageStorageForProcessing,
|
|
sopClassDictionary.NuclearMedicineImageStorage,
|
|
sopClassDictionary.VLEndoscopicImageStorage,
|
|
sopClassDictionary.VideoEndoscopicImageStorage,
|
|
sopClassDictionary.VLMicroscopicImageStorage,
|
|
sopClassDictionary.VideoMicroscopicImageStorage,
|
|
sopClassDictionary.VLSlideCoordinatesMicroscopicImageStorage,
|
|
sopClassDictionary.VLPhotographicImageStorage,
|
|
sopClassDictionary.VideoPhotographicImageStorage,
|
|
sopClassDictionary.OphthalmicPhotography8BitImageStorage,
|
|
sopClassDictionary.OphthalmicPhotography16BitImageStorage,
|
|
sopClassDictionary.OphthalmicTomographyImageStorage,
|
|
sopClassDictionary.VLWholeSlideMicroscopyImageStorage,
|
|
sopClassDictionary.PositronEmissionTomographyImageStorage,
|
|
sopClassDictionary.EnhancedPETImageStorage,
|
|
sopClassDictionary.LegacyConvertedEnhancedPETImageStorage,
|
|
sopClassDictionary.RTImageStorage,
|
|
sopClassDictionary.EnhancedUSVolumeStorage,
|
|
];
|
|
|
|
function getSopClassHandlerModule() {
|
|
return [
|
|
{
|
|
name: sopClassHandlerName,
|
|
sopClassUids,
|
|
getDisplaySetsFromSeries,
|
|
},
|
|
{
|
|
name: 'not-supported-display-sets-handler',
|
|
sopClassUids: [],
|
|
getDisplaySetsFromSeries: getDisplaySetsFromUnsupportedSeries,
|
|
},
|
|
];
|
|
}
|
|
|
|
export default getSopClassHandlerModule;
|