Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 55 additions & 46 deletions examples/VTKCornerstonePaintingSyncExample.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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`,
Expand All @@ -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,
Expand All @@ -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;
}

Expand All @@ -161,6 +145,7 @@ class VTKCornerstonePaintingSyncExample extends Component {

loadImageData(imageDataObject).then(() => {
const { actor } = createActorMapper(imageDataObject.vtkImageData);

this.setState({
vtkImageData: imageDataObject.vtkImageData,
volumes: [actor],
Expand All @@ -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 = () => {
Expand Down Expand Up @@ -233,7 +237,7 @@ class VTKCornerstonePaintingSyncExample extends Component {
<h1>Syncing VTK Labelmap with Cornerstone Brush Tool Data</h1>
<p>
This example demonstrates how to keep painting in VTK, which is
performed in 3D, in sync with Cornerstone&apos;s tool data, which is
performed in 3D, in sync with Cornerstone's tool data, which is
accessed in 2D.
</p>
<p>
Expand Down Expand Up @@ -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)}
/>
)}
Expand All @@ -287,8 +291,13 @@ class VTKCornerstonePaintingSyncExample extends Component {
{this.state.cornerstoneViewportData && (
<CornerstoneViewport
activeTool={'Brush'}
availableTools={[
{ name: 'Brush', mouseButtonMasks: [1] },
{ name: 'StackScrollMouseWheel' },
{ name: 'StackScrollMultiTouch' },
]}
viewportData={this.state.cornerstoneViewportData}
onMeasurementModified={this.onMeasurementModified}
onMeasurementsChanged={this.onMeasurementsChanged}
onElementEnabled={this.saveCornerstoneElements(0)}
/>
)}
Expand Down
8 changes: 4 additions & 4 deletions src/VTKViewport/createLabelPipeline.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down