Apply filters on vtkMRMLVolumeNode and then display the filtered volume in Slicer

Hi All,

I have a custom loadable modul. In this modul, I want to apply IKT or VTK filters on the previously loaded DICOM volume. I have something like this:

vtkMRMLVolumeNode* volumeNode = d->MRMLVolumeNode; // this contains the loaded DICOM volume
vtkImageData* imageData = volumeNode->GetImageData();    //now I have the image data of that volume

//apply filter, for example:

vtkSmartPointer<vtkImageGaussianSmooth> gaussianSmoothFilter = vtkSmartPointer<vtkImageGaussianSmooth>::New();
gaussianSmoothFilter->SetInputData( const_cast<vtkImageData*>( imageData ) );

I think I missed something from here because assertation happens during debug in the Update() function
gaussianSmoothFilter->Update();

Maybe I missed the gaussianSmoothFilter->SetInputConnection(...) function call before the Update(), but how can I get the proper input for this function? I have only the volumeNode object…

But now let’s assume that the filtered pointer holds the Gaussian filtered image:
vtkImageData* filtered = gaussianSmoothFilter->GetOutput();

My question is, how can I display this volume in the slice viewes?
(Example codes are highly appreciated.)

Thank’s,
Csaba

Something like this should work:

vtkMRMLVolumeNode* volumeNode = d->MRMLVolumeNode;
vtkNew<vtkImageGaussianSmooth> gaussianSmoothFilter;
gaussianSmoothFilter->SetInputData(volumeNode->GetImageData());
gaussianSmoothFilter->Update();
volumeNode->SetImageData(gaussianSmoothFilter->GetOutput());

For applying ITK and VTK filters, you don’t need to develop C++ loadable modules. The simplest is to use Python scripted modules or CLI modules. There are lots of examples for various module types in the Slicer core.

Thank you Andras!

A little correction:

This one causes exception in Update():
gaussianSmoothFilter->SetInputData(volumeNode->GetImageData());
but this is okay and works well:
gaussianSmoothFilter->SetInputConnection( volumeNode->GetImageDataConnection() );

What exception did you get?

Hi Andras,
Would you please tell me what I am doing wrong in the code below:

I need to apply normalize image filter of simple filters to volume.

normal = vtk.vtkImageNormalize()
normal.SetInputData(volumeNode.GetImageData())
normal.Update()
volumeNode.SetImageData(normal.GetOutput())

Error:
Traceback (most recent call last): File “<string>”, line 8, in <module> AttributeError: ‘MRMLCorePython.vtkMRMLScalarVolumeNode’ object has no attribute ‘SetImageData’

I got the results with below but its not showing correct results when compared to results obtained using slicer APP. is this the correct filter for normalize image filter?

normal = vtk.vtkImageNormalize()
normal.SetInputConnection(volumeNode.GetImageDataConnection())
normal.Update()
volumeNode.SetImageDataConnection(normal.GetOutputPort())

What do you expect this filter would do? What happens instead?
How did you obtain the good results that you mentioned?
Why would you like to normalize an image?

I was expecting normalized image intensities. The result are:
image
was expecting
image

I want to normalize an image to obtain standardize intensities before doing automatic segmentation.

Applying linear intensity scaling will most likely not affect automatic segmentation results. Even the most basic methods are insensitive to global image brightness/contrast adjustments.

Check out segmentation tutorials and read these posts to have an idea how you can segment semi-automatically or automatically in Slicer:

1 Like

Dear Andras,
Is there a way to do automated segmentation for brain, tumor and ventricles together in any MRI without user input?

Regards,
Saima Safdar

Fully automatic segmentation is probably not the best approach, but you can get very close to it (probably 1-2 minutes of user’s time) if you implement a custom script:

  • brain: you can use SwissSkullStripper extension to get the brain completely automatically
  • ventricles: probably you can get ventricles by thresholding in brain segment region, potentially with some pre/post processing for optimal results
  • tumor: there is a large variety of their size, location, and appearance, so fully automatic detection may be very difficult; however, you should be able to segment a tumor within one minute, with minimal user input, using “Grow from seeds” effect
1 Like

Does the swiss skull stripper always use the atlas image and atlas mask. Is it reliable to use the same mask and image for any mri for extracting brain.

in accessing the swissskullmodule one step is to convert the atlasmask which is in volume into labelvolume.

I am doing this through script but have some problem. Dont get the correct output result for swiss.

I know the problem is in the mask setting it to labelvolume as the downloaded atlas is a scalarvolumenode. I did it using the GUI and it does it job.

vol = slicer.modules.volumes
log = vol.logic()
outputlabelnode = slicer.vtkMRMLLabelMapVolumeNode()
labelVolNode = log.CreateLabelVolumeFromVolume(slicer.mrmlScene, outputlabelnode, nodeMaskAtlas)

Is this the way to convert a volumenode to labelvolume.

Problem with one parameter atlasmaskvolume as it takes the labelvolume.

full code: I do not know what I am doing wrong. tried alot but dont get the extracted skull in outputvolume.

import SampleData
sampleDataLogic = SampleData.SampleDataLogic()
masterVolumeNode = sampleDataLogic.downloadMRBrainTumor1()
[success, atlasImage] = slicer.util.loadVolume('D:/atlasImage.mha', returnNode = True)
[success2, atlasMask] = slicer.util.loadVolume('D:/atlasMask.mha', returnNode = True)

nodeImageAtlas = slicer.util.getNode(atlasImage.GetName())
nodeMaskAtlas = slicer.util.getNode(atlasMask.GetName())

vol = slicer.modules.volumes
log = vol.logic()
vol =log.SetActiveVolumeNode(nodeMaskAtlas)
#scal = slicer.vtkMRMLScalarVolumeNode()
#slicer.mrmlScene.AddNode(scal)
labelVolume = log.CreateAndAddLabelVolume(slicer.mrmlScene, nodeMaskAtlas, nodeMaskAtlas.GetName())

outVolume = slicer.vtkMRMLScalarVolumeNode()
slicer.mrmlScene.AddNode(outVolume)
maskLabel = slicer.vtkMRMLLabelMapVolumeNode()
slicer.mrmlScene.AddNode(maskLabel)

parameters = {}
parameters['atlasMRIVolume'] = nodeImageAtlas.GetID()
parameters['atlasMaskVolume'] = labelVolume.GetID()
parameters['patientVolume'] = masterVolumeNode.GetID()

parameters['patientOutputVolume'] = outVolume.GetID()
parameters['patientMaskLabel'] = maskLabel.GetID()

swissSkullStripper = slicer.modules.swissskullstripper
slicer.cli.runSync(swissSkullStripper,None, parameters)

Yes, CreateLabelVolumeFromVolume method converts a scalar volume to a label volume. However, in your full script you used CreateAndAddLabelVolume method, which creates an empty label volume based on geometry specified by another volume.

The simplest is to load the label volume with the correct loading function: slicer.util.loadLabelVolume() - then you don’t need any conversion.

1 Like

Hi Andras,
Could you please share the ventricle segmentation tutorial so I can get the idea of workflow and write the script for ventricle extraction. It can be done automatically through script calling modules. right?
I was using threshold and island effect but island effect require user input which I do not want.