feat(multiframe): enhanced support for multiframe dicom (#3164)
* Changes in cswil version and multiframe * Minor changes * wip * Adding support for NM multiframe images * Applying PR suggestions * fixing package versions * Restoring default.js config file * Check if NM subtype is reconstructable * Restore default.js values * refactore code * feat: add flag for strict zspacing --------- Co-authored-by: Alireza <ar.sedghi@gmail.com>
This commit is contained in:
1 parent
5e42a42b5f
commit
226244a26c
31 files changed
+268
-86
No files matched your search
@@ -30,62 +30,98 @@ export default function isDisplaySetReconstructable(instances) {
|
||||
}
|
||||
|
||||
// Can't reconstruct if all instances don't have the ImagePositionPatient.
|
||||
if (!instances.every(instance => !!instance.ImagePositionPatient)) {
|
||||
if (
|
||||
!isMultiframe &&
|
||||
!instances.every(instance => instance.ImagePositionPatient)
|
||||
) {
|
||||
return { value: false };
|
||||
}
|
||||
|
||||
const sortedInstances = sortInstancesByPosition(instances);
|
||||
|
||||
if (isMultiframe) {
|
||||
return processMultiframe(sortedInstances[0]);
|
||||
} else {
|
||||
return processSingleframe(sortedInstances);
|
||||
}
|
||||
return isMultiframe
|
||||
? processMultiframe(sortedInstances[0])
|
||||
: processSingleframe(sortedInstances);
|
||||
}
|
||||
|
||||
function hasPixelMeasurements(multiFrameInstance) {
|
||||
const perFrameSequence =
|
||||
multiFrameInstance.PerFrameFunctionalGroupsSequence?.[0];
|
||||
const sharedSequence = multiFrameInstance.SharedFunctionalGroupsSequence;
|
||||
|
||||
return (
|
||||
Boolean(perFrameSequence?.PixelMeasuresSequence) ||
|
||||
Boolean(sharedSequence?.PixelMeasuresSequence) ||
|
||||
Boolean(
|
||||
multiFrameInstance.PixelSpacing &&
|
||||
(multiFrameInstance.SliceThickness ||
|
||||
multiFrameInstance.SpacingBetweenFrames)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function hasOrientation(multiFrameInstance) {
|
||||
const sharedSequence = multiFrameInstance.SharedFunctionalGroupsSequence;
|
||||
const perFrameSequence =
|
||||
multiFrameInstance.PerFrameFunctionalGroupsSequence?.[0];
|
||||
|
||||
return (
|
||||
Boolean(sharedSequence?.PlaneOrientationSequence) ||
|
||||
Boolean(perFrameSequence?.PlaneOrientationSequence) ||
|
||||
Boolean(
|
||||
multiFrameInstance.ImageOrientationPatient ||
|
||||
multiFrameInstance.DetectorInformationSequence?.[0]
|
||||
?.ImageOrientationPatient
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function hasPosition(multiFrameInstance) {
|
||||
const perFrameSequence =
|
||||
multiFrameInstance.PerFrameFunctionalGroupsSequence?.[0];
|
||||
|
||||
return (
|
||||
Boolean(perFrameSequence?.PlanePositionSequence) ||
|
||||
Boolean(perFrameSequence?.CTPositionSequence) ||
|
||||
Boolean(
|
||||
multiFrameInstance.ImagePositionPatient ||
|
||||
multiFrameInstance.DetectorInformationSequence?.[0]
|
||||
?.ImagePositionPatient
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function isNMReconstructable(multiFrameInstance) {
|
||||
const imageSubType = multiFrameInstance.ImageType?.[2];
|
||||
return imageSubType === 'RECON TOMO' || imageSubType === 'RECON GATED TOMO';
|
||||
}
|
||||
|
||||
function processMultiframe(multiFrameInstance) {
|
||||
const {
|
||||
PerFrameFunctionalGroupsSequence,
|
||||
SharedFunctionalGroupsSequence,
|
||||
} = multiFrameInstance;
|
||||
|
||||
// If we don't have the PixelMeasuresSequence, then the pixel spacing and
|
||||
// slice thickness isn't specified or is changing and we can't reconstruct
|
||||
// the dataset.
|
||||
if (!hasPixelMeasurements(multiFrameInstance)) {
|
||||
return { value: false };
|
||||
}
|
||||
|
||||
if (!hasOrientation(multiFrameInstance)) {
|
||||
console.log('No image orientation information, not reconstructable');
|
||||
return { value: false };
|
||||
}
|
||||
|
||||
if (!hasPosition(multiFrameInstance)) {
|
||||
console.log('No image position information, not reconstructable');
|
||||
return { value: false };
|
||||
}
|
||||
|
||||
if (
|
||||
!SharedFunctionalGroupsSequence ||
|
||||
!SharedFunctionalGroupsSequence[0].PixelMeasuresSequence
|
||||
multiFrameInstance.Modality.includes('NM') &&
|
||||
!isNMReconstructable(multiFrameInstance)
|
||||
) {
|
||||
return { value: false };
|
||||
}
|
||||
|
||||
// Check that the orientation is either shared or with the allowed
|
||||
// difference amount
|
||||
const {
|
||||
PlaneOrientationSequence: sharedOrientation,
|
||||
} = SharedFunctionalGroupsSequence;
|
||||
|
||||
if (!sharedOrientation) {
|
||||
const {
|
||||
PlaneOrientationSequence: firstOrientation,
|
||||
} = PerFrameFunctionalGroupsSequence[0];
|
||||
|
||||
if (!firstOrientation) {
|
||||
console.log('No orientation information');
|
||||
return { value: false };
|
||||
}
|
||||
// TODO - check orientation consistency
|
||||
}
|
||||
|
||||
const frame0 = PerFrameFunctionalGroupsSequence[0];
|
||||
const firstPosition =
|
||||
frame0.PlanePositionSequence || frame0.CTPositionSequence;
|
||||
if (!firstPosition) {
|
||||
console.log('No image position information, not reconstructable');
|
||||
return { value: false };
|
||||
}
|
||||
// TODO - check spacing consistency
|
||||
|
||||
return { value: true };
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user