Open MrWerton opened 2 months ago
I think you can try the new setViewReference which accept the sliceIndex
@sedghi I try, but this not work. You can help-me?
My full code
My function to update index
can you please add the code instead of screenshot
@sedghi this is the repo: https://github.com/MrWerton/cornerstone-dicom-viewer
and the code:
import React, { useEffect, useRef } from "react";
import "./App.css";
import { createImageIdsAndCacheMetaData, initDemo } from "./core/helpers";
import {
Enums,
RenderingEngine,
StackViewport,
Types,
VolumeViewport,
cache,
getRenderingEngine,
setVolumesForViewports,
volumeLoader,
} from "@cornerstonejs/core";
import * as tools from "@cornerstonejs/tools";
const { ViewportType } = Enums;
const renderingEngineId = "myRenderingEngine";
const volumeId = "cornerstoneStreamingImageVolume:myVolume";
const viewportId = "CT_AXIAL";
const studyInstanceUID = "1.2.640.0.31017449.3.2.101.9.1454914.1230185";
const seriesInstanceUID =
"1.2.840.113619.2.507.7636706.3695232.30418.1697638227.903";
const wadoRsRoot = "http://localhost:8080/orthanc/dicom-web";
const { STACK_NEW_IMAGE, VOLUME_NEW_IMAGE } = Enums.Events;
const App: React.FC = () => {
const isInitialized = useRef(false);
const element = useRef<HTMLDivElement>(null);
const range = useRef<HTMLInputElement>(null);
useEffect(() => {
if (!isInitialized.current) {
isInitialized.current = true;
initializeDemo();
}
}, []);
const initializeDemo = async () => {
try {
await initDemo();
initializeTools();
await renderVolumeOrStack();
} catch (error) {
console.error("Initialization failed:", error);
}
};
const initializeTools = () => {
tools.addTool(tools.WindowLevelTool);
tools.addTool(tools.ZoomTool);
tools.addTool(tools.StackScrollMouseWheelTool);
};
const renderVolumeOrStack = async () => {
const renderingEngine = new RenderingEngine(renderingEngineId);
const { imageIds, metadataTags } = await createImageIdsAndCacheMetaData({
StudyInstanceUID: studyInstanceUID,
SeriesInstanceUID: seriesInstanceUID,
wadoRsRoot: wadoRsRoot,
});
console.log(metadataTags);
if (range.current) {
range.current.max = (imageIds.length - 1).toString();
}
if (imageIds.length < 10) {
await renderVolume(renderingEngine, imageIds);
} else {
await renderStack(renderingEngine, imageIds);
}
console.log("Cache Size:", cache.getCacheSize());
console.log("Bytes Available:", cache.getBytesAvailable());
};
const renderVolume = async (
renderingEngine: RenderingEngine,
imageIds: string[]
) => {
const volume = await volumeLoader.createAndCacheVolume(volumeId, {
imageIds,
});
element.current!.addEventListener(VOLUME_NEW_IMAGE, ((
evt: Types.EventTypes.VolumeNewImageEvent
) => {
const { imageIndex, numberOfSlices } = evt.detail;
console.log(
"Volume New Image",
imageIndex,
numberOfSlices,
imageIds.length
);
range.current!.value = (imageIndex - 1).toString();
}) as EventListener);
const viewportInput = {
viewportId,
element: element.current!,
type: ViewportType.ORTHOGRAPHIC,
defaultOptions: {
orientation: Enums.OrientationAxis.AXIAL,
},
};
renderingEngine.enableElement(viewportInput);
const viewport = renderingEngine.getViewport(viewportId) as VolumeViewport;
const toolGroup = tools.ToolGroupManager.createToolGroup("3d-group")!;
// addManipulationBindings(toolGroup, { is3DViewport: true });
toolGroup.addTool(tools.WindowLevelTool.toolName);
toolGroup.addTool(tools.ZoomTool.toolName);
toolGroup.addTool(tools.StackScrollMouseWheelTool.toolName);
toolGroup.addViewport(viewportId, renderingEngineId);
setToolBindings(toolGroup);
await volume.load();
await setVolumesForViewports(
renderingEngine,
[{ volumeId }],
[viewportId]
).then(() => {
viewport.setProperties({
orientation: Enums.OrientationAxis.AXIAL,
});
viewport.render();
});
renderingEngine.renderViewports([viewportId]);
console.log("Volume set for viewport", viewport);
};
const renderStack = async (
renderingEngine: RenderingEngine,
imageIds: string[]
) => {
element.current!.addEventListener(STACK_NEW_IMAGE, ((
evt: Types.EventTypes.StackNewImageEvent
) => {
const { imageIdIndex } = evt.detail;
range.current!.value = imageIdIndex.toString();
}) as EventListener);
const viewportInput = {
viewportId,
element: element.current!,
type: ViewportType.STACK,
};
renderingEngine.enableElement(viewportInput);
const viewport = renderingEngine.getViewport(viewportId) as StackViewport;
viewport.setStack(imageIds);
const toolGroup = tools.ToolGroupManager.createToolGroup("2d-group")!;
toolGroup.addTool(tools.WindowLevelTool.toolName);
toolGroup.addTool(tools.ZoomTool.toolName);
toolGroup.addTool(tools.StackScrollMouseWheelTool.toolName);
toolGroup.addViewport(viewportId, renderingEngineId);
setToolBindings(toolGroup);
viewport.render();
};
const setToolBindings = (toolGroup: tools.Types.IToolGroup) => {
toolGroup.setToolActive(tools.WindowLevelTool.toolName, {
bindings: [{ mouseButton: tools.Enums.MouseBindings.Primary }],
});
toolGroup.setToolActive(tools.ZoomTool.toolName, {
bindings: [{ mouseButton: tools.Enums.MouseBindings.Secondary }],
});
toolGroup.setToolActive(tools.StackScrollMouseWheelTool.toolName);
};
const handleRangeChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const value = Number(event.target.value);
updateImageIndex(value);
};
//here is the function to update the image index
const updateImageIndex = (newImageIdIndex: number) => {
const renderingEngine = getRenderingEngine(renderingEngineId);
if (renderingEngine) {
const viewport = renderingEngine.getViewport(viewportId)!;
if (viewport instanceof StackViewport) {
//here works for stack
const numImages = viewport.getImageIds().length;
newImageIdIndex = Math.min(newImageIdIndex, numImages - 1);
viewport.setImageIdIndex(newImageIdIndex);
viewport.render();
} else if (viewport instanceof VolumeViewport) {
viewport.setViewReference({
FrameOfReferenceUID: viewport.getFrameOfReferenceUID(),
sliceIndex: newImageIdIndex,
volumeId: volumeId,
referencedImageId: viewport.getCurrentImageId(),
});
viewport.render();
console.log("VolumeViewport", viewport.getCurrentImageId());
}
}
};
return (
<>
<input ref={range} type="range" onChange={handleRangeChange} />
<div style={{ width: "900px", height: "400px" }} ref={element} />
</>
);
};
export default App;
@sedghi Thank you very much, it worked. I needed to define the viewplane. If you could help me with one more thing, I would be eternally grateful. In my code, I am checking if it is a stack or volume by the number of image IDs, but I don't think this is correct. I wanted to know if there is a more correct way to verify if the image can or cannot be rendered as a volume, because some images I was testing do not render as volume but do render as stack. Could you help me with this? Thank you very much in advance!
if (imageIds.length > 10) {
await renderVolume(renderingEngine, imageIds);
} else {
await renderStack(renderingEngine, imageIds);
}
I think you're judging by the imagePosition
What feature or change would you like to see made?
Hello,
I'm currently facing a challenge in my project and I would appreciate your assistance. I need to find a way to programmatically change the image in a volume viewport. So far, I've been able to do this with stackviewport by calling the setImageIdIndex method. However, I've noticed that this approach doesn't work for volume, as there is no equivalent method available.
Do you happen to know of another way to achieve this goal? Any guidance or suggestions would be greatly appreciated.
Thank you in advance for your help!
Why should we prioritize this feature?
Prioritizing the requested feature to programmatically change images in the volume viewport is crucial for enhancing user control and flexibility. This feature interacts with existing functionality by extending image manipulation capabilities to volume rendering. Its implementation ensures consistency across viewports and improves user experience by empowering efficient data management and visualization. Prioritizing this feature reflects responsiveness to user needs and contributes to long-term project success and user satisfaction.