feat: Multiframe metadata provider (#2938)
* fix(volume):Support volume viewing * fix(multiframe):Display multiframe US, and multiframe PR fixes * fix(metadataProvider):Don't call combine if frame not defined
This commit is contained in:
parent
3900e62641
commit
ff24b57a4b
@ -1,4 +1,5 @@
|
||||
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';
|
||||
@ -143,138 +144,6 @@ function getDisplaySetsFromSeries(instances) {
|
||||
return displaySets;
|
||||
}
|
||||
|
||||
// TODO: Remove since we have roughly the same thing in dcmjs
|
||||
const sopClassDictionary = {
|
||||
ComputedRadiographyImageStorage: '1.2.840.10008.5.1.4.1.1.1',
|
||||
DigitalXRayImageStorageForPresentation: '1.2.840.10008.5.1.4.1.1.1.1',
|
||||
DigitalXRayImageStorageForProcessing: '1.2.840.10008.5.1.4.1.1.1.1.1',
|
||||
DigitalMammographyXRayImageStorageForPresentation:
|
||||
'1.2.840.10008.5.1.4.1.1.1.2',
|
||||
DigitalMammographyXRayImageStorageForProcessing:
|
||||
'1.2.840.10008.5.1.4.1.1.1.2.1',
|
||||
DigitalIntraOralXRayImageStorageForPresentation:
|
||||
'1.2.840.10008.5.1.4.1.1.1.3',
|
||||
DigitalIntraOralXRayImageStorageForProcessing:
|
||||
'1.2.840.10008.5.1.4.1.1.1.3.1',
|
||||
CTImageStorage: '1.2.840.10008.5.1.4.1.1.2',
|
||||
EnhancedCTImageStorage: '1.2.840.10008.5.1.4.1.1.2.1',
|
||||
LegacyConvertedEnhancedCTImageStorage: '1.2.840.10008.5.1.4.1.1.2.2',
|
||||
UltrasoundMultiframeImageStorage: '1.2.840.10008.5.1.4.1.1.3.1',
|
||||
MRImageStorage: '1.2.840.10008.5.1.4.1.1.4',
|
||||
EnhancedMRImageStorage: '1.2.840.10008.5.1.4.1.1.4.1',
|
||||
MRSpectroscopyStorage: '1.2.840.10008.5.1.4.1.1.4.2',
|
||||
EnhancedMRColorImageStorage: '1.2.840.10008.5.1.4.1.1.4.3',
|
||||
LegacyConvertedEnhancedMRImageStorage: '1.2.840.10008.5.1.4.1.1.4.4',
|
||||
UltrasoundImageStorageRET: '1.2.840.10008.5.1.4.1.1.6',
|
||||
UltrasoundImageStorage: '1.2.840.10008.5.1.4.1.1.6.1',
|
||||
EnhancedUSVolumeStorage: '1.2.840.10008.5.1.4.1.1.6.2',
|
||||
SecondaryCaptureImageStorage: '1.2.840.10008.5.1.4.1.1.7',
|
||||
MultiframeSingleBitSecondaryCaptureImageStorage:
|
||||
'1.2.840.10008.5.1.4.1.1.7.1',
|
||||
MultiframeGrayscaleByteSecondaryCaptureImageStorage:
|
||||
'1.2.840.10008.5.1.4.1.1.7.2',
|
||||
MultiframeGrayscaleWordSecondaryCaptureImageStorage:
|
||||
'1.2.840.10008.5.1.4.1.1.7.3',
|
||||
MultiframeTrueColorSecondaryCaptureImageStorage:
|
||||
'1.2.840.10008.5.1.4.1.1.7.4',
|
||||
Sop12LeadECGWaveformStorage: '1.2.840.10008.5.1.4.1.1.9.1.1',
|
||||
GeneralECGWaveformStorage: '1.2.840.10008.5.1.4.1.1.9.1.2',
|
||||
AmbulatoryECGWaveformStorage: '1.2.840.10008.5.1.4.1.1.9.1.3',
|
||||
HemodynamicWaveformStorage: '1.2.840.10008.5.1.4.1.1.9.2.1',
|
||||
CardiacElectrophysiologyWaveformStorage: '1.2.840.10008.5.1.4.1.1.9.3.1',
|
||||
BasicVoiceAudioWaveformStorage: '1.2.840.10008.5.1.4.1.1.9.4.1',
|
||||
GeneralAudioWaveformStorage: '1.2.840.10008.5.1.4.1.1.9.4.2',
|
||||
ArterialPulseWaveformStorage: '1.2.840.10008.5.1.4.1.1.9.5.1',
|
||||
RespiratoryWaveformStorage: '1.2.840.10008.5.1.4.1.1.9.6.1',
|
||||
GrayscaleSoftcopyPresentationStateStorage: '1.2.840.10008.5.1.4.1.1.11.1',
|
||||
ColorSoftcopyPresentationStateStorage: '1.2.840.10008.5.1.4.1.1.11.2',
|
||||
PseudoColorSoftcopyPresentationStateStorage: '1.2.840.10008.5.1.4.1.1.11.3',
|
||||
BlendingSoftcopyPresentationStateStorage: '1.2.840.10008.5.1.4.1.1.11.4',
|
||||
XAXRFGrayscaleSoftcopyPresentationStateStorage:
|
||||
'1.2.840.10008.5.1.4.1.1.11.5',
|
||||
XRayAngiographicImageStorage: '1.2.840.10008.5.1.4.1.1.12.1',
|
||||
EnhancedXAImageStorage: '1.2.840.10008.5.1.4.1.1.12.1.1',
|
||||
XRayRadiofluoroscopicImageStorage: '1.2.840.10008.5.1.4.1.1.12.2',
|
||||
EnhancedXRFImageStorage: '1.2.840.10008.5.1.4.1.1.12.2.1',
|
||||
XRay3DAngiographicImageStorage: '1.2.840.10008.5.1.4.1.1.13.1.1',
|
||||
XRay3DCraniofacialImageStorage: '1.2.840.10008.5.1.4.1.1.13.1.2',
|
||||
BreastTomosynthesisImageStorage: '1.2.840.10008.5.1.4.1.1.13.1.3',
|
||||
BreastProjectionXRayImageStorageForPresentation:
|
||||
'1.2.840.10008.5.1.4.1.1.13.1.4',
|
||||
BreastProjectionXRayImageStorageForProcessing:
|
||||
'1.2.840.10008.5.1.4.1.1.13.1.5',
|
||||
IntravascularOpticalCoherenceTomographyImageStorageForPresentation:
|
||||
'1.2.840.10008.5.1.4.1.1.14.1',
|
||||
IntravascularOpticalCoherenceTomographyImageStorageForProcessing:
|
||||
'1.2.840.10008.5.1.4.1.1.14.2',
|
||||
NuclearMedicineImageStorage: '1.2.840.10008.5.1.4.1.1.20',
|
||||
RawDataStorage: '1.2.840.10008.5.1.4.1.1.66',
|
||||
SpatialRegistrationStorage: '1.2.840.10008.5.1.4.1.1.66.1',
|
||||
SpatialFiducialsStorage: '1.2.840.10008.5.1.4.1.1.66.2',
|
||||
DeformableSpatialRegistrationStorage: '1.2.840.10008.5.1.4.1.1.66.3',
|
||||
SegmentationStorage: '1.2.840.10008.5.1.4.1.1.66.4',
|
||||
SurfaceSegmentationStorage: '1.2.840.10008.5.1.4.1.1.66.5',
|
||||
RealWorldValueMappingStorage: '1.2.840.10008.5.1.4.1.1.67',
|
||||
SurfaceScanMeshStorage: '1.2.840.10008.5.1.4.1.1.68.1',
|
||||
SurfaceScanPointCloudStorage: '1.2.840.10008.5.1.4.1.1.68.2',
|
||||
VLEndoscopicImageStorage: '1.2.840.10008.5.1.4.1.1.77.1.1',
|
||||
VideoEndoscopicImageStorage: '1.2.840.10008.5.1.4.1.1.77.1.1.1',
|
||||
VLMicroscopicImageStorage: '1.2.840.10008.5.1.4.1.1.77.1.2',
|
||||
VideoMicroscopicImageStorage: '1.2.840.10008.5.1.4.1.1.77.1.2.1',
|
||||
VLSlideCoordinatesMicroscopicImageStorage: '1.2.840.10008.5.1.4.1.1.77.1.3',
|
||||
VLPhotographicImageStorage: '1.2.840.10008.5.1.4.1.1.77.1.4',
|
||||
VideoPhotographicImageStorage: '1.2.840.10008.5.1.4.1.1.77.1.4.1',
|
||||
OphthalmicPhotography8BitImageStorage: '1.2.840.10008.5.1.4.1.1.77.1.5.1',
|
||||
OphthalmicPhotography16BitImageStorage: '1.2.840.10008.5.1.4.1.1.77.1.5.2',
|
||||
StereometricRelationshipStorage: '1.2.840.10008.5.1.4.1.1.77.1.5.3',
|
||||
OphthalmicTomographyImageStorage: '1.2.840.10008.5.1.4.1.1.77.1.5.4',
|
||||
VLWholeSlideMicroscopyImageStorage: '1.2.840.10008.5.1.4.1.1.77.1.6',
|
||||
LensometryMeasurementsStorage: '1.2.840.10008.5.1.4.1.1.78.1',
|
||||
AutorefractionMeasurementsStorage: '1.2.840.10008.5.1.4.1.1.78.2',
|
||||
KeratometryMeasurementsStorage: '1.2.840.10008.5.1.4.1.1.78.3',
|
||||
SubjectiveRefractionMeasurementsStorage: '1.2.840.10008.5.1.4.1.1.78.4',
|
||||
VisualAcuityMeasurementsStorage: '1.2.840.10008.5.1.4.1.1.78.5',
|
||||
SpectaclePrescriptionReportStorage: '1.2.840.10008.5.1.4.1.1.78.6',
|
||||
OphthalmicAxialMeasurementsStorage: '1.2.840.10008.5.1.4.1.1.78.7',
|
||||
IntraocularLensCalculationsStorage: '1.2.840.10008.5.1.4.1.1.78.8',
|
||||
MacularGridThicknessandVolumeReport: '1.2.840.10008.5.1.4.1.1.79.1',
|
||||
OphthalmicVisualFieldStaticPerimetryMeasurementsStorage:
|
||||
'1.2.840.10008.5.1.4.1.1.80.1',
|
||||
OphthalmicThicknessMapStorage: '1.2.840.10008.5.1.4.1.1.81.1',
|
||||
CornealTopographyMapStorage: '1.2.840.10008.5.1.4.1.1.82.1',
|
||||
BasicTextSR: '1.2.840.10008.5.1.4.1.1.88.11',
|
||||
EnhancedSR: '1.2.840.10008.5.1.4.1.1.88.22',
|
||||
ComprehensiveSR: '1.2.840.10008.5.1.4.1.1.88.33',
|
||||
Comprehensive3DSR: '1.2.840.10008.5.1.4.1.1.88.34',
|
||||
ProcedureLog: '1.2.840.10008.5.1.4.1.1.88.40',
|
||||
MammographyCADSR: '1.2.840.10008.5.1.4.1.1.88.50',
|
||||
KeyObjectSelection: '1.2.840.10008.5.1.4.1.1.88.59',
|
||||
ChestCADSR: '1.2.840.10008.5.1.4.1.1.88.65',
|
||||
XRayRadiationDoseSR: '1.2.840.10008.5.1.4.1.1.88.67',
|
||||
RadiopharmaceuticalRadiationDoseSR: '1.2.840.10008.5.1.4.1.1.88.68',
|
||||
ColonCADSR: '1.2.840.10008.5.1.4.1.1.88.69',
|
||||
ImplantationPlanSRDocumentStorage: '1.2.840.10008.5.1.4.1.1.88.70',
|
||||
EncapsulatedPDFStorage: '1.2.840.10008.5.1.4.1.1.104.1',
|
||||
EncapsulatedCDAStorage: '1.2.840.10008.5.1.4.1.1.104.2',
|
||||
PositronEmissionTomographyImageStorage: '1.2.840.10008.5.1.4.1.1.128',
|
||||
EnhancedPETImageStorage: '1.2.840.10008.5.1.4.1.1.130',
|
||||
LegacyConvertedEnhancedPETImageStorage: '1.2.840.10008.5.1.4.1.1.128.1',
|
||||
BasicStructuredDisplayStorage: '1.2.840.10008.5.1.4.1.1.131',
|
||||
RTImageStorage: '1.2.840.10008.5.1.4.1.1.481.1',
|
||||
RTDoseStorage: '1.2.840.10008.5.1.4.1.1.481.2',
|
||||
RTStructureSetStorage: '1.2.840.10008.5.1.4.1.1.481.3',
|
||||
RTBeamsTreatmentRecordStorage: '1.2.840.10008.5.1.4.1.1.481.4',
|
||||
RTPlanStorage: '1.2.840.10008.5.1.4.1.1.481.5',
|
||||
RTBrachyTreatmentRecordStorage: '1.2.840.10008.5.1.4.1.1.481.6',
|
||||
RTTreatmentSummaryRecordStorage: '1.2.840.10008.5.1.4.1.1.481.7',
|
||||
RTIonPlanStorage: '1.2.840.10008.5.1.4.1.1.481.8',
|
||||
RTIonBeamsTreatmentRecordStorage: '1.2.840.10008.5.1.4.1.1.481.9',
|
||||
RTBeamsDeliveryInstructionStorage: '1.2.840.10008.5.1.4.34.7',
|
||||
GenericImplantTemplateStorage: '1.2.840.10008.5.1.4.43.1',
|
||||
ImplantAssemblyTemplateStorage: '1.2.840.10008.5.1.4.44.1',
|
||||
ImplantTemplateGroupStorage: '1.2.840.10008.5.1.4.45.1',
|
||||
};
|
||||
|
||||
const sopClassUids = [
|
||||
sopClassDictionary.ComputedRadiographyImageStorage,
|
||||
sopClassDictionary.DigitalXRayImageStorageForPresentation,
|
||||
@ -325,6 +194,7 @@ const sopClassUids = [
|
||||
sopClassDictionary.EnhancedPETImageStorage,
|
||||
sopClassDictionary.LegacyConvertedEnhancedPETImageStorage,
|
||||
sopClassDictionary.RTImageStorage,
|
||||
sopClassDictionary.EnhancedUSVolumeStorage,
|
||||
];
|
||||
|
||||
function getSopClassHandlerModule() {
|
||||
|
||||
@ -5,6 +5,7 @@ import getPixelSpacingInformation from '../utils/metadataProvider/getPixelSpacin
|
||||
import DicomMetadataStore from '../services/DicomMetadataStore';
|
||||
import fetchPaletteColorLookupTableData from '../utils/metadataProvider/fetchPaletteColorLookupTableData';
|
||||
import toNumber from '../utils/toNumber';
|
||||
import combineFrameInstance from '../utils/combineFrameInstance';
|
||||
|
||||
class MetadataProvider {
|
||||
constructor() {
|
||||
@ -57,13 +58,21 @@ class MetadataProvider {
|
||||
return;
|
||||
}
|
||||
|
||||
const { StudyInstanceUID, SeriesInstanceUID, SOPInstanceUID } = uids;
|
||||
const {
|
||||
StudyInstanceUID,
|
||||
SeriesInstanceUID,
|
||||
SOPInstanceUID,
|
||||
frameNumber,
|
||||
} = uids;
|
||||
|
||||
return DicomMetadataStore.getInstance(
|
||||
const instance = DicomMetadataStore.getInstance(
|
||||
StudyInstanceUID,
|
||||
SeriesInstanceUID,
|
||||
SOPInstanceUID
|
||||
);
|
||||
return (
|
||||
(frameNumber && combineFrameInstance(frameNumber, instance)) || instance
|
||||
);
|
||||
}
|
||||
|
||||
get(query, imageId, options = { fallback: false }) {
|
||||
@ -408,7 +417,10 @@ class MetadataProvider {
|
||||
// SOPInstanceUID,
|
||||
// })
|
||||
// somewhere else
|
||||
if (imageId.startsWith('wadors:')) {
|
||||
if (
|
||||
imageId.startsWith('wadors:') ||
|
||||
imageId.startsWith('streaming-wadors:')
|
||||
) {
|
||||
const strippedImageId = imageId.split('/studies/')[1];
|
||||
const splitImageId = strippedImageId.split('/');
|
||||
|
||||
@ -416,6 +428,7 @@ class MetadataProvider {
|
||||
StudyInstanceUID: splitImageId[0], // Note: splitImageId[1] === 'series'
|
||||
SeriesInstanceUID: splitImageId[2], // Note: splitImageId[3] === 'instances'
|
||||
SOPInstanceUID: splitImageId[4],
|
||||
frameNumber: splitImageId[6],
|
||||
};
|
||||
} else if (imageId.includes('?requestType=WADO')) {
|
||||
const qs = queryString.parse(imageId);
|
||||
@ -424,6 +437,7 @@ class MetadataProvider {
|
||||
StudyInstanceUID: qs.studyUID,
|
||||
SeriesInstanceUID: qs.seriesUID,
|
||||
SOPInstanceUID: qs.objectUID,
|
||||
frameNumber: qs.frameNumber,
|
||||
};
|
||||
}
|
||||
|
||||
@ -438,7 +452,13 @@ class MetadataProvider {
|
||||
imageURI = imageIdToURI(imageId);
|
||||
}
|
||||
|
||||
return this.imageURIToUIDs.get(imageURI);
|
||||
const uids = this.imageURIToUIDs.get(imageURI);
|
||||
const frameNumber = imageId.split(/\/frames\//)[1];
|
||||
|
||||
if (uids && frameNumber !== undefined) {
|
||||
return { ...uids, frameNumber };
|
||||
}
|
||||
return uids;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
33
platform/core/src/utils/combineFrameInstance.ts
Normal file
33
platform/core/src/utils/combineFrameInstance.ts
Normal file
@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Combine the Per instance frame data, the shared frame data
|
||||
* and the root data objects.
|
||||
* The data is combined by taking nested sequence objects within
|
||||
* the functional group sequences. Data that is directly contained
|
||||
* within the functional group sequences, such as private creators
|
||||
* will be ignored.
|
||||
* This can be safely called with an undefined frame in order to handle
|
||||
* single frame data. (eg frame is undefined is the same as frame===1).
|
||||
*/
|
||||
const combineFrameInstance = (frame, instance) => {
|
||||
const {
|
||||
PerFrameFunctionalGroupsSequence,
|
||||
SharedFunctionalGroupsSequence,
|
||||
} = instance;
|
||||
if (!PerFrameFunctionalGroupsSequence) return instance;
|
||||
const shared = Object.values(SharedFunctionalGroupsSequence[0])
|
||||
.map(it => it[0])
|
||||
.filter(it => it !== undefined && typeof it === 'object');
|
||||
const perFrame = Object.values(
|
||||
PerFrameFunctionalGroupsSequence[(frame || 1) - 1]
|
||||
)
|
||||
.map(it => it[0])
|
||||
.filter(it => it !== undefined && typeof it === 'object');
|
||||
return Object.assign(
|
||||
{},
|
||||
instance,
|
||||
...Object.values(shared),
|
||||
...Object.values(perFrame)
|
||||
);
|
||||
};
|
||||
|
||||
export default combineFrameInstance;
|
||||
@ -12,6 +12,7 @@ const imagesTypes = [
|
||||
sopClassDictionary.EnhancedCTImageStorage,
|
||||
sopClassDictionary.LegacyConvertedEnhancedCTImageStorage,
|
||||
sopClassDictionary.UltrasoundMultiframeImageStorage,
|
||||
sopClassDictionary.EnhancedUSVolumeStorage,
|
||||
sopClassDictionary.MRImageStorage,
|
||||
sopClassDictionary.EnhancedMRImageStorage,
|
||||
sopClassDictionary.EnhancedMRColorImageStorage,
|
||||
|
||||
@ -128,3 +128,5 @@ export const sopClassDictionary = {
|
||||
ImplantAssemblyTemplateStorage: '1.2.840.10008.5.1.4.44.1',
|
||||
ImplantTemplateGroupStorage: '1.2.840.10008.5.1.4.45.1',
|
||||
};
|
||||
|
||||
export default sopClassDictionary;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user