Automating segmentation on volumes

Hello,

I’ve started using Slicer a few weeks ago for a University project. It’s about segmenting the volume of a cell with a predefined (known parameters) threshold, smoothing, removing small islands and margin increase procedure.
My input is a set of 80 folders, each containing 256 images (named imgXYZ.png).
I’ve searched a couple of websites and youtube videos on achieving this but failed to get further than importing the set of images that build a 256x256x256 cube with:
[success, loadedVolumeNode] = slicer.util.loadVolume("[success, loadedVolumeNode] = slicer.util.loadVolume(“path/fib1000/img001.png”, returnNode=True)", returnNode=True)
and then creating the segmentation “node” with:
seg = slicer.mrmlScene.AddNewNodeByClass(‘vtkMRMLSegmentationNode’, ‘Segment’)

Despite not getting further than this I was also trying to access the Name variable of the loadedVolumeNode with print(loadedVolumeNode.GetAttribute(“Name”)) with a simple None as the result.

I am in no way fluent in Python as I’ve first used it when trying to create a script for Slicer (which was last week), so if someone could please point me in the right direction I’d be very grateful.

Janko

PS: If this is in the wrong forum, could it be moved into the correct one.

Can you do what you want to do manually using the segment editor (without resorting the scripts) as a test first?

Slicer reads PNG stacks as a vector volume. I am not sure if segment editor works with vector volumes, you may have to convert to a scalar first.

