Segmentation using thresholding using Python

Hey there,
I’m back with more silly questions
using the examples of using segment editor have been really helpful, the issue I have been running into, however, is using an image that is not the sample image.

Just dragging in an image and avoiding anything that uses ‘masterVolumeNode’ was my original plan, but I am unable to apply the threshold on the image of interest if I do it that way.Same with pulling in the image and setting it as the master volume manually on segment editor. So I did some digging to try and find out how to load in my own image the correct way and found this:

masterVolumeNode = slicer.util.loadVolume('C:/Users/m222222/Dropbox/BRAIN_MASK.nii.gz’, returnNode=True)

(the path is similar to my actual path)
and it doesn’t complain at me, but it also doesn’t open the file, and when I tried to run things anyways, after
‘segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode(masterVolumeNode)’
I got an error that I needed a VTK object, and after
‘segmentEditorWidget.setMasterVolumeNode(masterVolumeNode)’
it also said that I needed a VTK object

if I run it without those 2 lines, it complains at the end on ‘effect.self().onApply()’ and says…

Traceback (most recent call last):
File “”, line 1, in
File “/Applications/Slicer.app/Contents/lib/Slicer-4.10/qt-scripted-modules/SegmentEditorEffects/SegmentEditorEffects/SegmentEditorThresholdEffect.py”, line 351, in onApply
modifierLabelmap.GetImageToWorldMatrix(originalImageToWorldMatrix)
AttributeError: ‘NoneType’ object has no attribute ‘GetImageToWorldMatrix’

To be honest, I really don’t know what I’m doing on the coding front, so even simple things like loading images are rough, which is why I’m here.

I’m just confused and would like to know the correct way to load a master volume so the sample works with a novel image.

Thank you,
Jazlynn

This example should work as is, just replace this line:

masterVolumeNode = sampleDataLogic.downloadMRBrainTumor1()

by this, if you use recent 4.11 version of Slicer:

masterVolumeNode = slicer.util.loadVolume('C:/Users/m222222/Dropbox/BRAIN_MASK.nii.gz')

by this, if you use 4.10 version:

[success, masterVolumeNode] = slicer.util.loadVolume('C:/Users/m222222/Dropbox/BRAIN_MASK.nii.gz', returnNode=True)

that makes a lot of sense, thank you

I replaced the first line with

[success, masterVolumeNode] = slicer.util.loadVolume(“C:/Users/m214492/Dropbox/CNV Modeling/Brain for Gustavo/BRAIN_MASK.nii.gz”, returnNode=True)

because it gave a syntax error the ran with one quote, and everything seemed to work until I got to that apply line

effect.self().onApply()

Where the callback was:

Traceback (most recent call last):
File “”, line 1, in
File “/Applications/Slicer.app/Contents/lib/Slicer-4.10/qt-scripted-modules/SegmentEditorEffects/SegmentEditorEffects/SegmentEditorThresholdEffect.py”, line 351, in onApply
modifierLabelmap.GetImageToWorldMatrix(originalImageToWorldMatrix)
AttributeError: ‘NoneType’ object has no attribute ‘GetImageToWorldMatrix’

I’m really not sure why or what it going on internally in slicer when this happens, but it runs with the sample

sorry for all of the questions

best,
Jazlynn

I think it may have something to do with the fact that in the sample, slicer actually opens the file, and you can see it in your 3 colored windows, but when I set my master volume, the file doesn’t come up visibly in slicer. I’m not sure if that could be the issue or not.

Does the example that I linked above works? If yes then try to follow that example more closely, make modifications step-by-step, and see which change causes the problem.

The sample that is provided works without an issue, and slicer doesn’t throw up an error until the thresholding line (after going through the code step by step)

effect.self().onApply()

So there must be an issue earlier although there was no complaint from slicer. I believe that is has to do with loading the master image; when I set the master image to be my novel image, the image is not shown in the colored ‘slices’ windows. However, when the sample image is loaded, it appears in the colored ‘slices’ windows.

The exact code I have been running is:
The master volume is a mask, saved as a nifty file.

[success, masterVolumeNode] = slicer.util.loadVolume(“C:/Users/m22222/Dropbox/BRAIN_MASK.nii.gz”, returnNode=True)

segmentationNode = slicer.mrmlScene.AddNewNodeByClass(“vtkMRMLSegmentationNode”)
segmentationNode.CreateDefaultDisplayNodes() # only needed for display
segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode(masterVolumeNode)
addedSegmentID = segmentationNode.GetSegmentation().AddEmptySegment(“skin”)

segmentEditorWidget = slicer.qMRMLSegmentEditorWidget()
segmentEditorWidget.setMRMLScene(slicer.mrmlScene)
segmentEditorNode = slicer.mrmlScene.AddNewNodeByClass(“vtkMRMLSegmentEditorNode”)
segmentEditorWidget.setMRMLSegmentEditorNode(segmentEditorNode)
segmentEditorWidget.setSegmentationNode(segmentationNode)
segmentEditorWidget.setMasterVolumeNode(masterVolumeNode)

segmentEditorWidget.setActiveEffectByName(“Threshold”)
effect = segmentEditorWidget.activeEffect()
effect.setParameter(“MinimumThreshold”,“1”)
effect.setParameter(“MaximumThreshold”,“1”)
effect.self().onApply()

segmentEditorWidget = None
slicer.mrmlScene.RemoveNode(segmentEditorNode)

segmentationNode.CreateClosedSurfaceRepresentation()

What is the output of print(master VolumeNode)?

The output is just ‘none’

It means the image loading has failed. The application log may contain more details (menu: Help / Report a bug). Is the file path correct? Can you load the image by using “Add data”?

When I use the ‘add data’ option I get

[INFO][VTK] 02.08.2019 10:18:59 [vtkMRMLVolumeArchetypeStorageNode (0x7f9436777de0)] (/Volumes/Dashboards/Stable/Slicer-4102/Libs/MRML/Core/vtkMRMLVolumeArchetypeStorageNode.cxx:465) - Loaded volume from file: /Users/m214492/Dropbox/CNV Modeling/Brain for Gustavo/BRAIN_MASK.nii.gz. Dimensions: 270x320x76. Number of components: 1. Pixel type: float.
[DEBUG][Qt] 02.08.2019 10:18:59 [] (unknown:0) - “Volume” Reader has successfully read the file “/Users/m214492/Dropbox/CNV Modeling/Brain for Gustavo/BRAIN_MASK.nii.gz” “[0.29s]”

in the application log

When I enter it using the CLI I get

[DEBUG][Qt] 02.08.2019 10:18:00 [] (unknown:0) - Python console user input: [success, masterVolumeNode] = slicer.util.loadVolume(“C:/Users/m214492/Dropbox/CNV Modeling/Brain for Gustavo/BRAIN_MASK.nii.gz”, returnNode=True)

Path looks different:
/Users/m214492/Dropbox/CNV Modeling/Brain for Gustavo/BRAIN_MASK.nii.gz
is not the same as
C:/Users/m214492/Dropbox/CNV Modeling/Brain for Gustavo/BRAIN_MASK.nii.gz

Drive name (such as C:) is only used on Windows machines.

Oh my goodness you have just saved my life, thank you so much

A post was split to a new topic: Change segment color and opacity

Hello
I am new to 3DS Slicer.
I would like to automate 3D mesh generation with 3DSlicer from dcm serie and save it as obj file.
the idea is to open obj files in hololens afterwards.

I can open my dcm files like this.

dicomDataDir = "C:/Users/xbouq/Downloads/Anonymized/dcm"
loadedNodeIDs = []  # this list will contain the list of all loaded node IDs

from DICOMLib import DICOMUtils
with DICOMUtils.TemporaryDICOMDatabase() as db:
  DICOMUtils.importDicom(dicomDataDir, db)
  patientUIDs = db.patients()
  for patientUID in patientUIDs:
    loadedNodeIDs.extend(DICOMUtils.loadPatientByUID(patientUID))

But after i dont understand how make a link with segmentatioNodes

segmentationNode = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLSegmentationNode')
segmentationNode.CreateDefaultDisplayNodes()
segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode(masterVolumeNode)
addedSegmentID = segmentationNode.GetSegmentation().AddEmptySegment('skin')

segmentEditorWidget = slicer.qMRMLSegmentEditorWidget()
segmentEditorWidget.setMRMLScene(slicer.mrmlScene)
segmentEditorNode = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLSegmentEditorNode')
segmentEditorWidget.setMRMLSegmentEditorNode(segmentEditorNode)
segmentEditorWidget.setSegmentationNode(segmentationNode)
segmentEditorWidget.setMasterVolumeNode(masterVolumeNode)

segmentEditorWidget.setActiveEffectByName('Threshold')
effect = segmentEditorWidget.activeEffect()
effect.setParameter('MinimumThreshold','135') // for bones
effect.setParameter('MaximumThreshold','294')
effect.self().onApply()

Can you help me ?
maybe there is a plugin for 3DSlicer?

You can get the volume node object from loadedNodeIDs by using masterVolumeNode = slicer.mrmlScene.GetNodeByID(nodeID).

If you import a complete DICOM study then the loaded nodes include scout scans, dose report, etc., so you may want to filter out images that have only one or few slices.

Thank’s very lot Andras
But now i have another problem.

dicomDataDir = "C:/Users/xbouq/Downloads/Anonymized/dcm"
loadedNodeIDs = []  # this list will contain the list of all loaded node IDs

from DICOMLib import DICOMUtils
with DICOMUtils.TemporaryDICOMDatabase() as db:
  DICOMUtils.importDicom(dicomDataDir, db)
  patientUIDs = db.patients()
  for patientUID in patientUIDs:
    loadedNodeIDs.extend(DICOMUtils.loadPatientByUID(patientUID))



segmentationNode = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLSegmentationNode')
masterVolumeNode = segmentationNode.GetNodeReference(segmentationNode.GetReferenceImageGeometryReferenceRole())

segmentationNode.CreateDefaultDisplayNodes()
segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode(masterVolumeNode)
addedSegmentID = segmentationNode.GetSegmentation().AddEmptySegment('skin')

segmentEditorWidget = slicer.qMRMLSegmentEditorWidget()
segmentEditorWidget.setMRMLScene(slicer.mrmlScene)
segmentEditorNode = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLSegmentEditorNode')
segmentEditorWidget.setMRMLSegmentEditorNode(segmentEditorNode)
segmentEditorWidget.setSegmentationNode(segmentationNode)
segmentEditorWidget.setMasterVolumeNode(masterVolumeNode)


addedSegmentID = segmentationNode.GetSegmentation().AddEmptySegment("Segmentation")
segmentEditorNode.SetSelectedSegmentID(addedSegmentID)
    
segmentEditorWidget.setActiveEffectByName('Threshold')
effect = segmentEditorWidget.activeEffect()
effect.setParameter('MinimumThreshold',"135")
effect.setParameter('MaximumThreshold',"294")
effect.self().onApply()

When execution arrival at this line i have this error, Something escape me…

SegmentEditorThresholdEffect.py", line 590, in onApply

```    modifierLabelmap.GetImageToWorldMatrix(originalImageToWorldMatrix)
AttributeError: 'NoneType' object has no attribute 'GetImageToWorldMatrix'


layoutManager = slicer.app.layoutManager()
threeDWidget = layoutManager.threeDWidget(0)
threeDView = threeDWidget.threeDView()
threeDView.resetFocalPoint()  

outputFolder = "C:/Users/xbouq/Downloads/Anonymized/dcm"
slicer.vtkSlicerSegmentationsModuleLogic.ExportSegmentsClosedSurfaceRepresentationToFiles(outputFolder, segmentationNode, None, "OBJ", True, 1.0, False)

This would get you the node that was used to set the segmentation geometry (which is usually the master volume). But you have just created a new segmentation node. You have not set its geometry, so this GetNode… method will return None.

Instead, you can set the master volume (a volume that you loaded from DICOM) into the segmentation node by calling segmentEditorWidget.setMasterVolumeNode(masterVolumeNode).

Hi Andras
How to replace this init of masterVolumeNode
sampleDataLogic = SampleData.SampleDataLogic()
masterVolumeNode = sampleDataLogic.downloadMRHead()

with this loading system
dicomDataDir = “C:/Users/xbouq/Downloads/Anonymized/dcm”
loadedNodeIDs = [] # this list will contain the list of all loaded node IDs

from DICOMLib import DICOMUtils
with DICOMUtils.TemporaryDICOMDatabase() as db:
DICOMUtils.importDicom(dicomDataDir, db)
patientUIDs = db.patients()
for patientUID in patientUIDs:
loadedNodeIDs.extend(DICOMUtils.loadPatientByUID(patientUID))

masterVolumeNode =

Do you know if there are freelancers to develop with 3dSlicer.
Our idea is to do a proof of concept, where we will copy Dicom files to a directory and with an online command we could select filters to generate 3d files to visualize them in the end in hololens.
But we don’t have any expertise with 3Dslicer which is sacred software and with Python either.

I manage to generate OBJ files with the software but I can’t automate the process and I may not find the time to learn to program with 3Dslicer. There are too many concepts that I don’t know :slight_smile:

It would be something like this:

i = 0  # first loaded image series (it multiple image series are loaded then you may want to iterate through all of them)
masterVolumeNode = slicer.mrmlScene.GetNodeByID(loadedNodeIDs[i])

Simple thresholding often does not provide sufficiently good quality results. I would recommend to use Grow from seeds or Local threshold effects in Segment Editor, or use MONAILabel extension to train a neural network for automatic segmentation. As a proof of concept, you can segment a couple of images manually using Segment Editor module and later you can automate it.

I would recommend to contact Slicer Commercial Partners.