There is an error when create a segment from numpy array

hellow, everyone.

i want to creat a segment from a numpy array. and i found the python code in script repository as following.

volumeNode = getNode('MRHead')
segmentationNode = getNode('Segmentation')
segmentId = segmentationNode.GetSegmentation().GetSegmentIdBySegmentName('Segment_1')

# Get segment as numpy array
segmentArray = slicer.util.arrayFromSegmentBinaryLabelmap(segmentationNode, segmentId, volumeNode)

# Modify the segmentation
segmentArray[:] = 0  # clear the segmentation
segmentArray[ slicer.util.arrayFromVolume(volumeNode) > 80 ] = 1  # create segment by simple thresholding of an image
segmentArray[20:80, 40:90, 30:70] = 1  # fill a rectangular region using numpy indexing
slicer.util.updateSegmentBinaryLabelmapFromArray(segmentArray, segmentationNode, segmentId, volumeNode)

in my own extension, the code line “volumeNode = getNode(‘MRHead’)” was be replaced by a qMRMLNodeCombobox in the nodetypes called “vtkMRMLScalarVolumeNode“.

the code line “segmentationNode = getNode(‘Segmentation’)“ was be replaced by a qMRMLNodeCombobox in the nodetypes called “vtkMRMLSegmentationNode“.

and i convert the “inputSelector“ and “inputsegmentation“ into def process as following.

def onApplyButton(self) -> None:

    """Run processing when user clicks "Apply" button."""

    with slicer.util.tryWithErrorDisplay(\_("Failed to compute results."), waitCursor=True):

        \# Compute output

        self.logic.process(self.ui.inputSelector.currentNode(), self.ui.imageThresholdSliderWidget.value, 

                           self.ui.inputlowerpoint.currentNode(), self.ui.inputmidpoint.currentNode(),

                           self.ui.inputupperpoint.currentNode(), self.ui.inputsegmentation.currentNode())

class cutcalciLogic(ScriptedLoadableModuleLogic):

"""This class should implement all the actual

computation done by your module.  The interface

should be such that other python code can import

this class and make use of the functionality without

requiring an instance of the Widget.

Uses ScriptedLoadableModuleLogic base class, available at:

https://github.com/Slicer/Slicer/blob/main/Base/Python/slicer/ScriptedLoadableModule.py

"""



def \__init_\_(self) -> None:

    """Called when the logic class is instantiated. Can be used for initializing member variables."""

    ScriptedLoadableModuleLogic.\__init_\_(self)



def getParameterNode(self):

    return cutcalciParameterNode(super().getParameterNode())



def getFiducialKJI(self, inputpoint, volume):    

def get_vascular_up2low(self, image, upperpoint, lowerpoint, CT_value):

def get_vascular_low2up(self, image, lowerpoint, upperpoint, CT_value):

def check_vascular(self, vascular_array, lowerpoint):

def get_vascular(self, image, upperpoint, midpoint, lowerpoint):

    vascular_array= self.get_vascular_up2low(image, upperpoint, lowerpoint, CT_value= 130)

    while self.check_vascular(vascular_array, lowerpoint)==0:

        vascular_array_1= self.get_vascular_low2up(image, midpoint, upperpoint)

        vascular_array_2= self.get_vascular_up2low(image, midpoint, lowerpoint)

        vascular_array= vascular_array+ vascular_array_1+ vascular_array_2

    return vascular_array

