diff --git a/packages/cornerstone-render/src/volumeLoader.ts b/packages/cornerstone-render/src/volumeLoader.ts index 3babe6345..c8791cd54 100644 --- a/packages/cornerstone-render/src/volumeLoader.ts +++ b/packages/cornerstone-render/src/volumeLoader.ts @@ -299,7 +299,8 @@ export function createAndCacheDerivedVolume( */ export function createAndCacheLocalVolume( options: LocalVolumeOptions, - uid: string + uid: string, + preventCache = false ): ImageVolume { const { scalarData, metadata, dimensions, spacing, origin, direction } = options @@ -360,6 +361,10 @@ export function createAndCacheLocalVolume( sizeInBytes: numBytes, }) + if (preventCache) { + return derivedVolume + } + const volumeLoadObject = { promise: Promise.resolve(derivedVolume), } diff --git a/packages/cornerstone-tools/src/util/segmentation/createMergedLabelmap.ts b/packages/cornerstone-tools/src/util/segmentation/createMergedLabelmap.ts new file mode 100644 index 000000000..a4d915b2b --- /dev/null +++ b/packages/cornerstone-tools/src/util/segmentation/createMergedLabelmap.ts @@ -0,0 +1,60 @@ +import { IImageVolume } from '@precisionmetrics/cornerstone-render/src/types' +import { createAndCacheLocalVolume } from '@precisionmetrics/cornerstone-render' +import isEqual from '../math/vec3/isEqual' + +/** + * Given a list of labelmaps (with the possibility of overlapping regions), + * it generates a new labelmap with the same dimensions as the input labelmaps, + * by merging all the overlapping regions. This methods can be used + * to avoid double counting the segments in more than one labelmaps + * + * @param {} labelmaps + * @param {number} segmentIndex + * @returns {number} TMTV in ml + */ +function createMergedLabelmap( + labelmaps: Array, + segmentIndex = 1, // The segment index to use for the merged labelmap + uid = 'mergedLabelmap' +): IImageVolume { + labelmaps.forEach(({ direction, dimensions, origin, spacing }) => { + if ( + !isEqual(dimensions, labelmaps[0].dimensions) || + !isEqual(direction, labelmaps[0].direction) || + !isEqual(spacing, labelmaps[0].spacing) || + !isEqual(origin, labelmaps[0].origin) + ) { + throw new Error('labelmaps must have the same size and shape') + } + }) + + const labelmap = labelmaps[0] + + const arrayType = labelmap.scalarData.constructor + const outputData = new arrayType(labelmap.scalarData.length) + + labelmaps.forEach((labelmap) => { + const { scalarData } = labelmap + for (let i = 0; i < scalarData.length; i++) { + if (scalarData[i] === segmentIndex) { + outputData[i] = segmentIndex + } + } + }) + + const options = { + scalarData: outputData, + metadata: labelmap.metadata, + spacing: labelmap.spacing, + origin: labelmap.origin, + direction: labelmap.direction, + dimensions: labelmap.dimensions, + } + + const preventCache = true + const mergedVolume = createAndCacheLocalVolume(options, uid, preventCache) + + return mergedVolume +} + +export default createMergedLabelmap diff --git a/packages/cornerstone-tools/src/util/segmentation/index.ts b/packages/cornerstone-tools/src/util/segmentation/index.ts index 30a54e7ce..b141b1dfc 100644 --- a/packages/cornerstone-tools/src/util/segmentation/index.ts +++ b/packages/cornerstone-tools/src/util/segmentation/index.ts @@ -8,6 +8,7 @@ import thresholdVolumeByRoiStats from './thresholdVolumeByRoiStats' import triggerLabelmapRender from './triggerLabelmapRender' import calculateSuvPeak from './calculateSuvPeak' import calculateTMTV from './calculateTMTV' +import createMergedLabelmap from './createMergedLabelmap' export { getBoundingBoxAroundShape, @@ -18,6 +19,7 @@ export { triggerLabelmapRender, calculateSuvPeak, calculateTMTV, + createMergedLabelmap, } export default { @@ -29,4 +31,5 @@ export default { triggerLabelmapRender, calculateSuvPeak, calculateTMTV, + createMergedLabelmap, } diff --git a/packages/cornerstone-tools/src/util/segmentation/thresholdVolumeByRange.ts b/packages/cornerstone-tools/src/util/segmentation/thresholdVolumeByRange.ts index a932fbbc2..3b12fd103 100644 --- a/packages/cornerstone-tools/src/util/segmentation/thresholdVolumeByRange.ts +++ b/packages/cornerstone-tools/src/util/segmentation/thresholdVolumeByRange.ts @@ -34,7 +34,7 @@ function thresholdVolumeByRange( referenceVolumes: IImageVolume[], labelmap: IImageVolume, options: ThresholdRangeOptions -): void { +): IImageVolume { if (referenceVolumes.length > 1) { throw new Error('thresholding more than one volumes is not supported yet') } @@ -104,6 +104,7 @@ function thresholdVolumeByRange( }) triggerLabelmapRender(renderingEngine, labelmap, labelmapImageData) + return labelmap } function worldToIndex(imageData, ain) { diff --git a/packages/cornerstone-tools/src/util/segmentation/thresholdVolumeByRoiStats.ts b/packages/cornerstone-tools/src/util/segmentation/thresholdVolumeByRoiStats.ts index 44afcc0e4..fb717992b 100644 --- a/packages/cornerstone-tools/src/util/segmentation/thresholdVolumeByRoiStats.ts +++ b/packages/cornerstone-tools/src/util/segmentation/thresholdVolumeByRoiStats.ts @@ -36,7 +36,7 @@ function thresholdVolumeByRoiStats( referenceVolumes: IImageVolume[], labelmap: IImageVolume, options: ThresholdRoiStatsOptions -): void { +): IImageVolume { if (referenceVolumes.length > 1) { throw new Error('thresholding more than one volumes is not supported yet') } @@ -105,6 +105,7 @@ function thresholdVolumeByRoiStats( // Run threshold volume by the new range thresholdVolumeByRange(toolDataList, referenceVolumes, labelmap, rangeOptions) + return labelmap } function _worldToIndex(imageData, ain) {