Skip to content

Commit ecae76f

Browse files
committed
fix(loadImageData): Scale to Modality pixels or SUV when inserting slices into volume (0.0.12)
1 parent 9254c8c commit ecae76f

File tree

8 files changed

+254
-149
lines changed

8 files changed

+254
-149
lines changed

example/package.json

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@
1515
"bfj": "6.1.1",
1616
"case-sensitive-paths-webpack-plugin": "2.2.0",
1717
"chalk": "2.4.2",
18-
"cornerstone-core": "^2.2.8",
19-
"cornerstone-tools": "3.11.0",
20-
"cornerstone-wado-image-loader": "^2.2.3",
18+
"cornerstone-core": "^2.3.0",
19+
"cornerstone-tools": "3.19.1",
20+
"cornerstone-wado-image-loader": "^3.0.0",
2121
"css-loader": "2.1.1",
2222
"dicom-parser": "^1.8.3",
23-
"dicomweb-client": "^0.4.4",
23+
"dicomweb-client": "^0.5.2",
2424
"dotenv": "8.0.0",
2525
"dotenv-expand": "5.1.0",
2626
"eslint": "5.16.0",
@@ -49,7 +49,7 @@
4949
"prop-types": "^15.7.2",
5050
"react": "^16.8.6",
5151
"react-app-polyfill": "^1.0.1",
52-
"react-cornerstone-viewport": "0.1.29",
52+
"react-cornerstone-viewport": "0.2.2",
5353
"react-dev-utils": "^7.0.5",
5454
"react-dom": "^16.8.6",
5555
"react-resize-detector": "^4.1.3",
@@ -61,17 +61,16 @@
6161
"style-loader": "0.23.1",
6262
"terser-webpack-plugin": "1.2.4",
6363
"url-loader": "1.1.2",
64-
"vtk.js": "^8.13.0",
64+
"vtk.js": "^11.0.1",
6565
"webpack": "4.32.2",
6666
"webpack-dev-server": "3.4.1",
6767
"webpack-manifest-plugin": "2.0.4",
6868
"workbox-webpack-plugin": "4.3.1"
6969
},
7070
"scripts": {
7171
"version": "node -p -e \"'export default \\'' + require('./package.json').version + '\\';'\" > src/version.js",
72-
"copy:webworkers": "cpx \"node_modules/cornerstone-wado-image-loader/dist/*.min.js*\" public",
73-
"start": "yarn run copy:webworkers && node scripts/start.js",
74-
"build": "yarn run copy:webworkers && node scripts/build.js",
72+
"start": "node scripts/start.js",
73+
"build": "node scripts/build.js",
7574
"test": "node scripts/test.js --env=jsdom"
7675
},
7776
"jest": {

example/src/VTKFusionExample.js

Lines changed: 49 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ import vtkColorMaps from 'vtk.js/Sources/Rendering/Core/ColorTransferFunction/Co
1717

1818
import presets from './presets.js'
1919

20+
window.cornerstoneWADOImageLoader = cornerstoneWADOImageLoader;
21+
2022
const url = 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs'
23+
//const url = 'http://localhost:8080/dcm4chee-arc/aets/DCM4CHEE/rs'
2124
const client = new api.DICOMwebClient({ url })
2225
const studyInstanceUID =
2326
'1.3.6.1.4.1.14519.5.2.1.2744.7002.373729467545468642229382466905'
@@ -43,8 +46,19 @@ function createActorMapper(imageData) {
4346
}
4447

4548
function createCT2dPipeline(imageData) {
46-
const { actor, mapper } = createActorMapper(imageData)
47-
mapper.setSampleDistance(5.0)
49+
const { actor } = createActorMapper(imageData)
50+
const cfun = vtkColorTransferFunction.newInstance()
51+
/*
52+
0: { description: 'Soft tissue', window: 400, level: 40 },
53+
1: { description: 'Lung', window: 1500, level: -600 },
54+
2: { description: 'Liver', window: 150, level: 90 },
55+
3: { description: 'Bone', window: 2500, level: 480 },
56+
4: { description: 'Brain', window: 80, level: 40 },*/
57+
const preset = vtkColorMaps.getPresetByName('Grayscale')
58+
cfun.applyColorMap(preset)
59+
cfun.setMappingRange(-360, 440)
60+
61+
actor.getProperty().setRGBTransferFunction(0, cfun)
4862

4963
return actor
5064
}
@@ -53,22 +67,18 @@ function createPET2dPipeline(imageData, petColorMapId) {
5367
const { actor, mapper } = createActorMapper(imageData)
5468
mapper.setSampleDistance(5.0)
5569

56-
const range = imageData
57-
.getPointData()
58-
.getScalars()
59-
.getRange()
60-
6170
const cfun = vtkColorTransferFunction.newInstance()
6271
const preset = vtkColorMaps.getPresetByName(petColorMapId)
6372
cfun.applyColorMap(preset)
64-
cfun.setMappingRange(range[0], (range[1] * 2) / 5)
73+
cfun.setMappingRange(0, 5)
6574

6675
actor.getProperty().setRGBTransferFunction(0, cfun)
6776

6877
// Create scalar opacity function
6978
const ofun = vtkPiecewiseFunction.newInstance()
70-
ofun.addPoint(0.0, 0.0)
71-
ofun.addPoint(range[1] / 4, 0.3)
79+
ofun.addPoint(0, 0.0)
80+
ofun.addPoint(0.1, 0.9);
81+
ofun.addPoint(5, 1.0);
7282

7383
actor.getProperty().setScalarOpacity(0, ofun)
7484

@@ -117,12 +127,6 @@ function applyPointsToRGBFunction(points, range, cfun) {
117127
}
118128

119129
function applyPreset(actor, preset) {
120-
/*const imageData = actor.getMapper().getInputData()
121-
const dataRange = imageData
122-
.getPointData()
123-
.getScalars()
124-
.getRange()*/
125-
126130
// Create color transfer function
127131
const colorTransferArray = preset.colorTransfer
128132
.split(' ')
@@ -134,7 +138,7 @@ function applyPreset(actor, preset) {
134138
const width = shiftRange[1] - shiftRange[0];
135139

136140
// TODO: Something about the rescaling is still very wrong
137-
const shift = -1000;//dataRange[0];
141+
const shift = shiftRange[0];
138142
min += shift;
139143

140144
const cfun = vtkColorTransferFunction.newInstance()
@@ -161,7 +165,7 @@ function applyPreset(actor, preset) {
161165

162166
const ofun = vtkPiecewiseFunction.newInstance()
163167
const normPoints = [];
164-
for (let i = 0; i < scalarOpacityArray.length; i+=2) {
168+
for (let i = 0; i < scalarOpacityArray.length; i += 2) {
165169
let value = scalarOpacityArray[i]
166170
const opacity = scalarOpacityArray[i + 1]
167171

@@ -227,7 +231,7 @@ function createCT3dPipeline(imageData, ctTransferFunctionPresetId) {
227231

228232
applyPreset(actor, preset)
229233

230-
actor.getProperty().setScalarOpacityUnitDistance(0, 4.5)
234+
actor.getProperty().setScalarOpacityUnitDistance(0, 2.5)
231235

232236
return actor
233237
}
@@ -246,22 +250,21 @@ function createPET3dPipeline(imageData, petColorMapId) {
246250
mapper.setSampleDistance(sampleDistance);
247251

248252
// Apply colormap
249-
const range = imageData
250-
.getPointData()
251-
.getScalars()
252-
.getRange()
253253
const cfun = vtkColorTransferFunction.newInstance()
254-
cfun.applyColorMap(vtkColorMaps.getPresetByName(petColorMapId))
255-
cfun.setMappingRange(range[0], (range[1] * 3) / 5)
254+
const preset = vtkColorMaps.getPresetByName(petColorMapId)
255+
cfun.applyColorMap(preset)
256+
cfun.setMappingRange(0, 5)
256257

257258
actor.getProperty().setRGBTransferFunction(0, cfun)
258259

259260
// Create scalar opacity function
260261
const ofun = vtkPiecewiseFunction.newInstance()
261262
ofun.addPoint(0.0, 0.0)
262-
ofun.addPoint(range[1] / 3, 0.2)
263+
ofun.addPoint(0.1, 0.1)
264+
ofun.addPoint(5, 0.2)
263265

264266
actor.getProperty().setScalarOpacity(0, ofun)
267+
actor.getProperty().setScalarOpacityUnitDistance(0, 2.5)
265268

266269
return actor
267270
}
@@ -321,12 +324,12 @@ class VTKFusionExample extends Component {
321324
let ctImageIds = imageIds.filter(imageId =>
322325
imageId.includes(ctSeriesInstanceUID)
323326
)
324-
ctImageIds = ctImageIds//.slice(0, 100)
327+
//ctImageIds = ctImageIds.slice(0, ctImageIds.length / 4)
325328

326329
let petImageIds = imageIds.filter(imageId =>
327330
imageId.includes(petSeriesInstanceUID)
328331
)
329-
petImageIds = petImageIds.slice(0, 100)
332+
petImageIds = petImageIds.slice(0, petImageIds.length / 4)
330333

331334
const ctImageDataPromise = loadDataset(ctImageIds, 'ctDisplaySet')
332335
const petImageDataPromise = loadDataset(petImageIds, 'petDisplaySet')
@@ -378,19 +381,29 @@ class VTKFusionExample extends Component {
378381
const actor2d = this.state.volumes[1]
379382
const actor3d = this.state.volumeRenderingVolumes[1]
380383

381-
const imageData = actor2d.getMapper().getInputData()
382-
const range = imageData
383-
.getPointData()
384-
.getScalars()
385-
.getRange()
386-
387384
const preset = vtkColorMaps
388385
.getPresetByName(petColorMapId);
389386

390-
[(actor2d, actor3d)].forEach(actor => {
387+
[actor2d, actor3d].forEach(actor => {
388+
if (!actor) {
389+
return;
390+
}
391+
391392
const cfun = actor.getProperty().getRGBTransferFunction(0)
393+
394+
// TODO: Looks like this is returned by reference and mutated when
395+
// applyColorMap is run, so we are copying the array with .slice().
396+
// - Bit surprised we have to do this though. I wonder where else this is
397+
// causing issues
398+
const cRange = cfun.getMappingRange().slice();
392399
cfun.applyColorMap(preset)
393-
cfun.setMappingRange(range[0], (range[1] * 2) / 5)
400+
401+
const newCfun = vtkColorTransferFunction.newInstance()
402+
newCfun.applyColorMap(preset);
403+
newCfun.setMappingRange(cRange[0], cRange[1])
404+
405+
// TODO: Why doesn't mutating the current RGBTransferFunction work?
406+
actor.getProperty().setRGBTransferFunction(0, newCfun);
394407
})
395408

396409
this.setState({

example/src/initCornerstone.js

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,22 +28,20 @@ cornerstoneTools.toolColors.setActiveColor('rgb(0, 255, 0)');
2828

2929
cornerstoneTools.store.state.touchProximity = 40;
3030

31-
const config = {
32-
maxWebWorkers: 4,//Math.max(navigator.hardwareConcurrency - 1, 1),
33-
startWebWorkersOnDemand: true,
34-
webWorkerPath: '/cornerstoneWADOImageLoaderWebWorker.min.js',
35-
taskConfiguration: {
36-
decodeTask: {
37-
loadCodecsOnStartup: true,
38-
initializeCodecsOnStartup: false,
39-
codecsPath: '/cornerstoneWADOImageLoaderCodecs.min.js',
40-
usePDFJS: false,
41-
strict: false
42-
}
43-
}
44-
};
45-
46-
cornerstoneWADOImageLoader.webWorkerManager.initialize(config);
31+
window.cornerstone = cornerstone;
4732

4833
cornerstoneWADOImageLoader.external.cornerstone = cornerstone;
4934
cornerstoneWADOImageLoader.external.dicomParser = dicomParser;
35+
36+
var config = {
37+
maxWebWorkers: navigator.hardwareConcurrency || 1,
38+
startWebWorkersOnDemand : true,
39+
taskConfiguration: {
40+
decodeTask: {
41+
initializeCodecsOnStartup: false,
42+
usePDFJS: false,
43+
strict: false,
44+
},
45+
}
46+
};
47+
cornerstoneWADOImageLoader.webWorkerManager.initialize(config);

0 commit comments

Comments
 (0)