Hi, i am trying to visualize a set of 2D DICOM slices into 3D object. But the important thing is I have to apply the marching cube algorithm. I have been searching for solutions on many sites but found nothing, also, I could see any clear tutorials about my problem on VTK.js website. Can you guys give me some suggestion? @thewtex
Here is an example of doing marching cube of an ImageData. You just need to load your DICOM like ParaView Glance is doing using itk.js and you should be good to go.
Adding the example that @jourdain points to which shows how to execute marching cubes, the other calls you need to make are readImageDICOMFileSeries and convertItkToVtkImage.
Hi again, thanks for the clear explanation. The example is really clear and useful. So in general (considering the example attached by @jourdain ), I need to read the DICOM series, then convert them into a variable by using _convertItkToVtkImage_. Afterward, the file with VTI format in the example will be replace by assigned variable, then I will get what I need, is it right?
@truongleit you got it :+1:
Hi again, need some helps from you guys! I followed the code from _itk-vtk-viewer_ to see how you read and convert the input files into the VTK image, then tried to do the apply it to the _VolumeContour_ example. But in the final step, I receive an error which is:
"Uncaught (in promise) TypeError: a.getOrigin is not a function"
Here is my code:
function render(files) {
let reader = itkreadImageDICOMFileSeries;
let arg = files;
reader(null, arg).then(({
image: itkImage,
webWorker
}) => {
webWorker.terminate()
console.log(itkImage)
const imageData = vtkITKHelper.convertItkToVtkImage(itkImage);
console.log(imageData)
const dataRange = imageData
.getPointData()
.getScalars()
.getRange();
const firstIsoValue = (dataRange[0] + dataRange[1]) / 3;
const el = document.querySelector('.isoValue');
el.setAttribute('min', dataRange[0]);
el.setAttribute('max', dataRange[1]);
el.setAttribute('value', firstIsoValue);
el.addEventListener('input', updateIsoValue);
marchingCube.setContourValue(firstIsoValue);
renderer.addActor(actor);
renderer.getActiveCamera().set({
position: [1, 1, 0],
viewUp: [0, 0, -1]
});
renderer.resetCamera();
renderWindow.render();
})
}
The _imageData_ variable is the one that will be rendered. I also compared the _imageData_ in my code with the _imageData_ in _itk-vtk-viewer_. They are exactly similar when loading the same DICOM serie. Note that the _VolumeContour_ example is running perfectly on my device. @thewtex @jourdain
Where do you call marchingCube.setInputData(imageData)?
HUGE thanks to you! It is working now 馃憤 @jourdain
Hi again! I would like to render the 3D object into a specific container. In my case, the div class is 'threeD', how can I do that? I read the code and found out that it's now using _vtkFullScreenRenderWindow_ to visualize object in fullscreen mode. But I don't know what I should do next, read some more examples on the site but most of them are using fullscreen mode as well. Hope to reiceive your help soon, thanks again. @jourdain
Here is my code:
const fullScreenRenderWindow = vtkFullScreenRenderWindow.newInstance({
background: [0, 0, 0],
});
const renderWindow = fullScreenRenderWindow.getRenderWindow();
const renderer = fullScreenRenderWindow.getRenderer();
// fullScreenRenderWindow.addController(controlPanel);
const actor = vtkActor.newInstance();
const mapper = vtkMapper.newInstance();
const marchingCube = vtkImageMarchingCubes.newInstance({
contourValue: 0.0,
computeNormals: true,
mergePoints: true,
});
actor.setMapper(mapper);
mapper.setInputConnection(marchingCube.getOutputPort());
function updateIsoValue(e) {
const isoValue = Number(e.target.value);
marchingCube.setContourValue(isoValue);
renderWindow.render();
}
const reader = vtkHttpDataSetReader.newInstance({
fetchGzip: true
});
marchingCube.setInputConnection(reader.getOutputPort());
function render(files) {
let reader = itkreadImageDICOMFileSeries;
let arg = files;
reader(null, arg).then(({
image: itkImage,
webWorker
}) => {
webWorker.terminate()
console.log(itkImage)
const imageData = vtkITKHelper.convertItkToVtkImage(itkImage);
console.log(imageData)
const dataRange = imageData
.getPointData()
.getScalars()
.getRange();
const firstIsoValue = (dataRange[0] + dataRange[1]) / 3;
marchingCube.setInputData(imageData);
marchingCube.setContourValue(firstIsoValue);
renderer.addActor(actor);
renderer.getActiveCamera().set({
position: [1, 1, 0],
viewUp: [0, 0, -1]
});
renderer.resetCamera();
renderWindow.render();
})
}
var fileInput = document.getElementById('file-input');
fileInput.addEventListener('change', function(event) {
var input = event.target;
render(input.files);
});
global.fullScreen = fullScreenRenderWindow;
global.actor = actor;
global.mapper = mapper;
global.marchingCube = marchingCube;
Hi again, is there any configs except iso value for marching cube rendering? Is it possible to add the control UI from vtkVolumeController to the render so I can change the 3D object's colors? @jourdain
You can do what you want, but the generated polydata won't have any field to color by since you contour (same value) it.
You can set the color to its actor using actor.getProperty().setColor(r, g, b) where r,g,b are float between [0,1].
Thanks for suggestion! Also, I am building a color-changing function based on your instruction, so how can I make the object's color change immediately right after I choose new color? Currently I am testing it by typing directly the code in Chrome DevTools, so after I modify the color's value of actor, I need to do something (ex: rotate) with the object's canvas in order to see the change. @jourdain
You need to call render() on the vtkRenderWindow instance.
Hi again, I am thinking of creating 4 view modes for my application which contains both 3D and 2D (X, Y, Z) objects. Thanks to your clear explanation, the 3D mode is now performing pretty well. Now I am moving to visualize the input collection of DICOM slices into 3 axes (X, Y and Z). However, the only example I found on VTK.JS site isMultiSliceImageMapper. The problem of mine is I need to display them in 3 different DOM elements, not like the given example. Can you instruct me a little bit more? Thanks @jourdain
You can look at ParaView Glance which already do all of that.
Thanks a lot! My app also has other rendering algorithms which are implemented by using other JavaScript library. When switching from VTK's Marching Cube to another, how can I destroy the render for memory-saving purposes? @jourdain
Most helpful comment
Here is an example of doing marching cube of an ImageData. You just need to load your DICOM like ParaView Glance is doing using itk.js and you should be good to go.