2020-05-10 16:33:04 +02:00
|
|
|
import { isImage } from '@ohif/core/src/utils/isImage';
|
2022-09-20 20:47:18 +02:00
|
|
|
import sopClassDictionary from '@ohif/core/src/utils/sopClassDictionary';
|
2020-05-10 16:33:04 +02:00
|
|
|
import ImageSet from '@ohif/core/src/classes/ImageSet';
|
|
|
|
|
import isDisplaySetReconstructable from '@ohif/core/src/utils/isDisplaySetReconstructable';
|
2022-04-06 19:28:42 +02:00
|
|
|
import { id } from './id';
|
2020-05-11 18:56:46 +02:00
|
|
|
|
|
|
|
|
const sopClassHandlerName = 'stack';
|
2020-05-10 16:33:04 +02:00
|
|
|
|
|
|
|
|
const isMultiFrame = instance => {
|
|
|
|
|
return instance.NumberOfFrames > 1;
|
|
|
|
|
};
|
|
|
|
|
|
2020-05-11 18:56:46 +02:00
|
|
|
const makeDisplaySet = instances => {
|
2020-05-10 16:33:04 +02:00
|
|
|
const instance = instances[0];
|
|
|
|
|
const imageSet = new ImageSet(instances);
|
|
|
|
|
|
2022-07-27 18:39:04 +02:00
|
|
|
const displayReconstructableInfo = isDisplaySetReconstructable(instances);
|
|
|
|
|
|
2020-05-10 16:33:04 +02:00
|
|
|
// set appropriate attributes to image set...
|
|
|
|
|
imageSet.setAttributes({
|
2020-05-15 19:07:21 +02:00
|
|
|
displaySetInstanceUID: imageSet.uid, // create a local alias for the imageSet UID
|
2020-05-11 18:56:46 +02:00
|
|
|
SeriesDate: instance.SeriesDate,
|
|
|
|
|
SeriesTime: instance.SeriesTime,
|
2020-05-14 16:28:45 +02:00
|
|
|
SeriesInstanceUID: instance.SeriesInstanceUID,
|
|
|
|
|
StudyInstanceUID: instance.StudyInstanceUID,
|
2021-08-20 18:14:19 +02:00
|
|
|
SeriesNumber: instance.SeriesNumber || 0,
|
2020-05-11 18:56:46 +02:00
|
|
|
FrameRate: instance.FrameTime,
|
2022-11-16 20:19:52 +01:00
|
|
|
SOPClassUID: instance.SOPClassUID,
|
2021-08-20 18:14:19 +02:00
|
|
|
SeriesDescription: instance.SeriesDescription || '',
|
2020-05-15 10:05:40 +02:00
|
|
|
Modality: instance.Modality,
|
2020-05-10 16:33:04 +02:00
|
|
|
isMultiFrame: isMultiFrame(instance),
|
2023-03-15 17:41:41 +01:00
|
|
|
countIcon: displayReconstructableInfo.value ? 'icon-mpr' : undefined,
|
2020-05-14 13:04:39 +02:00
|
|
|
numImageFrames: instances.length,
|
2020-05-11 18:56:46 +02:00
|
|
|
SOPClassHandlerId: `${id}.sopClassHandlerModule.${sopClassHandlerName}`,
|
2022-07-27 18:39:04 +02:00
|
|
|
isReconstructable: displayReconstructableInfo.value,
|
2020-05-10 16:33:04 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 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 (
|
2020-05-11 18:56:46 +02:00
|
|
|
(parseInt(a.InstanceNumber) || 0) - (parseInt(b.InstanceNumber) || 0)
|
2020-05-10 16:33:04 +02:00
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
*/
|
2020-05-11 18:56:46 +02:00
|
|
|
function getDisplaySetsFromSeries(instances) {
|
2020-05-10 16:33:04 +02:00
|
|
|
// 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);
|
2022-09-21 15:54:29 +02:00
|
|
|
} else if (isSingleImageModality(instance.Modality)) {
|
2020-05-10 16:33:04 +02:00
|
|
|
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,
|
2022-03-11 17:18:56 +01:00
|
|
|
sopClassDictionary.UltrasoundImageStorageRET,
|
2020-05-10 16:33:04 +02:00
|
|
|
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,
|
2022-09-20 20:47:18 +02:00
|
|
|
sopClassDictionary.EnhancedUSVolumeStorage,
|
2020-05-10 16:33:04 +02:00
|
|
|
];
|
|
|
|
|
|
|
|
|
|
function getSopClassHandlerModule() {
|
|
|
|
|
return [
|
|
|
|
|
{
|
2020-05-11 18:56:46 +02:00
|
|
|
name: sopClassHandlerName,
|
2020-05-10 16:33:04 +02:00
|
|
|
sopClassUids,
|
2020-05-11 18:56:46 +02:00
|
|
|
getDisplaySetsFromSeries,
|
2020-05-10 16:33:04 +02:00
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default getSopClassHandlerModule;
|