def process(self,

            inputVolume: vtkMRMLScalarVolumeNode,

            imageThreshold: float,

            inputlowerpoint,

            inputmidpoint,

            inputupperpoint,

            inputsegmentation,

            showResult: bool = True) -> None:

    if not inputVolume:

        raise ValueError("Input volume is invalid")

    lowerpoint= self.getFiducialKJI(inputlowerpoint, inputVolume)

    midpoint= self.getFiducialKJI(inputmidpoint, inputVolume)

    upperpoint= self.getFiducialKJI(inputupperpoint, inputVolume)

    image_array= slicer.util.arrayFromVolume(inputVolume)

    #vascular_array= self.get_vascular(image_array,upperpoint, midpoint, lowerpoint)

    segmentId = inputsegmentation.GetSegmentation().GetSegmentIdBySegmentName('Segment_1')

    print(lowerpoint)

    \# Get segment as numpy array

    segmentArray = slicer.util.arrayFromSegmentBinaryLabelmap(inputsegmentation, segmentId, inputVolume) **#there is an error in this code line**

    \# Modify the segmentation

    #segmentArray\[:\] = 0  # clear the segmentation

    #segmentArray\[ slicer.util.arrayFromVolume(inputVolume) > 80 \] = 1  # create segment by simple thresholding of an image

    #segmentArray\[20:80, 40:90, 30:70\] = 1  # fill a rectangular region using numpy indexing

    #slicer.util.updateSegmentBinaryLabelmapFromArray(segmentArray, inputsegmentation, segmentId, inputVolume)

and when i reload and apply this extension.

3D slicer tell me there is an error.

Traceback (most recent call last):
File “D:\program_file\Slicer 5.6.2\bin\Python\slicer\util.py”, line 3255, in tryWithErrorDisplay
yield
File “D:/program_file/Slicer 5.6.2/cutcalci/cutcalci/cutcalci.py”, line 245, in onApplyButton
self.logic.process(self.ui.inputSelector.currentNode(), self.ui.imageThresholdSliderWidget.value,
File “D:/program_file/Slicer 5.6.2/cutcalci/cutcalci/cutcalci.py”, line 423, in process

Get segment as numpy array

File “D:\program_file\Slicer 5.6.2\bin\Python\slicer\util.py”, line 2138, in arrayFromSegmentBinaryLabelmap
narray = slicer.util.arrayFromVolume(labelmapVolumeNode)
File “D:\program_file\Slicer 5.6.2\bin\Python\slicer\util.py”, line 1742, in arrayFromVolume
narray = vtk.util.numpy_support.vtk_to_numpy(vimage.GetPointData().GetScalars()).reshape(nshape)
File “D:\program_file\Slicer 5.6.2\bin\Lib\site-packages\vtkmodules\util\numpy_support.py”, line 215, in vtk_to_numpy
typ = vtk_array.GetDataType()
AttributeError: ‘NoneType’ object has no attribute ‘GetDataType’

i’m sure that it is the code line “segmentArray = slicer.util.arrayFromSegmentBinaryLabelmap(inputsegmentation, segmentId, inputVolume) “ which causes this error. because there the KJI coordinate of lowerpoint can be printed in python console.

so, my problem is how to create a segment from numpy array successfully?

You should write small examples in the slicer python console to confirm the your assumptions step by step. Or you can expose variables from within your module by assigning them into the global space with something like slicer.modules.segmentationNode = segmentationNode and then you can call methods on it to see what happens.

i know where is wrong in the code now.

in the code line “segmentId = inputsegmentation.GetSegmentation().GetSegmentIdBySegmentName(‘Segment_1’)“, the function “GetSegmentIdBySegmentName()“ won’t create a new segment in the existed segmentation but the effect of this function is to find a exised segment called “Segment_1“.

so, if you want use this code line, you need to create a new segment in segment editor and than use this code line to rewrite the segment with your own numpy array

further, i find in the following network link, there is a code line “addedSegmentID = segmentationNode.GetSegmentation().AddEmptySegment(segmentName)“ can create a new segment in chosen segmentation.

and i alter this code line as “segmentId = inputsegmentation.GetSegmentation().AddEmptySegment(‘Segment_1’)“ to replace the orginal code line “segmentId = inputsegmentation.GetSegmentation().GetSegmentIdBySegmentName(‘Segment_1’)“

after reloading the extension, now i can create a new segment in the chosen segmentation.

1 Like