From 5f750ed0214bbc2789cf78f5f0b1039af5aee8a8 Mon Sep 17 00:00:00 2001 From: "James A. Petts" Date: Fri, 8 Nov 2019 07:56:03 +0000 Subject: [PATCH 1/6] Pass down colorLUT options to View2D --- src/VTKViewport/View2D.js | 4 ++- src/VTKViewport/View3D.js | 1 + src/VTKViewport/createLabelPipeline.js | 40 ++++++++++++++++++++++---- src/helpers/formatDA.js | 9 ++++-- src/helpers/formatTM.js | 18 ++++++------ 5 files changed, 56 insertions(+), 16 deletions(-) diff --git a/src/VTKViewport/View2D.js b/src/VTKViewport/View2D.js index cd01f093..c8085daa 100644 --- a/src/VTKViewport/View2D.js +++ b/src/VTKViewport/View2D.js @@ -28,6 +28,7 @@ export default class View2D extends Component { onCreated: PropTypes.func, onDestroyed: PropTypes.func, orientation: PropTypes.object, + labelmapRenderingOptions: PropTypes.object, }; static defaultProps = { @@ -400,7 +401,8 @@ export default class View2D extends Component { const labelmapImageData = this.props.paintFilterLabelMapImageData; const labelmap = createLabelPipeline( this.props.paintFilterBackgroundImageData, - labelmapImageData + labelmapImageData, + this.props.labelmapRenderingOptions ); this.labelmap = labelmap; diff --git a/src/VTKViewport/View3D.js b/src/VTKViewport/View3D.js index 2379662d..7a8e45c9 100644 --- a/src/VTKViewport/View3D.js +++ b/src/VTKViewport/View3D.js @@ -189,6 +189,7 @@ export default class View3D extends Component { const labelmap = createLabelPipeline( this.props.paintFilterBackgroundImageData, labelmapImageData, + null, // TODO -> fix up colors when I work on 3D. true ); diff --git a/src/VTKViewport/createLabelPipeline.js b/src/VTKViewport/createLabelPipeline.js index e2858228..60881824 100644 --- a/src/VTKViewport/createLabelPipeline.js +++ b/src/VTKViewport/createLabelPipeline.js @@ -8,9 +8,15 @@ import vtkPiecewiseFunction from 'vtk.js/Sources/Common/DataModel/PiecewiseFunct export default function createLabelPipeline( backgroundImageData, paintFilterLabelMapImageData, + options, useSampleDistance = false ) { let labelMapData; + let { colorLUT, globalOpacity } = options; + + if (globalOpacity === undefined) { + globalOpacity = 1.0; + } if (paintFilterLabelMapImageData) { labelMapData = paintFilterLabelMapImageData; @@ -54,12 +60,36 @@ export default function createLabelPipeline( // labelmap pipeline labelMap.actor.setMapper(labelMap.mapper); - // set up labelMap color and opacity mapping - 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 + console.log('ENTERING COLORLUT'); + labelMap.ofun.addPoint(0, 0); - labelMap.ofun.addPoint(1, 0.9); + + // set up labelMap color and opacity mapping + if (colorLUT) { + for (let i = 0; i < 256; i++) { + //for (let i = 0; i < colorLUT.length; i++) { + const color = colorLUT[i]; + labelMap.cfun.addRGBPoint( + i, + color[0] / 255, + color[1] / 255, + color[2] / 255 + ); + + const segmentOpacity = (color[3] / 255) * globalOpacity; + + labelMap.ofun.addPoint(i, segmentOpacity); + } + } else { + // Some default. + 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, globalOpacity); + labelMap.ofun.addPoint(2, globalOpacity); + labelMap.ofun.addPoint(3, globalOpacity); + } labelMap.actor.getProperty().setRGBTransferFunction(0, labelMap.cfun); labelMap.actor.getProperty().setScalarOpacity(0, labelMap.ofun); diff --git a/src/helpers/formatDA.js b/src/helpers/formatDA.js index 582291d2..d0e7f936 100644 --- a/src/helpers/formatDA.js +++ b/src/helpers/formatDA.js @@ -5,7 +5,12 @@ export default function formatDA(date, strFormat = 'MMM D, YYYY') { return; } - const parsedDateTime = parse(date, 'YYYYMMDD'); + try { + const parsedDateTime = parse(date, 'yyyyMMdd', new Date()); + const formattedDateTime = format(parsedDateTime, strFormat); - return format(parsedDateTime, strFormat); + return formattedDateTime; + } catch (err) { + // swallow? + } } diff --git a/src/helpers/formatTM.js b/src/helpers/formatTM.js index 48afc843..14567ecc 100644 --- a/src/helpers/formatTM.js +++ b/src/helpers/formatTM.js @@ -5,14 +5,16 @@ export default function formatTM(time, strFormat = 'HH:mm:ss') { return; } - // DICOM Time is stored as HHmmss.SSS, where: - // HH 24 hour time: - // m mm 0..59 Minutes - // s ss 0..59 Seconds - // S SS SSS 0..999 Fractional seconds - // - // See MomentJS: http://momentjs.com/docs/#/parsing/string-format/ - const parsedDateTime = parse(time, 'HHmmss.SSS'); + try { + const inputFormat = 'HHmmss.SSS'; + const strTime = time.toString().substring(0, inputFormat.length); + const parsedDateTime = parse(strTime, 'HHmmss.SSS', new Date(0)); + const formattedDateTime = format(parsedDateTime, strFormat); + + return formattedDateTime; + } catch (err) { + // swallow? + } return format(parsedDateTime, strFormat); } From 4fce906d0acd0f5d30d191b985890437b7bdc1c3 Mon Sep 17 00:00:00 2001 From: "James A. Petts" Date: Mon, 11 Nov 2019 09:00:15 +0000 Subject: [PATCH 2/6] Ability to toggle segmentation on/off --- src/VTKViewport/View2D.js | 35 ++++++++++++++++++++++++-- src/VTKViewport/createLabelPipeline.js | 29 +++++++++++++-------- 2 files changed, 51 insertions(+), 13 deletions(-) diff --git a/src/VTKViewport/View2D.js b/src/VTKViewport/View2D.js index c8085daa..edfc57ef 100644 --- a/src/VTKViewport/View2D.js +++ b/src/VTKViewport/View2D.js @@ -11,8 +11,11 @@ import vtkSVGWidgetManager from './vtkSVGWidgetManager'; import ViewportOverlay from '../ViewportOverlay/ViewportOverlay.js'; import { ViewTypes } from 'vtk.js/Sources/Widgets/Core/WidgetManager/Constants'; import { createSub } from '../lib/createSub.js'; +import realsApproximatelyEqual from '../lib/math/realsApproximatelyEqual'; import createLabelPipeline from './createLabelPipeline'; +const minSlabThickness = 0.1; // TODO -> Should this be configurable or not? + export default class View2D extends Component { static propTypes = { volumes: PropTypes.array.isRequired, @@ -33,6 +36,9 @@ export default class View2D extends Component { static defaultProps = { painting: false, + labelmapRenderingOptions: { + visible: true, + }, }; constructor(props) { @@ -265,8 +271,6 @@ export default class View2D extends Component { if (currentIStyle.getSlabThickness) { return currentIStyle.getSlabThickness(); } - - //return this.currentSlabThickness; } setSlabThickness(slabThickness) { @@ -275,6 +279,23 @@ export default class View2D extends Component { if (istyle.setSlabThickness) { istyle.setSlabThickness(slabThickness); + + if (this.props.paintFilterLabelMapImageData) { + const labelmapActor = this.labelmap.actor; + + if (realsApproximatelyEqual(slabThickness, minSlabThickness)) { + if ( + labelmapActor.getVisibility() !== + this.props.labelmapRenderingOptions.visible + ) { + labelmapActor.setVisibility( + this.props.labelmapRenderingOptions.visible + ); + } + } else { + labelmapActor.setVisibility(false); + } + } } renderWindow.render(); @@ -420,6 +441,16 @@ export default class View2D extends Component { ); } + if ( + prevProps.labelmapRenderingOptions && + prevProps.labelmapRenderingOptions.visible !== + this.props.labelmapRenderingOptions.visible + ) { + this.labelmap.actor.setVisibility( + prevProps.labelmapRenderingOptions.visible + ); + } + if (prevProps.painting !== this.props.painting) { if (this.props.painting) { this.viewWidget = this.widgetManager.addWidget( diff --git a/src/VTKViewport/createLabelPipeline.js b/src/VTKViewport/createLabelPipeline.js index 60881824..506c7ebb 100644 --- a/src/VTKViewport/createLabelPipeline.js +++ b/src/VTKViewport/createLabelPipeline.js @@ -1,6 +1,7 @@ import vtkImageData from 'vtk.js/Sources/Common/DataModel/ImageData'; import vtkDataArray from 'vtk.js/Sources/Common/Core/DataArray'; import vtkVolume from 'vtk.js/Sources/Rendering/Core/Volume'; +import vtkImageSlice from 'vtk.js/Sources/Rendering/Core/ImageSlice'; import vtkVolumeMapper from 'vtk.js/Sources/Rendering/Core/VolumeMapper'; import vtkColorTransferFunction from 'vtk.js/Sources/Rendering/Core/ColorTransferFunction'; import vtkPiecewiseFunction from 'vtk.js/Sources/Common/DataModel/PiecewiseFunction'; @@ -12,7 +13,11 @@ export default function createLabelPipeline( useSampleDistance = false ) { let labelMapData; - let { colorLUT, globalOpacity } = options; + let { colorLUT, globalOpacity, visible } = options; + + if (visible === undefined) { + visible = false; + } if (globalOpacity === undefined) { globalOpacity = 1.0; @@ -51,7 +56,7 @@ export default function createLabelPipeline( } const labelMap = { - actor: vtkVolume.newInstance(), + actor: vtkImageSlice.newInstance(), mapper, cfun: vtkColorTransferFunction.newInstance(), ofun: vtkPiecewiseFunction.newInstance(), @@ -59,10 +64,15 @@ export default function createLabelPipeline( // labelmap pipeline labelMap.actor.setMapper(labelMap.mapper); + labelMap.actor.setVisibility(visible); + // All labels above 1 are fully opaque. + labelMap.ofun.addPoint(0, 0); + labelMap.ofun.addPoint(1, 1); - console.log('ENTERING COLORLUT'); + // TODO: Set global opacity for the whole labelmap. - labelMap.ofun.addPoint(0, 0); + //labelMap.actor.getProperty().setOpacity(globalOpacity); + // ^This only works for the slicemapper, not the volume mapper. // set up labelMap color and opacity mapping if (colorLUT) { @@ -76,23 +86,20 @@ export default function createLabelPipeline( color[2] / 255 ); - const segmentOpacity = (color[3] / 255) * globalOpacity; - - labelMap.ofun.addPoint(i, segmentOpacity); + // TODO: per-segment opacity seems broken at the moment. 0.99 is barely visible and 1 is opaque. + //const segmentOpacity = (color[3] / 255) * globalOpacity; + //labelMap.ofun.addPointLong(i, segmentOpacity, 1.0, 1.0); } } else { // Some default. 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, globalOpacity); - labelMap.ofun.addPoint(2, globalOpacity); - labelMap.ofun.addPoint(3, globalOpacity); } labelMap.actor.getProperty().setRGBTransferFunction(0, labelMap.cfun); labelMap.actor.getProperty().setScalarOpacity(0, labelMap.ofun); + labelMap.actor.getProperty().setInterpolationTypeToNearest(); return labelMap; From c54de73d76a1951f2495163d4d925f1419db65be Mon Sep 17 00:00:00 2001 From: "James A. Petts" Date: Tue, 12 Nov 2019 08:58:43 +0000 Subject: [PATCH 3/6] WIP --- src/VTKViewport/createLabelPipeline.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/VTKViewport/createLabelPipeline.js b/src/VTKViewport/createLabelPipeline.js index 506c7ebb..0eef2bad 100644 --- a/src/VTKViewport/createLabelPipeline.js +++ b/src/VTKViewport/createLabelPipeline.js @@ -1,7 +1,6 @@ import vtkImageData from 'vtk.js/Sources/Common/DataModel/ImageData'; import vtkDataArray from 'vtk.js/Sources/Common/Core/DataArray'; import vtkVolume from 'vtk.js/Sources/Rendering/Core/Volume'; -import vtkImageSlice from 'vtk.js/Sources/Rendering/Core/ImageSlice'; import vtkVolumeMapper from 'vtk.js/Sources/Rendering/Core/VolumeMapper'; import vtkColorTransferFunction from 'vtk.js/Sources/Rendering/Core/ColorTransferFunction'; import vtkPiecewiseFunction from 'vtk.js/Sources/Common/DataModel/PiecewiseFunction'; @@ -56,7 +55,7 @@ export default function createLabelPipeline( } const labelMap = { - actor: vtkImageSlice.newInstance(), + actor: vtkVolume.newInstance(), mapper, cfun: vtkColorTransferFunction.newInstance(), ofun: vtkPiecewiseFunction.newInstance(), @@ -71,7 +70,9 @@ export default function createLabelPipeline( // TODO: Set global opacity for the whole labelmap. - //labelMap.actor.getProperty().setOpacity(globalOpacity); + const property = labelMap.actor.getProperty(); + + console.log(property); // ^This only works for the slicemapper, not the volume mapper. // set up labelMap color and opacity mapping From 840cdbf89a20c0fd75e6dbc9c01653f5f6fe135d Mon Sep 17 00:00:00 2001 From: "James A. Petts" Date: Fri, 15 Nov 2019 09:52:07 +0000 Subject: [PATCH 4/6] Ability to set segmentation LUTs --- src/VTKViewport/createLabelPipeline.js | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/VTKViewport/createLabelPipeline.js b/src/VTKViewport/createLabelPipeline.js index 0eef2bad..e5ca3fc2 100644 --- a/src/VTKViewport/createLabelPipeline.js +++ b/src/VTKViewport/createLabelPipeline.js @@ -66,14 +66,7 @@ export default function createLabelPipeline( labelMap.actor.setVisibility(visible); // All labels above 1 are fully opaque. labelMap.ofun.addPoint(0, 0); - labelMap.ofun.addPoint(1, 1); - - // TODO: Set global opacity for the whole labelmap. - - const property = labelMap.actor.getProperty(); - - console.log(property); - // ^This only works for the slicemapper, not the volume mapper. + //labelMap.ofun.addPoint(1, globalOpacity); // set up labelMap color and opacity mapping if (colorLUT) { @@ -87,9 +80,8 @@ export default function createLabelPipeline( color[2] / 255 ); - // TODO: per-segment opacity seems broken at the moment. 0.99 is barely visible and 1 is opaque. - //const segmentOpacity = (color[3] / 255) * globalOpacity; - //labelMap.ofun.addPointLong(i, segmentOpacity, 1.0, 1.0); + const segmentOpacity = (color[3] / 255) * globalOpacity; + labelMap.ofun.addPointLong(i, segmentOpacity, 0.5, 1.0); } } else { // Some default. @@ -102,6 +94,8 @@ export default function createLabelPipeline( labelMap.actor.getProperty().setScalarOpacity(0, labelMap.ofun); labelMap.actor.getProperty().setInterpolationTypeToNearest(); + labelMap.actor.getProperty().setScalarOpacityUnitDistance(0, 0.1); + labelMap.actor.getProperty().setUseGradientOpacity(0, false); return labelMap; } From d7e6987bbce0de16889b639aea29895f07acd65b Mon Sep 17 00:00:00 2001 From: "James A. Petts" Date: Fri, 15 Nov 2019 09:59:27 +0000 Subject: [PATCH 5/6] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20Allows=20configurati?= =?UTF-8?q?on=20of=20a=20the=20segmentation=20properties?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allows the parent component to pass down a colorLUT (with individual segment opacities), a global segmentation opacity, and a visiblity flag for the segmentation. --- src/VTKViewport/createLabelPipeline.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/VTKViewport/createLabelPipeline.js b/src/VTKViewport/createLabelPipeline.js index e5ca3fc2..c3b5f59c 100644 --- a/src/VTKViewport/createLabelPipeline.js +++ b/src/VTKViewport/createLabelPipeline.js @@ -64,13 +64,14 @@ export default function createLabelPipeline( // labelmap pipeline labelMap.actor.setMapper(labelMap.mapper); labelMap.actor.setVisibility(visible); - // All labels above 1 are fully opaque. labelMap.ofun.addPoint(0, 0); - //labelMap.ofun.addPoint(1, globalOpacity); // set up labelMap color and opacity mapping if (colorLUT) { - for (let i = 0; i < 256; i++) { + // TODO -> It seems to crash if you set it higher than 256?? + const numColors = Math.min(256, colorLUT.length); + + for (let i = 0; i < numColors; i++) { //for (let i = 0; i < colorLUT.length; i++) { const color = colorLUT[i]; labelMap.cfun.addRGBPoint( From 967644e032a5b7691bbfa6f01452d72420ed334b Mon Sep 17 00:00:00 2001 From: "James A. Petts" Date: Fri, 15 Nov 2019 10:33:37 +0000 Subject: [PATCH 6/6] Fix broken examples and View3D port. --- src/VTKViewport/View3D.js | 6 +++++- src/VTKViewport/createLabelPipeline.js | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/VTKViewport/View3D.js b/src/VTKViewport/View3D.js index 7a8e45c9..14d7d835 100644 --- a/src/VTKViewport/View3D.js +++ b/src/VTKViewport/View3D.js @@ -24,11 +24,15 @@ export default class View3D extends Component { dataDetails: PropTypes.object, onCreated: PropTypes.func, onDestroyed: PropTypes.func, + labelmapRenderingOptions: PropTypes.object, }; static defaultProps = { painting: false, sliceNormal: [0, 0, 1], + labelmapRenderingOptions: { + visible: true, + }, }; constructor(props) { @@ -189,7 +193,7 @@ export default class View3D extends Component { const labelmap = createLabelPipeline( this.props.paintFilterBackgroundImageData, labelmapImageData, - null, // TODO -> fix up colors when I work on 3D. + this.props.labelmapRenderingOptions, true ); diff --git a/src/VTKViewport/createLabelPipeline.js b/src/VTKViewport/createLabelPipeline.js index c3b5f59c..6ea9ccfb 100644 --- a/src/VTKViewport/createLabelPipeline.js +++ b/src/VTKViewport/createLabelPipeline.js @@ -12,6 +12,7 @@ export default function createLabelPipeline( useSampleDistance = false ) { let labelMapData; + let { colorLUT, globalOpacity, visible } = options; if (visible === undefined) { @@ -89,6 +90,7 @@ export default function createLabelPipeline( 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(1, 0.5); // All labels full opacity } labelMap.actor.getProperty().setRGBTransferFunction(0, labelMap.cfun);