Help to displaying a Volume_3D Viewport of NIFTI
I’m running an example displaying a volume stack for segmentation read from a .nii file. I can currently run this example locally. However, I want to display it in a 3D Viewport, possibly using a tool like RotateTrackball. Can anyone help me with this? Thank you very much.
Here is my current example
import {
RenderingEngine,
Enums,
init as csInit,
volumeLoader,
setVolumesForViewports,
eventTarget,
imageLoader,
} from '@cornerstonejs/core';
import * as cornerstoneTools from '@cornerstonejs/tools';
import {
Enums as NiftiEnums,
cornerstoneNiftiImageLoader,
createNiftiImageIdsAndCacheMetadata,
} from '@cornerstonejs/nifti-volume-loader';
import { addDropdownToToolbar, initDemo } from '../../../../utils/demo/helpers';
const {
ToolGroupManager,
StackScrollTool,
ZoomTool,
Enums: csToolsEnums,
WindowLevelTool,
PanTool,
} = cornerstoneTools;
const { MouseBindings } = csToolsEnums;
// This is for debugging purposes
console.warn(
'Click on index.ts to open source code for this example --------->'
);
const size = '500px';
const content = document.getElementById('content');
const viewportGrid = document.createElement('div');
viewportGrid.style.display = 'flex';
viewportGrid.style.display = 'flex';
viewportGrid.style.flexDirection = 'row';
const element1 = document.createElement('div');
const element2 = document.createElement('div');
const element3 = document.createElement('div');
element1.style.width = size;
element1.style.height = size;
element2.style.width = size;
element2.style.height = size;
element3.style.width = size;
element3.style.height = size;
element1.oncontextmenu = () => false;
element2.oncontextmenu = () => false;
element3.oncontextmenu = () => false;
viewportGrid.appendChild(element1);
viewportGrid.appendChild(element2);
viewportGrid.appendChild(element3);
content.appendChild(viewportGrid);
const pr = document.createElement('p');
pr.innerHTML = 'Nifti Loading Progress:';
const progress = document.createElement('progress');
progress.value = 0;
progress.max = 100;
content.appendChild(pr);
content.appendChild(progress);
const viewportId1 = 'CT_NIFTI_AXIAL';
const viewportId2 = 'CT_NIFTI_SAGITTAL';
const viewportId3 = 'CT_NIFTI_CORONAL';
const viewportIds = [viewportId1, viewportId2, viewportId3];
const toolsNames = [
WindowLevelTool.toolName,
PanTool.toolName,
StackScrollTool.toolName,
ZoomTool.toolName,
];
let selectedToolName = toolsNames[0];
const toolGroupId = 'STACK_TOOL_GROUP_ID';
addDropdownToToolbar({
options: { values: toolsNames, defaultValue: selectedToolName },
onSelectedValueChange: (newSelectedToolNameAsStringOrNumber) => {
const newSelectedToolName = String(newSelectedToolNameAsStringOrNumber);
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId);
toolGroup.setToolActive(newSelectedToolName, {
bindings: [
{
mouseButton: MouseBindings.Primary, // Left Click
},
],
});
toolGroup.setToolPassive(selectedToolName);
selectedToolName = <string>newSelectedToolName;
},
});
const niftiURL = 'http://localhost:8001/test-segmentation';
const volumeLoaderScheme = 'cornerstoneStreamingImageVolume'; // Loader id which defines which volume loader to use
const volumeId = `${volumeLoaderScheme}:${niftiURL}`; // VolumeId with loader id + volume id
async function setup() {
await initDemo();
imageLoader.registerImageLoader('nifti', cornerstoneNiftiImageLoader);
const imageIds = await createNiftiImageIdsAndCacheMetadata({ url: niftiURL });
// Add tools to Cornerstone3D
cornerstoneTools.addTool(WindowLevelTool);
cornerstoneTools.addTool(PanTool);
cornerstoneTools.addTool(StackScrollTool);
cornerstoneTools.addTool(ZoomTool);
const toolGroup = ToolGroupManager.createToolGroup(toolGroupId);
toolGroup.addTool(WindowLevelTool.toolName);
toolGroup.addTool(PanTool.toolName);
toolGroup.addTool(ZoomTool.toolName);
toolGroup.addTool(StackScrollTool.toolName);
toolGroup.setToolActive(WindowLevelTool.toolName, {
bindings: [
{
mouseButton: MouseBindings.Primary, // Left Click
},
],
});
toolGroup.setToolActive(ZoomTool.toolName, {
bindings: [
{
mouseButton: MouseBindings.Secondary, // Right Click
},
],
});
toolGroup.setToolActive(PanTool.toolName, {
bindings: [
{
mouseButton: MouseBindings.Auxiliary, // Right Click
},
],
});
toolGroup.setToolActive(StackScrollTool.toolName, {
bindings: [
{
mouseButton: MouseBindings.Wheel,
},
],
});
const renderingEngineId = 'myRenderingEngine';
const renderingEngine = new RenderingEngine(renderingEngineId);
const viewportInputArray = [
{
viewportId: viewportId1,
type: Enums.ViewportType.ORTHOGRAPHIC,
element: element1,
defaultOptions: {
orientation: Enums.OrientationAxis.AXIAL,
},
},
{
viewportId: viewportId2,
type: Enums.ViewportType.ORTHOGRAPHIC,
element: element2,
defaultOptions: {
orientation: Enums.OrientationAxis.SAGITTAL,
},
},
{
viewportId: viewportId3,
type: Enums.ViewportType.ORTHOGRAPHIC,
element: element3,
defaultOptions: {
orientation: Enums.OrientationAxis.CORONAL,
},
},
];
renderingEngine.setViewports(viewportInputArray);
// Set the tool group on the viewports
viewportIds.forEach((viewportId) =>
toolGroup.addViewport(viewportId, renderingEngineId)
);
const updateProgress = (evt) => {
const { data } = evt.detail;
if (!data) {
return;
}
const { total, loaded } = data;
if (!total) {
return;
}
const progress = Math.round((loaded / total) * 100);
const element = document.querySelector('progress');
element.value = progress;
};
eventTarget.addEventListener(
NiftiEnums.Events.NIFTI_VOLUME_PROGRESS,
updateProgress
);
// This will load the nifti file, no need to call .load again for nifti
const volume = await volumeLoader.createAndCacheVolume(volumeId, {
imageIds,
});
await volume.load();
const segmentationId = 'AI_LABELMAP_ID';
// 2. Thêm volume NIfTI vào hệ thống Segmentation của Cornerstone
await cornerstoneTools.segmentation.addSegmentations([
{
segmentationId,
representation: {
// Khai báo đây là kiểu Labelmap (tô màu theo nhãn 1, 2, 3...)
type: csToolsEnums.SegmentationRepresentations.Labelmap,
data: {
volumeId: volumeId,
},
},
},
]);
const segmentationRepresentationRuns = viewportIds.map((vId) =>
cornerstoneTools.segmentation.addSegmentationRepresentations(vId, [
{
segmentationId,
type: csToolsEnums.SegmentationRepresentations.Labelmap,
},
])
);
await Promise.all(segmentationRepresentationRuns);
setVolumesForViewports(
renderingEngine,
[{ volumeId }],
viewportInputArray.map((v) => v.viewportId)
);
renderingEngine.render();
}
setup();
Additionally, I have a question: Does Nifti Volume Loader support reading files that have been compressed into .nii.gz format?