From cf9cc52fc47c00160153d5c0705eb2a5b12a3d88 Mon Sep 17 00:00:00 2001 From: "James A. Petts" Date: Tue, 17 Sep 2019 09:40:22 +0100 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20CorerstoneTools=204.?= =?UTF-8?q?0=20+=20vtk-js=20brush=20sync=20example?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sync example for cornerstoneTools 4.0 and brush sync. --- examples/VTKCornerstonePaintingSyncExample.js | 101 ++++++++++-------- src/VTKViewport/createLabelPipeline.js | 8 +- 2 files changed, 59 insertions(+), 50 deletions(-) diff --git a/examples/VTKCornerstonePaintingSyncExample.js b/examples/VTKCornerstonePaintingSyncExample.js index d3347c3f..619de2d6 100644 --- a/examples/VTKCornerstonePaintingSyncExample.js +++ b/examples/VTKCornerstonePaintingSyncExample.js @@ -24,46 +24,32 @@ function setupSyncedBrush(imageDataObject, element) { // If you want to load a segmentation labelmap, you would want to load // it into this array at this point. - const threeDimensionalPixelData = new Uint8ClampedArray(numVolumePixels); + const threeDimensionalPixelData = new Uint16Array(numVolumePixels); const buffer = threeDimensionalPixelData.buffer; - - // Slice buffer into 2d-sized pieces, which are added to Cornerstone ToolData - const toolType = 'brush'; - const segmentationIndex = 0; const imageIds = imageDataObject.imageIds; - if (imageIds.length !== depth) { + const numberOfFrames = imageIds.length; + + if (numberOfFrames !== depth) { throw new Error('Depth should match the number of imageIds'); } - const { globalImageIdSpecificToolStateManager } = cornerstoneTools; - - for (let i = 0; i < imageIds.length; i++) { - const imageId = imageIds[i]; - const byteOffset = width * height * i; - const length = width * height; - const slicePixelData = new Uint8ClampedArray(buffer, byteOffset, length); - - const toolData = []; - toolData[segmentationIndex] = { - pixelData: slicePixelData, - invalidated: true, - }; - - const toolState = - globalImageIdSpecificToolStateManager.saveImageIdToolState(imageId) || {}; + const segmentationModule = cornerstoneTools.getModule('segmentation'); - toolState[toolType] = { - data: toolData, - }; + segmentationModule.setters.labelmap3DByFirstImageId( + imageIds[0], + buffer, + 0, + [], + numberOfFrames, + undefined, + 0 + ); - globalImageIdSpecificToolStateManager.restoreImageIdToolState( - imageId, - toolState - ); - } + segmentationModule.setters.colorLUT(0, [[255, 0, 0, 255]]); // Create VTK Image Data with buffer as input + const labelMap = vtkImageData.newInstance(); // right now only support 256 labels @@ -100,9 +86,6 @@ const ROOT_URL = : window.location.hostname; const imageIds = [ - //'dicomweb://s3.amazonaws.com/lury/PTCTStudy/1.3.6.1.4.1.25403.52237031786.3872.20100510032220.10.dcm', - //'dicomweb://s3.amazonaws.com/lury/PTCTStudy/1.3.6.1.4.1.25403.52237031786.3872.20100510032220.11.dcm', - //'dicomweb://s3.amazonaws.com/lury/PTCTStudy/1.3.6.1.4.1.25403.52237031786.3872.20100510032220.12.dcm', `dicomweb://${ROOT_URL}/PTCTStudy/1.3.6.1.4.1.25403.52237031786.3872.20100510032221.1.dcm`, `dicomweb://${ROOT_URL}/PTCTStudy/1.3.6.1.4.1.25403.52237031786.3872.20100510032221.2.dcm`, `dicomweb://${ROOT_URL}/PTCTStudy/1.3.6.1.4.1.25403.52237031786.3872.20100510032221.3.dcm`, @@ -120,8 +103,6 @@ const promises = imageIds.map(imageId => { return cornerstone.loadAndCacheImage(imageId); }); -const BaseBrushTool = cornerstoneTools.import('base/BaseBrushTool'); - class VTKCornerstonePaintingSyncExample extends Component { state = { volumes: null, @@ -147,10 +128,13 @@ class VTKCornerstonePaintingSyncExample extends Component { }; const imageDataObject = getImageData(imageIds, displaySetInstanceUid); - const labelMapInputData = setupSyncedBrush(imageDataObject); + const labelMapInputData = setupSyncedBrush( + imageDataObject, + this.cornerstoneElements[0] + ); - this.onMeasurementModified = event => { - if (event.type !== EVENTS.MEASUREMENT_MODIFIED) { + this.onMeasurementsChanged = event => { + if (event.type !== EVENTS.LABELMAP_MODIFIED) { return; } @@ -161,6 +145,7 @@ class VTKCornerstonePaintingSyncExample extends Component { loadImageData(imageDataObject).then(() => { const { actor } = createActorMapper(imageDataObject.vtkImageData); + this.setState({ vtkImageData: imageDataObject.vtkImageData, volumes: [actor], @@ -175,14 +160,33 @@ class VTKCornerstonePaintingSyncExample extends Component { ); } - invalidateBrush = () => { + onPaintEnd = () => { const element = this.cornerstoneElements[0]; const enabledElement = cornerstone.getEnabledElement(element); - const enabledElementUid = enabledElement.uuid; + const { getters, setters } = cornerstoneTools.getModule('segmentation'); + const labelmap3D = getters.labelmap3D(element); + const stackState = cornerstoneTools.getToolState(element, 'stack'); + const { rows, columns } = enabledElement.image; + + if (!stackState || !labelmap3D) { + return; + } + + const stackData = stackState.data[0]; + const numberOfFrames = stackData.imageIds.length; + + // TODO -> Can do more efficiently if we can grab the strokeBuffer from vtk-js. + for (let i = 0; i < numberOfFrames; i++) { + const labelmap2D = getters.labelmap2DByImageIdIndex( + labelmap3D, + i, + rows, + columns + ); + setters.updateSegmentsOnLabelmap2D(labelmap2D); + } - // Note: This calls updateImage internally - // TODO: Find out why it's not very quick to update... - BaseBrushTool.invalidateBrushOnEnabledElement(enabledElementUid); + cornerstone.updateImage(element); }; rerenderAllVTKViewports = () => { @@ -233,7 +237,7 @@ class VTKCornerstonePaintingSyncExample extends Component {

Syncing VTK Labelmap with Cornerstone Brush Tool Data

This example demonstrates how to keep painting in VTK, which is - performed in 3D, in sync with Cornerstone's tool data, which is + performed in 3D, in sync with Cornerstone's tool data, which is accessed in 2D.

@@ -278,7 +282,7 @@ class VTKCornerstonePaintingSyncExample extends Component { paintFilterBackgroundImageData={this.state.vtkImageData} paintFilterLabelMapImageData={this.state.labelMapInputData} painting={this.state.focusedWidgetId === 'PaintWidget'} - onPaint={this.invalidateBrush} + onPaintEnd={this.onPaintEnd} onCreated={this.saveComponentReference(0)} /> )} @@ -287,8 +291,13 @@ class VTKCornerstonePaintingSyncExample extends Component { {this.state.cornerstoneViewportData && ( )} diff --git a/src/VTKViewport/createLabelPipeline.js b/src/VTKViewport/createLabelPipeline.js index 53b0f5b6..4ab621e4 100644 --- a/src/VTKViewport/createLabelPipeline.js +++ b/src/VTKViewport/createLabelPipeline.js @@ -53,11 +53,11 @@ export default function createLabelPipeline( labelMap.actor.setMapper(labelMap.mapper); // set up labelMap color and opacity mapping - labelMap.cfun.addRGBPoint(1, 0, 0, 1); // label '1' will be blue - labelMap.cfun.addRGBPoint(2, 1, 0, 0); // label '2' will be red - labelMap.cfun.addRGBPoint(3, 0, 1, 0); // label '3' will be green + labelMap.cfun.addRGBPoint(1, 1, 0, 0); // label '1' will be red + labelMap.cfun.addRGBPoint(2, 0, 1, 0); // label '2' will be green + labelMap.cfun.addRGBPoint(3, 0, 1, 1); // label '3' will be blue labelMap.ofun.addPoint(0, 0); - labelMap.ofun.addPoint(1, 0.5); + labelMap.ofun.addPoint(1, 0.9); labelMap.actor.getProperty().setRGBTransferFunction(0, labelMap.cfun); labelMap.actor.getProperty().setScalarOpacity(0, labelMap.ofun); From 620fe22df9e29af062b16841fe374123813ace61 Mon Sep 17 00:00:00 2001 From: "James A. Petts" Date: Tue, 17 Sep 2019 09:43:58 +0100 Subject: [PATCH 2/2] Test remove .npmrc --- .npmrc | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 .npmrc diff --git a/.npmrc b/.npmrc deleted file mode 100644 index a1ee1f87..00000000 --- a/.npmrc +++ /dev/null @@ -1,2 +0,0 @@ -react-vtkjs-viewport:registry=https://registry.npmjs.org/ -//registry.npmjs.org/:_authToken=${NPM_TOKEN}