From 4bb36704eed6137cb7ccd3ee6ea93c097d11066e Mon Sep 17 00:00:00 2001 From: Davide Punzo Date: Wed, 14 Apr 2021 19:43:58 +0200 Subject: [PATCH] IDC2346: fix images sorting (#2358) --- .../src/classes/metadata/StudyMetadata.js | 26 +++++++--- .../src/utils/isDisplaySetReconstructable.js | 51 ++++++++++++------- 2 files changed, 51 insertions(+), 26 deletions(-) diff --git a/platform/core/src/classes/metadata/StudyMetadata.js b/platform/core/src/classes/metadata/StudyMetadata.js index 0dd12f791..e05701f8a 100644 --- a/platform/core/src/classes/metadata/StudyMetadata.js +++ b/platform/core/src/classes/metadata/StudyMetadata.js @@ -9,7 +9,7 @@ import { SeriesMetadata } from './SeriesMetadata'; import { api } from 'dicomweb-client'; // - createStacks import { isImage } from '../../utils/isImage'; -import isDisplaySetReconstructable from '../../utils/isDisplaySetReconstructable'; +import { isDisplaySetReconstructable, isSpacingUniform } from '../../utils/isDisplaySetReconstructable'; import errorHandler from '../../errorHandler'; import isLowPriorityModality from '../../utils/isLowPriorityModality'; @@ -796,7 +796,7 @@ const makeDisplaySet = (series, instances) => { isMultiFrame: isMultiFrame(instance), }); - // Sort the images in this series if needed + // Sort the images in this series by instanceNumber const shallSort = true; //!OHIF.utils.ObjectPath.get(Meteor, 'settings.public.ui.sortSeriesByIncomingOrder'); if (shallSort) { imageSet.sortBy((a, b) => { @@ -817,19 +817,29 @@ const makeDisplaySet = (series, instances) => { const displayReconstructableInfo = isDisplaySetReconstructable(instances); imageSet.isReconstructable = displayReconstructableInfo.value; + let displaySpacingInfo = undefined; if (shallSort && imageSet.isReconstructable) { + // sort images by image position imageSet.sortByImagePositionPatient(); - } - if (displayReconstructableInfo.missingFrames) { - // TODO -> This is currently unused, but may be used for reconstructing - // Volumes with gaps later on. - imageSet.missingFrames = displayReconstructableInfo.missingFrames; + // check if the spacing is uniform and update isReconstructable + const datasetIs4D = displayReconstructableInfo.warningIssues.find + (issue => issue === ReconstructionIssues.DATASET_4D); + displaySpacingInfo = isSpacingUniform(imageSet.images, datasetIs4D); + imageSet.isReconstructable = displaySpacingInfo.isUniform; + + if (displaySpacingInfo.missingFrames) { + // TODO -> This is currently unused, but may be used for reconstructing + // Volumes with gaps later on. + imageSet.missingFrames = displaySpacingInfo.missingFrames; + } } if (!imageSet.displayReconstructableInfo) { // It is not reconstrabale Save type of warning - imageSet.warningIssues = displayReconstructableInfo.warningIssues; + imageSet.warningIssues = displaySpacingInfo ? + displayReconstructableInfo.warningIssues.concat(displaySpacingInfo.warningIssues) : + displayReconstructableInfo.warningIssues; } return imageSet; diff --git a/platform/core/src/utils/isDisplaySetReconstructable.js b/platform/core/src/utils/isDisplaySetReconstructable.js index 1950e3254..bf9d72c59 100644 --- a/platform/core/src/utils/isDisplaySetReconstructable.js +++ b/platform/core/src/utils/isDisplaySetReconstructable.js @@ -4,11 +4,11 @@ import { ReconstructionIssues } from './../enums.js'; /** * Checks if a series is reconstructable to a 3D volume. * - * @param {Object[]} instances An array of `OHIFInstanceMetadata` objects. + * @param {Object[]} An array of `OHIFInstanceMetadata` objects. * - * @returns {Object} reconstructable value, missingFrames and warningIssues. + * @returns {Object} value, warningIssues. */ -export default function isDisplaySetReconstructable(instances) { +function isDisplaySetReconstructable(instances) { if (!instances.length) { return { value: false }; } @@ -28,7 +28,7 @@ export default function isDisplaySetReconstructable(instances) { } if (isMultiframe) { - return processMultiframe(instances[0]); + return processMultiframe(); } else { return processSingleframe(instances); } @@ -37,12 +37,10 @@ export default function isDisplaySetReconstructable(instances) { /** * Process reconstructable multiframes checks * TODO: deal with multriframe checks! return false for now as can't reconstruct. - * - * @param {Object} instanceof `OHIFInstanceMetadata` objects. Currently not used. - * - * @returns {Object} reconstructable value and warningIssues. + * * + * @returns {Object} value and warningIssues. */ -function processMultiframe(instance) { +function processMultiframe() { const warningIssues = [ReconstructionIssues.MULTIFRAMES]; return { value: false, warningIssues }; } @@ -50,9 +48,9 @@ function processMultiframe(instance) { /** * Process reconstructable single frame checks * - * @param {Object[]} instances An array of `OHIFInstanceMetadata` objects. + * @param {Object[]} An array of `OHIFInstanceMetadata` objects. * - * @returns {Object} reconstructable value, missingFrames and warningIssues. + * @returns {Object} value and warningIssues. */ function processSingleframe(instances) { const n = instances.length; @@ -61,7 +59,6 @@ function processSingleframe(instances) { const firstImageColumns = firstImage.Columns; const firstImageSamplesPerPixel = firstImage.SamplesPerPixel; const firstImageOrientationPatient = firstImage.ImageOrientationPatient; - const firstImagePositionPatient = firstImage.ImagePositionPatient; const warningIssues = []; // Can't reconstruct if we: @@ -91,11 +88,28 @@ function processSingleframe(instances) { } // check if dataset is 4D - const datasetIs4D = _isDataset4D(instances); - if (datasetIs4D) { + if (_isDataset4D(instances)) { warningIssues.push(ReconstructionIssues.DATASET_4D); } + return { value: warningIssues.length === 0 ? true : false, warningIssues }; +} + +/** + * Check is the spacing is uniform. + * The input metadata array has to be ordered by image position. + * + * @param {Object[]} An array of `OHIFInstanceMetadata` objects. + * @param {boolean} is the dataset 4D. + * + * @returns {Object} isUniform, warningIssues and missingFrames + */ +function isSpacingUniform(instances, datasetIs4D) { + const n = instances.length; + const firstImage = instances[0].getData().metadata; + const firstImagePositionPatient = firstImage.ImagePositionPatient; + + const warningIssues = []; let missingFrames = 0; // Check if frame spacing is approximately equal within a spacingTolerance. @@ -150,11 +164,10 @@ function processSingleframe(instances) { } } - - - return { value: warningIssues.length === 0 ? true : false, missingFrames, warningIssues }; + return { isUniform: warningIssues.length === 0 ? true : false, missingFrames, warningIssues }; } + /** * Check if 4D dataset. * @@ -166,7 +179,7 @@ function processSingleframe(instances) { * * @param {Object[]} instances An array of `OHIFInstanceMetadata` objects. * - * @returns {boolean} reconstructable value. + * @returns {boolean} dataset4D value. */ function _isDataset4D(instances) { const n = instances.length; @@ -258,3 +271,5 @@ function _getPerpendicularDistance(a, b) { } const constructableModalities = ['MR', 'CT', 'PT', 'NM']; + +export {isDisplaySetReconstructable, isSpacingUniform};