Segmentation UI for VTKjs (#1685)
* Add single viewport configuration * Multiple viewport configuration * Improve performance by using independent set methods * Add jump to slice command * Add context configuration * Cache panel visibility * Fix sync between vtk and cornerstone * Remove apis index * Add approach * Add loading to update volumes * Fix broken configuration * Bump vtk version * Use loading label * Update cy tests after vtk loading label changed * Remove loading for segs
This commit is contained in:
1 parent
19a8e71317
commit
42c22df1b6
22 files changed
+516
-173
No files matched your search
@@ -5,10 +5,13 @@ import {
|
||||
vtkInteractorStyleMPRRotate,
|
||||
vtkSVGCrosshairsWidget,
|
||||
} from 'react-vtkjs-viewport';
|
||||
|
||||
import { getImageData } from 'react-vtkjs-viewport';
|
||||
import { vec3 } from 'gl-matrix';
|
||||
import setMPRLayout from './utils/setMPRLayout.js';
|
||||
import setViewportToVTK from './utils/setViewportToVTK.js';
|
||||
import Constants from 'vtk.js/Sources/Rendering/Core/VolumeMapper/Constants.js';
|
||||
import OHIFVTKViewport from './OHIFVTKViewport';
|
||||
import vtkCoordinate from 'vtk.js/Sources/Rendering/Core/Coordinate';
|
||||
|
||||
const { BlendMode } = Constants;
|
||||
|
||||
@@ -34,7 +37,6 @@ const commandsModule = ({ commandsManager }) => {
|
||||
}
|
||||
|
||||
const displaySet = viewportSpecificData[activeViewportIndex];
|
||||
|
||||
let api;
|
||||
if (!api) {
|
||||
try {
|
||||
@@ -99,6 +101,20 @@ const commandsModule = ({ commandsManager }) => {
|
||||
});
|
||||
}
|
||||
|
||||
const _convertModelToWorldSpace = (position, vtkImageData) => {
|
||||
const indexToWorld = vtkImageData.getIndexToWorld();
|
||||
const pos = vec3.create();
|
||||
|
||||
position[0] += 0.5; /* Move to the centre of the voxel. */
|
||||
position[1] += 0.5; /* Move to the centre of the voxel. */
|
||||
position[2] += 0.5; /* Move to the centre of the voxel. */
|
||||
|
||||
vec3.set(pos, position[0], position[1], position[2]);
|
||||
vec3.transformMat4(pos, pos, indexToWorld);
|
||||
|
||||
return pos;
|
||||
};
|
||||
|
||||
const actions = {
|
||||
getVtkApis: ({ index }) => {
|
||||
return apis[index];
|
||||
@@ -124,6 +140,119 @@ const commandsModule = ({ commandsManager }) => {
|
||||
|
||||
_setView(api, [0, 1, 0], [0, 0, 1]);
|
||||
},
|
||||
requestNewSegmentation: async ({ viewports }) => {
|
||||
const allViewports = Object.values(viewports.viewportSpecificData);
|
||||
const promises = allViewports.map(async (viewport, viewportIndex) => {
|
||||
let api = apis[viewportIndex];
|
||||
|
||||
if (!api) {
|
||||
api = await _getActiveViewportVTKApi(viewports);
|
||||
apis[viewportIndex] = api;
|
||||
}
|
||||
|
||||
api.requestNewSegmentation();
|
||||
api.updateImage();
|
||||
});
|
||||
await Promise.all(promises);
|
||||
},
|
||||
jumpToSlice: async ({
|
||||
viewports,
|
||||
studies,
|
||||
StudyInstanceUID,
|
||||
displaySetInstanceUID,
|
||||
SOPClassUID,
|
||||
SOPInstanceUID,
|
||||
segmentNumber,
|
||||
frameIndex,
|
||||
frame,
|
||||
done = () => { }
|
||||
}) => {
|
||||
let api = apis[viewports.activeViewportIndex];
|
||||
|
||||
if (!api) {
|
||||
api = await _getActiveViewportVTKApi(viewports);
|
||||
apis[viewports.activeViewportIndex] = api;
|
||||
}
|
||||
|
||||
const stack = OHIFVTKViewport.getCornerstoneStack(
|
||||
studies,
|
||||
StudyInstanceUID,
|
||||
displaySetInstanceUID,
|
||||
SOPClassUID,
|
||||
SOPInstanceUID,
|
||||
frameIndex,
|
||||
);
|
||||
|
||||
const imageDataObject = getImageData(stack.imageIds, displaySetInstanceUID);
|
||||
|
||||
let pixelIndex = 0;
|
||||
let x = 0;
|
||||
let y = 0;
|
||||
let count = 0;
|
||||
|
||||
const rows = imageDataObject.dimensions[1];
|
||||
const cols = imageDataObject.dimensions[0];
|
||||
|
||||
for (let j = 0; j < rows; j++) {
|
||||
for (let i = 0; i < cols; i++) {
|
||||
// [i, j] =
|
||||
const pixel = frame.pixelData[pixelIndex];
|
||||
if (pixel === segmentNumber) {
|
||||
x += i;
|
||||
y += j;
|
||||
count++;
|
||||
}
|
||||
pixelIndex++;
|
||||
}
|
||||
}
|
||||
x /= count;
|
||||
y /= count;
|
||||
|
||||
const position = [x, y, frameIndex];
|
||||
const worldPos = _convertModelToWorldSpace(position, imageDataObject.vtkImageData);
|
||||
|
||||
api.svgWidgets.crosshairsWidget.moveCrosshairs(worldPos, apis);
|
||||
done();
|
||||
},
|
||||
setSegmentationConfiguration: async ({
|
||||
viewports,
|
||||
globalOpacity,
|
||||
visible,
|
||||
renderOutline,
|
||||
outlineThickness,
|
||||
}) => {
|
||||
const allViewports = Object.values(viewports.viewportSpecificData);
|
||||
const promises = allViewports.map(async (viewport, viewportIndex) => {
|
||||
let api = apis[viewportIndex];
|
||||
|
||||
if (!api) {
|
||||
api = await _getActiveViewportVTKApi(viewports);
|
||||
apis[viewportIndex] = api;
|
||||
}
|
||||
|
||||
api.setGlobalOpacity(globalOpacity);
|
||||
api.setVisibility(visible);
|
||||
api.setOutlineThickness(outlineThickness);
|
||||
api.setOutlineRendering(renderOutline);
|
||||
api.updateImage();
|
||||
});
|
||||
await Promise.all(promises);
|
||||
},
|
||||
setSegmentConfiguration: async ({ viewports, visible, segmentNumber }) => {
|
||||
const allViewports = Object.values(viewports.viewportSpecificData);
|
||||
const promises = allViewports.map(async (viewport, viewportIndex) => {
|
||||
let api = apis[viewportIndex];
|
||||
|
||||
if (!api) {
|
||||
api = await _getActiveViewportVTKApi(viewports);
|
||||
apis[viewportIndex] = api;
|
||||
}
|
||||
|
||||
api.setSegmentVisibility(segmentNumber, visible);
|
||||
api.updateImage();
|
||||
});
|
||||
await Promise.all(promises);
|
||||
},
|
||||
enableRotateTool: () => {
|
||||
apis.forEach(api => {
|
||||
const istyle = vtkInteractorStyleMPRRotate.newInstance();
|
||||
@@ -280,6 +409,26 @@ const commandsModule = ({ commandsManager }) => {
|
||||
window.vtkActions = actions;
|
||||
|
||||
const definitions = {
|
||||
requestNewSegmentation: {
|
||||
commandFn: actions.requestNewSegmentation,
|
||||
storeContexts: ['viewports'],
|
||||
options: {},
|
||||
},
|
||||
jumpToSlice: {
|
||||
commandFn: actions.jumpToSlice,
|
||||
storeContexts: ['viewports'],
|
||||
options: {},
|
||||
},
|
||||
setSegmentationConfiguration: {
|
||||
commandFn: actions.setSegmentationConfiguration,
|
||||
storeContexts: ['viewports'],
|
||||
options: {},
|
||||
},
|
||||
setSegmentConfiguration: {
|
||||
commandFn: actions.setSegmentConfiguration,
|
||||
storeContexts: ['viewports'],
|
||||
options: {},
|
||||
},
|
||||
axial: {
|
||||
commandFn: actions.axial,
|
||||
storeContexts: ['viewports'],
|
||||
|
||||
Reference in new issue
Block a user