Mail](https://go.microsoft.com/fwlink/?LinkId=550986) for Windows 10

1 Like

I can do it manually, but I would have to do it for 80 subvolumes which were extracted from the master volume. I would also like to specify the segmentations parameters, for example: try all combinations of Threshold Range starting at [0, 20] and ending at [25, 40], which removes doing it by hand as an option.

The segment editor works fine when importing the volume through File -> Add Data -> Select first image (001) -> untick Single File.

The whole process would look like: Load a folder of images, create a segmentation node and apply the volume to it, apply threshold with specified range, apply smoothing, remove small islands, apply margin increase and finally save the segmentation to a file. This would preferably be repeated X times while not crashing for out of memory.

I’m guessing there are functions for this but I either cannot find them or can’t figure out how to call them properly, I’m constantly getting errors or None, when printing something.

There are complete examples of automating segmentation by Python scripting, which should be quite close to what you need: https://www.slicer.org/wiki/Documentation/Nightly/ScriptRepository#How_to_run_segment_editor_effects_from_a_script

Hello,

I’m following this example:

and got stuck after the following commands were entered:

// Load Volume consisting of png images
[success, loadedVolumeNode] = slicer.util.loadVolume(“C:/Users/Janko/Desktop/RVP_LGM/MatLabIMG/fib1000/img001.png”, returnNode=True)

// Create segmentation node
segmentationNode = slicer.mrmlScene.AddNewNodeByClass(“vtkMRMLSegmentationNode”, “SegmentationOfVolume”)

// Only needed for display? What does this mean
segmentationNode.CreateDefaultDisplayNodes()

// Set volume of segmentation to loaded volume
segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode(loadedVolumeNode)

// Create new segment - this is where the effects will be applied to
addedSegmentID = segmentationNode.GetSegmentation().AddEmptySegment(“mitochondrium”)

// Create segment editor to get access to effects
segmentEditorWidget = slicer.qMRMLSegmentEditorWidget()
segmentEditorWidget.setMRMLScene(slicer.mrmlScene)
segmentEditorNode = slicer.mrmlScene.AddNewNodeByClass(“vtkMRMLSegmentEditorNode”)
segmentEditorWidget.setMRMLSegmentEditorNode(segmentEditorNode)
segmentEditorWidget.setSegmentationNode(segmentationNode)
segmentEditorWidget.setMasterVolumeNode(loadedVolumeNode)

It is a copy paste up to right before an effect is created, with only some names changed to suit my case.
After running the last function, the segment editor doesn’t get its Master Volume assigned to the loadedVolumeNode so I’m wondering if I’m doing something wrong.
I’m running the 4.9.0, 4. 17 edition of Slicer.

Thank you

1 Like

To see the segment editor settings that you’ve set, make your internal segment editor widget visible by calling segmentEditorWidget.show().

1 Like

Thank you.

I’ve got a small problem regarding changing the Margin size for the Margin effect.
I’ve checked the following pages for how the parameter could be called:
http://apidocs.slicer.org/master/SegmentEditorMarginEffect_8py_source.html
http://apidocs.slicer.org/master/classSegmentEditorMarginEffect_1_1SegmentEditorMarginEffect.html
yet none of the names I’ve tried changed the value of it.

I was also looking for a function that would print all names of parameters but was unsuccessful there as well.
It would be useful because I could also need the parameters for the Islands effect.

The parameter name is “MarginSizeMm”. What names did you try and what values did you set? Did you see the value updating on the user interface?

I checked the 2 links I posted above.
Could you please show me where you store the parameter lists for functions? I can’t find the parameter name of the Operation for Margin if I want to change to Grow or Shrink, nor can I find actual value to which I should set the parameter (is it a string “Grow”, is it GROW as a constant).

Thank you,
Janko

List of all parameters are always listed in setMRMLDefaults method. For the margin effect there is only a single parameter:

Sign of margin size defines grow/shrink. Positive value means growing, negative value means shrinking.

1 Like

Thank you,
I was able to find the parameters for the Islands Segment effect.

Hello,

is there any way to find exactly what I’m not deleting when closing Slicer? I have a memory leak with the following message:
image

# Load Volume consisting of png images
[success, loadedVolumeNode] = slicer.util.loadVolume("C:/Users/Janko/Desktop/RVP_LGM/MatLabIMG/fib1000/img001.png", returnNode=True)

# Create segmentation node
segmentationNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLSegmentationNode", "SegmentationOfVolume")

# Only needed for display? What does this mean
segmentationNode.CreateDefaultDisplayNodes()

# Set volume of segmentation to loaded volume 
segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode(loadedVolumeNode)

# Create new segment - this is where the effects will be applied to
addedSegmentID = segmentationNode.GetSegmentation().AddEmptySegment("mitochondrium")

# Create segment editor to get access to effects, literally creates a new Segment Editor window
segmentEditorWidget = slicer.qMRMLSegmentEditorWidget()
segmentEditorWidget.setMRMLScene(slicer.mrmlScene)
segmentEditorNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLSegmentEditorNode")
segmentEditorWidget.setMRMLSegmentEditorNode(segmentEditorNode)
segmentEditorWidget.setSegmentationNode(segmentationNode)
segmentEditorWidget.setMasterVolumeNode(loadedVolumeNode)

# Shows the new Segment Editor window
segmentEditorWidget.show()

# Thresholding
segmentEditorWidget.setActiveEffectByName("Threshold")
effect = segmentEditorWidget.activeEffect()
effect.setParameter("MinimumThreshold","1")
effect.setParameter("MaximumThreshold","110")
effect.self().onApply()

# Smoothing
segmentEditorWidget.setActiveEffectByName("Smoothing")
effect = segmentEditorWidget.activeEffect()
effect.setParameter("SmoothingMethod", "MEDIAN")
effect.setParameter("KernelSizeMm", 7)
effect.self().onApply()

# Islands
segmentEditorWidget.setActiveEffectByName("Islands")
effect = segmentEditorWidget.activeEffect()
effect.setParameter("Operation", "REMOVE_SMALL_ISLANDS")
effect.setParameter("MinimumSize", 500)
effect.self().onApply()

# Margin
segmentEditorWidget.setActiveEffectByName("Margin")
effect = segmentEditorWidget.activeEffect()
effect.setParameter("MarginSizeMm", 7)
effect.self().onApply()

segmentEditorWidget = None
slicer.mrmlScene.RemoveNode(segmentEditorNode)

# Write to .seg.nrrd file (.seg required for Slicer to detect it's a segmentation file)
myNode = slicer.util.getNode("SegmentationOfVolume")
myStorageNode = myNode.CreateDefaultStorageNode()
myStorageNode.SetFileName("C:/Users/Janko/Desktop//RVP_LGM/SlicerOutput/"+"fib1000"+".seg.nrrd")
myStorageNode.WriteData(myNode)

slicer.mrmlScene.Clear(0)

This is my entire code before running a loop that’ll iterate through all 80 volumes and I was hoping the Clear() function would clear all memory allocations, but I am not freeing something. I was hoping to get to a clean start and repeat the process again without running out of memory. I know I could keep some declarations and just change the input to it (like volume for segmentation) but my first goal would be to remove all leaks.
I tried running the code 4x and got the following memory usage from Task manager:
167.3MB
213.2MB
217.9MB
218.4MB
which shows a slight increase in usage each time.

Edit:
I’ve added the following three RemoveNode calls:
slicer.mrmlScene.RemoveNode(myNode)
slicer.mrmlScene.RemoveNode(segmentationNode)
slicer.mrmlScene.RemoveNode(loadedVolumeNode)
which reduces the leaks to: 1, 1, 2, 2 of the same Error.

Janko

If you clear the scene and delete all Python variables you create then memory usage should return to the initial value. If you have a Python variable that refers to a VTK object then that object will not be deleted until you delete that variable (calling del or letting the variable go out of scope), even if it is a node that you’ve deleted from the scene.

It seems that you leak a storage node. CreateDefaultStorageNode creates a new storage node and sets its reference count of 1 (so that it can be returned as a simple pointer). After you save it in a Python variable, you need to decrement the reference count by calling myStorageNode.UnRegister(None) to indicate that it is now owned by the Python variable. See more details and examples here: https://www.slicer.org/wiki/Documentation/Nightly/Developers/Tutorials/MemoryManagement#Python_scripts_and_scripted_modules

1 Like

Thank you,

I’ve got a bit of a problem loading the segmentation back now, after saving with a StorageNode. The volume information is lost through the process which is something I would like to keep.
Is there a different way to save a segmentation node or am I incorrectly calling something?

What do you mean? What did you expect to happen and what happened instead?

When I load a saved segmentation node and try loading it back, it does not remember the Master volume for it.
image
Should I be saving the entire mrml scene, or is there a way to store aditional info about the volume location on my disk?

Correct. Saved segmentation and master volume files are saved independently and do not refer to each other. In the scene file we store Segment editor settings, which includes reference to the segmentation node and master volume node.

I´m in trouble with “Margin” effect, @lassoan . This is my code:

segmentEditorWidget.setActiveEffectByName(“Margin”)
effect = segmentEditorWidget.activeEffect()
effect.setParameter(“KernelSizeMm”, -5)
effect.self().onApply()
# Margin (Shrink)
# Sign of margin size defines grow/shrink. Positive value means growing, negative value means shrinking.

I´ve probed both signs in kernel size (positive or negative) and always is done growing effect. What I´m doing wrong?

Thanks

The correct parameter name is MarginSizeMm - see source code.

Right…Thanks @lassoan

1 Like