UNPKG

@acransac/vtk.js

Version:

Visualization Toolkit for the Web

149 lines (120 loc) 5.11 kB
import 'vtk.js/Sources/favicon'; import vtkFullScreenRenderWindow from 'vtk.js/Sources/Rendering/Misc/FullScreenRenderWindow'; import vtkHttpDataSetReader from 'vtk.js/Sources/IO/Core/HttpDataSetReader'; import vtkVolume from 'vtk.js/Sources/Rendering/Core/Volume'; import vtkVolumeMapper from 'vtk.js/Sources/Rendering/Core/VolumeMapper'; import vtkInteractorStyleMPRSlice from 'vtk.js/Sources/Interaction/Style/InteractorStyleMPRSlice'; import vtkImageData from 'vtk.js/Sources/Common/DataModel/ImageData'; import vtkDataArray from 'vtk.js/Sources/Common/Core/DataArray'; import vtkColorTransferFunction from 'vtk.js/Sources/Rendering/Core/ColorTransferFunction'; import vtkPiecewiseFunction from 'vtk.js/Sources/Common/DataModel/PiecewiseFunction'; const fullScreenRenderWindow = vtkFullScreenRenderWindow.newInstance({ background: [0.3, 0.3, 0.3], }); const renderWindow = fullScreenRenderWindow.getRenderWindow(); const renderer = fullScreenRenderWindow.getRenderer(); const istyle = vtkInteractorStyleMPRSlice.newInstance(); renderWindow.getInteractor().setInteractorStyle(istyle); global.fullScreen = fullScreenRenderWindow; global.renderWindow = renderWindow; // ---------------------------------------------------------------------------- // Volume rendering // ---------------------------------------------------------------------------- const actor = vtkVolume.newInstance(); const mapper = vtkVolumeMapper.newInstance(); actor.setMapper(mapper); const ofun = vtkPiecewiseFunction.newInstance(); ofun.addPoint(0, 0); ofun.addPoint(1, 1.0); actor.getProperty().setScalarOpacity(0, ofun); function createLabelPipeline(backgroundImageData) { // Create a labelmap image the same dimensions as our background volume. const labelMapData = vtkImageData.newInstance( backgroundImageData.get('spacing', 'origin', 'direction') ); labelMapData.computeTransforms(); const values = new Uint8Array(backgroundImageData.getNumberOfPoints()); const dataArray = vtkDataArray.newInstance({ numberOfComponents: 1, // labelmap with single component values, }); labelMapData.getPointData().setScalars(dataArray); labelMapData.setDimensions(...backgroundImageData.getDimensions()); labelMapData.setSpacing(...backgroundImageData.getSpacing()); labelMapData.setOrigin(...backgroundImageData.getOrigin()); labelMapData.setDirection(...backgroundImageData.getDirection()); const labelMap = { actor: vtkVolume.newInstance(), mapper: vtkVolumeMapper.newInstance(), imageData: labelMapData, cfun: vtkColorTransferFunction.newInstance(), ofun: vtkPiecewiseFunction.newInstance(), }; // Labelmap pipeline labelMap.mapper.setInputData(labelMapData); 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.ofun.addPoint(0, 0); labelMap.ofun.addPoint(1, 0.5, 0.5, 1.0); // Red will have an opacity of 0.2. labelMap.ofun.addPoint(2, 0.5, 0.5, 1.0); // Green will have an opacity of 0.2. labelMap.ofun.setClamping(false); labelMap.actor.getProperty().setRGBTransferFunction(0, labelMap.cfun); labelMap.actor.getProperty().setScalarOpacity(0, labelMap.ofun); labelMap.actor.getProperty().setInterpolationTypeToNearest(); labelMap.actor.getProperty().setUseLabelOutline(true); labelMap.actor.getProperty().setLabelOutlineThickness(3); return labelMap; } function fillBlobForThreshold(imageData, backgroundImageData) { const dims = imageData.getDimensions(); const values = imageData.getPointData().getScalars().getData(); const backgroundValues = backgroundImageData .getPointData() .getScalars() .getData(); const size = dims[0] * dims[1] * dims[2]; // Head const headThreshold = [324, 1524]; for (let i = 0; i < size; i++) { if ( backgroundValues[i] >= headThreshold[0] && backgroundValues[i] < headThreshold[1] ) { values[i] = 1; } } // Bone const boneThreshold = [1200, 2324]; for (let i = 0; i < size; i++) { if ( backgroundValues[i] >= boneThreshold[0] && backgroundValues[i] < boneThreshold[1] ) { values[i] = 2; } } imageData.getPointData().getScalars().setData(values); } const reader = vtkHttpDataSetReader.newInstance({ fetchGzip: true, }); reader .setUrl(`${__BASE_PATH__}/data/volume/headsq.vti`, { loadData: true }) .then(() => { const data = reader.getOutputData(); mapper.setInputData(data); const labelMap = createLabelPipeline(data); const sourceDataRGBTransferFunction = actor .getProperty() .getRGBTransferFunction(0); sourceDataRGBTransferFunction.setMappingRange(324, 2324); fillBlobForThreshold(labelMap.imageData, data); // Set interactor style volume mapper after mapper sets input data istyle.setVolumeMapper(mapper); renderer.addVolume(actor); renderer.addVolume(labelMap.actor); renderer.getActiveCamera().setViewUp(1, 0, 0); renderWindow.render(); });