From 572cc044bd236a4f5f73e5f5ddd32f487c2ccbc1 Mon Sep 17 00:00:00 2001 From: Miguel Chambel Date: Sun, 15 Nov 2020 15:22:11 +0000 Subject: [PATCH 1/4] feat(segmentation): add function to generate segmentation in cornerstone adapter from dataset instead of images. --- src/adapters/Cornerstone/Segmentation.js | 27 +++++++++++++++++++++ src/adapters/Cornerstone/Segmentation_4X.js | 26 +++++++++++++++++++- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/adapters/Cornerstone/Segmentation.js b/src/adapters/Cornerstone/Segmentation.js index c8852cfc..667fa80b 100644 --- a/src/adapters/Cornerstone/Segmentation.js +++ b/src/adapters/Cornerstone/Segmentation.js @@ -108,3 +108,30 @@ function fillSegmentation( `No generateSegmentation adapater for cornerstone version ${cornerstoneToolsVersion}, exiting.` ); } + +/** + * generateSegmentationWithDataset - Fills a derived segmentation dataset with cornerstoneTools `LabelMap3D` data from Dataset instead of images + * + * @param {object[]} dataset An empty segmentation derived dataset. + * @param {Object|Object[]} inputLabelmaps3D The cornerstone `Labelmap3D` object, or an array of objects. + * @param {Object} userOptions Options object to override default options. + * @returns {Blob} description + */ +function generateSegmentationWithDataset( + dataset, + inputLabelmaps3D, + options = { includeSliceSpacing: true }, + cornerstoneToolsVersion = 4 +) { + if (cornerstoneToolsVersion === 4) { + return Segmentation_4X.generateSegmentationWithDataset( + dataset, + inputLabelmaps3D, + options + ); + } + + console.warn( + `No generateSegmentationWithDataset adapater for cornerstone version ${cornerstoneToolsVersion}, exiting.` + ); +} diff --git a/src/adapters/Cornerstone/Segmentation_4X.js b/src/adapters/Cornerstone/Segmentation_4X.js index cc98a5c4..2afc5699 100644 --- a/src/adapters/Cornerstone/Segmentation_4X.js +++ b/src/adapters/Cornerstone/Segmentation_4X.js @@ -21,7 +21,8 @@ import { const Segmentation = { generateSegmentation, generateToolState, - fillSegmentation + fillSegmentation, + generateSegmentationWithDataset }; export default Segmentation; @@ -39,6 +40,29 @@ const generateSegmentationDefaultOptions = { rleEncode: true }; +/** + * generateSegmentationWithDataset - Generates cornerstoneTools brush data, given a stack of + * imageIds, images and the cornerstoneTools brushData. + * + * @param {object[]} datasets An array of cornerstone image dataset that contain the metadata for each instance + * and a property _meta with empty array (required for compatibility with other dcmjs functions) + * The dataset for each instance of image can be generated with `cornerstone.metaData.get('instance', imageId)`` + * but prop _meta = [] needs to be added to each element other + * @param {Object|Object[]} inputLabelmaps3D The cornerstone `Labelmap3D` object, or an array of objects. + * @param {Object} userOptions Options to pass to the segmentation derivation and `fillSegmentation`. + * @returns {Blob} + */ +function generateSegmentationWithDataset( + datasets, + inputLabelmaps3D, + userOptions = {} +) { + //on multiframe images, datasets array contains only 1 element but should work as well + const multiframe = Normalizer.normalizeToDataset(datasets); + const segmentation = new SegmentationDerivation([multiframe], userOptions); + return fillSegmentation(segmentation, inputLabelmaps3D, userOptions); +} + /** * generateSegmentation - Generates cornerstoneTools brush data, given a stack of * imageIds, images and the cornerstoneTools brushData. From 567931cbdd9f9e7c0696c54ec039f3b2d5cf578c Mon Sep 17 00:00:00 2001 From: Miguel Chambel Date: Mon, 16 Nov 2020 10:26:37 +0000 Subject: [PATCH 2/4] refactor function signature with more meaningfull name; expose function in segmentation object with cornerstone version control/warning --- src/adapters/Cornerstone/Segmentation.js | 11 ++++++----- src/adapters/Cornerstone/Segmentation_4X.js | 6 +++--- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/adapters/Cornerstone/Segmentation.js b/src/adapters/Cornerstone/Segmentation.js index 667fa80b..5d3ead77 100644 --- a/src/adapters/Cornerstone/Segmentation.js +++ b/src/adapters/Cornerstone/Segmentation.js @@ -4,7 +4,8 @@ import Segmentation_4X from "./Segmentation_4X"; const Segmentation = { generateSegmentation, generateToolState, - fillSegmentation + fillSegmentation, + generateSegmentationFromDatasets }; export default Segmentation; @@ -110,21 +111,21 @@ function fillSegmentation( } /** - * generateSegmentationWithDataset - Fills a derived segmentation dataset with cornerstoneTools `LabelMap3D` data from Dataset instead of images + * generateSegmentationFromDatasets - Fills a derived segmentation dataset with cornerstoneTools `LabelMap3D` data from Dataset instead of images * * @param {object[]} dataset An empty segmentation derived dataset. * @param {Object|Object[]} inputLabelmaps3D The cornerstone `Labelmap3D` object, or an array of objects. * @param {Object} userOptions Options object to override default options. * @returns {Blob} description */ -function generateSegmentationWithDataset( +function generateSegmentationFromDatasets( dataset, inputLabelmaps3D, options = { includeSliceSpacing: true }, cornerstoneToolsVersion = 4 ) { if (cornerstoneToolsVersion === 4) { - return Segmentation_4X.generateSegmentationWithDataset( + return Segmentation_4X.generateSegmentationFromDatasets( dataset, inputLabelmaps3D, options @@ -132,6 +133,6 @@ function generateSegmentationWithDataset( } console.warn( - `No generateSegmentationWithDataset adapater for cornerstone version ${cornerstoneToolsVersion}, exiting.` + `No generateSegmentationFromDatasets adapater for cornerstone version ${cornerstoneToolsVersion}, exiting.` ); } diff --git a/src/adapters/Cornerstone/Segmentation_4X.js b/src/adapters/Cornerstone/Segmentation_4X.js index 2afc5699..98f8423e 100644 --- a/src/adapters/Cornerstone/Segmentation_4X.js +++ b/src/adapters/Cornerstone/Segmentation_4X.js @@ -22,7 +22,7 @@ const Segmentation = { generateSegmentation, generateToolState, fillSegmentation, - generateSegmentationWithDataset + generateSegmentationFromDatasets }; export default Segmentation; @@ -41,7 +41,7 @@ const generateSegmentationDefaultOptions = { }; /** - * generateSegmentationWithDataset - Generates cornerstoneTools brush data, given a stack of + * generateSegmentationFromDatasets - Generates cornerstoneTools brush data, given a stack of * imageIds, images and the cornerstoneTools brushData. * * @param {object[]} datasets An array of cornerstone image dataset that contain the metadata for each instance @@ -52,7 +52,7 @@ const generateSegmentationDefaultOptions = { * @param {Object} userOptions Options to pass to the segmentation derivation and `fillSegmentation`. * @returns {Blob} */ -function generateSegmentationWithDataset( +function generateSegmentationFromDatasets( datasets, inputLabelmaps3D, userOptions = {} From f9444d9bb09ed01c19531526e354c9b5bc04d7f6 Mon Sep 17 00:00:00 2001 From: Miguel Chambel Date: Tue, 17 Nov 2020 13:58:46 +0000 Subject: [PATCH 3/4] _meta property added automatically for every dataset if not defined or null --- src/adapters/Cornerstone/Segmentation.js | 4 ++-- src/adapters/Cornerstone/Segmentation_4X.js | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/adapters/Cornerstone/Segmentation.js b/src/adapters/Cornerstone/Segmentation.js index 5d3ead77..2f0f31d8 100644 --- a/src/adapters/Cornerstone/Segmentation.js +++ b/src/adapters/Cornerstone/Segmentation.js @@ -119,14 +119,14 @@ function fillSegmentation( * @returns {Blob} description */ function generateSegmentationFromDatasets( - dataset, + datasets, inputLabelmaps3D, options = { includeSliceSpacing: true }, cornerstoneToolsVersion = 4 ) { if (cornerstoneToolsVersion === 4) { return Segmentation_4X.generateSegmentationFromDatasets( - dataset, + datasets, inputLabelmaps3D, options ); diff --git a/src/adapters/Cornerstone/Segmentation_4X.js b/src/adapters/Cornerstone/Segmentation_4X.js index 98f8423e..f213ded1 100644 --- a/src/adapters/Cornerstone/Segmentation_4X.js +++ b/src/adapters/Cornerstone/Segmentation_4X.js @@ -57,7 +57,8 @@ function generateSegmentationFromDatasets( inputLabelmaps3D, userOptions = {} ) { - //on multiframe images, datasets array contains only 1 element but should work as well + //make sure _meta property is present in every element of datasets with at least an empty array + datasets = datasets.map(ds => ({ ...ds, _meta: ds._meta || [] })); const multiframe = Normalizer.normalizeToDataset(datasets); const segmentation = new SegmentationDerivation([multiframe], userOptions); return fillSegmentation(segmentation, inputLabelmaps3D, userOptions); From 1893686ea0832d5ad8fe70c16c482a8f3fd40f65 Mon Sep 17 00:00:00 2001 From: Miguel Chambel Date: Fri, 20 Nov 2020 18:36:04 +0000 Subject: [PATCH 4/4] add _meta default value in derived dataset constructor --- src/adapters/Cornerstone/Segmentation_4X.js | 7 ++----- src/derivations/DerivedDataset.js | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/adapters/Cornerstone/Segmentation_4X.js b/src/adapters/Cornerstone/Segmentation_4X.js index f213ded1..eb248e2f 100644 --- a/src/adapters/Cornerstone/Segmentation_4X.js +++ b/src/adapters/Cornerstone/Segmentation_4X.js @@ -44,10 +44,9 @@ const generateSegmentationDefaultOptions = { * generateSegmentationFromDatasets - Generates cornerstoneTools brush data, given a stack of * imageIds, images and the cornerstoneTools brushData. * - * @param {object[]} datasets An array of cornerstone image dataset that contain the metadata for each instance + * @param {object[]} datasets An array of cornerstone image datasets that contain the metadata for each instance * and a property _meta with empty array (required for compatibility with other dcmjs functions) - * The dataset for each instance of image can be generated with `cornerstone.metaData.get('instance', imageId)`` - * but prop _meta = [] needs to be added to each element other + * The dataset for each instance of image can be generated with `cornerstone.metaData.get('instance', imageId)` * @param {Object|Object[]} inputLabelmaps3D The cornerstone `Labelmap3D` object, or an array of objects. * @param {Object} userOptions Options to pass to the segmentation derivation and `fillSegmentation`. * @returns {Blob} @@ -57,8 +56,6 @@ function generateSegmentationFromDatasets( inputLabelmaps3D, userOptions = {} ) { - //make sure _meta property is present in every element of datasets with at least an empty array - datasets = datasets.map(ds => ({ ...ds, _meta: ds._meta || [] })); const multiframe = Normalizer.normalizeToDataset(datasets); const segmentation = new SegmentationDerivation([multiframe], userOptions); return fillSegmentation(segmentation, inputLabelmaps3D, userOptions); diff --git a/src/derivations/DerivedDataset.js b/src/derivations/DerivedDataset.js index c7caa77d..991ed288 100644 --- a/src/derivations/DerivedDataset.js +++ b/src/derivations/DerivedDataset.js @@ -38,7 +38,7 @@ export default class DerivedDataset { this.referencedDataset = this.referencedDatasets[0]; this.dataset = { _vrMap: this.referencedDataset._vrMap, - _meta: this.referencedDataset._meta + _meta: this.referencedDataset._meta || [] }; this.derive();