Esempio n. 1
0
    def test_SimpleITK_SlicerPushPull(self):
        """ Download the MRHead node
        """
        import SampleData
        SampleData.downloadSample("MRHead")
        volumeNode1 = slicer.util.getNode('MRHead')
        self.assertEqual(volumeNode1.GetName(), "MRHead")
        """ Verify that pulling SimpleITK image from Slicer and then pushing it
        back creates an identical volume.
        """

        sitkimage = su.PullVolumeFromSlicer(volumeNode1)
        self.assertIsNotNone(sitkimage)

        volumeNode1Copy = su.PushVolumeToSlicer(
            sitkimage, name="MRHead", className="vtkMRMLScalarVolumeNode")
        self.assertIsNotNone(volumeNode1Copy)
        """ Verify that image is not overwritten but a new one is created """
        self.assertEqual(volumeNode1, slicer.util.getNode('MRHead'),
                         'Original volume is changed')
        self.assertNotEqual(volumeNode1, volumeNode1Copy,
                            'Copy of original volume is not created')
        """ Few modification of the image : Direction, Origin """
        sitkimage.SetDirection((-1.0, 1.0, 0.0, 0.0, -1.0, 1.0, 1.0, 0.0, 1.0))
        sitkimage.SetOrigin((100.0, 100.0, 100.0))
        """ Few pixel changed """
        size = sitkimage.GetSize()
        for x in range(0, size[0], int(size[0] / 10)):
            for y in range(0, size[1], int(size[1] / 10)):
                for z in range(0, size[2], int(size[2] / 10)):
                    sitkimage.SetPixel(x, y, z, 0)

        volumeNode1Modified = su.PushVolumeToSlicer(
            sitkimage,
            name="ImageChanged",
            className="vtkMRMLScalarVolumeNode")
        self.assertEqual(volumeNode1Modified.GetName(), "ImageChanged",
                         'Volume name is not set correctly')
        self.assertNotEqual(volumeNode1.GetMTime(),
                            volumeNode1Modified.GetMTime(),
                            'Error Push Pull: Modify Time are the same')
        """ Test the consistency between sitkimage and volumeNode1Modified
        """
        tmp = volumeNode1Modified.GetOrigin()
        valToCompare = (-tmp[0], -tmp[1], tmp[2])
        self.assertEqual(valToCompare, sitkimage.GetOrigin(),
                         'Modified origin mismatch')
        """ Test push with all parameter combinations """
        for volumeClassName in [
                'vtkMRMLScalarVolumeNode', 'vtkMRMLLabelMapVolumeNode'
        ]:
            volumeNodeTested = None
            volumeNodeNew = None
            for pushToNewNode in [True, False]:
                print("volumeClassName : %s" % volumeClassName)
                print("pushToNewNode : %s " % pushToNewNode)

                if pushToNewNode:
                    volumeNodeTested = su.PushVolumeToSlicer(
                        sitkimage,
                        name='volumeNode-' + volumeClassName + "-" +
                        str(pushToNewNode),
                        className=volumeClassName)
                    existingVolumeNode = volumeNodeTested
                else:
                    volumeNodeTested = su.PushVolumeToSlicer(
                        sitkimage, existingVolumeNode)

                self.assertEqual(volumeNodeTested.GetClassName(),
                                 volumeClassName,
                                 'Created volume node class is incorrect')

        slicer.mrmlScene.Clear(0)
    def registerVolume(self,
                       json_path,
                       fixedNode,
                       fixedMaskNode,
                       outputVolumeNode=None):

        modules = slicer.modules
        if hasattr(modules, 'ParsePathJsonWidget'):
            widgetPresent = True
        else:
            widgetPresent = False

        if widgetPresent:
            self.cmdStartEvent()
            slicer.app.processEvents()

        if not self.logic:
            import sys
            sys.path.append(os.path.join(self.scriptPath, "Resources",
                                         "Utils"))

            import ParsePathJsonUtils as ppju
            self.logic = ppju.ParsePathJsonUtils()
            self.logic.setPath(json_path)

            if not self.logic.successfulInitialization:
                success = self.logic.initComponents()
                if not success:
                    qt.QMessageBox.critical(
                        slicer.util.mainWindow(), "Error",
                        "Failure to load json. Check path!")
                    return

        if not str(self.logic.path) == str(json_path):
            self.logic.setPath(json_path)
            if not self.logic.successfulInitialization:
                success = self.logic.initComponents()
                if not success:
                    qt.QMessageBox.critical(
                        slicer.util.mainWindow(), "Error",
                        "Failure to load json. Check path!")
                    return

        if outputVolumeNode:
            import sitkUtils
            slicer.app.processEvents()

            self.logic.pathologyVolume.imagingContraint = sitkUtils.PullVolumeFromSlicer(
                fixedNode)
            self.logic.pathologyVolume.imagingContraintMask = sitkUtils.PullVolumeFromSlicer(
                fixedMaskNode)
            self.logic.pathologyVolume.registerSlices(True)

            outputVolume = self.logic.pathologyVolume.loadRgbVolume()
            sitkUtils.PushVolumeToSlicer(outputVolume,
                                         targetNode=outputVolumeNode)

            selectionNode = slicer.app.applicationLogic().GetSelectionNode()
            selectionNode.SetReferenceActiveVolumeID(outputVolumeNode.GetID())
            slicer.app.applicationLogic().PropagateVolumeSelection(0)
        else:
            qt.QMessageBox.critical(slicer.util.mainWindow(), "No Output",
                                    "Output Volume was not set!")

        if widgetPresent:
            self.cmdEndEvent()
Esempio n. 3
0
Author : Jason
Github : https://github.com/yuquant
Description : 
"""
import SimpleITK as sitk
import slicer
from slicer.util import *
import sitkUtils
# 导入nii图像和标签
image_path = r'D:/data/test_nii/prostate2label/images.nii.gz'
label_path = r'D:/data/test_nii/prostate2label/labels.nii.gz'
image_node = loadVolume(image_path)

label = sitk.ReadImage(label_path)
tmp_node = sitkUtils.PushVolumeToSlicer(sitkimage=label,
                                        targetNode=None,
                                        name='tmp',
                                        className='vtkMRMLLabelMapVolumeNode')
seg_node = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLSegmentationNode')

# seg_node_name = 'labels'
# seg_node = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLSegmentationNode', seg_node_name)
seg_node.SetName('seg')
# seg_node.CreateDefaultDisplayNodes()
# seg_node.GetSegmentation().AddEmptySegment()
# 如果不添加上边这两行,就会发生下边的现象(如果不经过标注,也会导致标注无法修改),可能是seg node 的创建方式不对
# segmentationNode = self.scriptedEffect.parameterSetNode().GetSegmentationNode()
# 在现有标签的基础上叠加
# 由于缺少reference图像,似乎导入的像素会按照最小外接矩形切割,导致影响标注(区域外无法标注)
# 目前存在的一个问题是标签的值的种类决定了标签数量,万一一个标签为空,则会导致所有顺序错位
slicer.modules.segmentations.logic().ImportLabelmapToSegmentationNode(
    tmp_node, seg_node)
Esempio n. 4
0
  def doCropping(self, inputVolume, point, croppingLength ):
        print("================= Begin cropping ... =====================")
        print("Cochlea location: " + str(point) + "   cropping length: " + str(croppingLength) )
        
        # resampling spacing  
        self.RSx= self.RSxyz[0] ; self.RSy= self.RSxyz[1];     self.RSz= self.RSxyz[2]

        #Get input image information 
        spacing = inputVolume.GetSpacing()
        imgData = inputVolume.GetImageData()
        dimensions = imgData.GetDimensions()
        
        # compute cropping bounds from image information and cropping parameters
        croppingBounds = [[0,0,0],[0,0,0]];   size = [0,0,0];    lower = [0,0,0] ;     upper = [0,0,0]
        for i in range(0,3):
            size[i] = int((self.croppingLength[i]/spacing[i])/2)
            lower[i] = int(point[i]) - int(size[i])
            upper[i] = dimensions[i] - int(point[i]+size[i])
            # Check if calculated boundaries exceed image dimensions
            if lower[i] < 0:
                    lower[i] = 0
            #endif        
            if upper[i] > dimensions[i]:
                   upper[i] = int(dimensions[i])
            #endif
        #endfor   
        croppingBounds = [lower,upper]
	# Call SimpleITK CropImageFilter
        print("Cropping with " + str(croppingBounds[0]) + " and " + str(croppingBounds[1]) + ".")
        inputImage = sitkUtils.PullVolumeFromSlicer(inputVolume.GetID())
        cropper = sitkUtils.sitk.CropImageFilter()
        croppedImage = cropper.Execute(inputImage, croppingBounds[0], croppingBounds[1])          
        nodeName = str(inputVolume.GetName()) + "_crop"
        self.inputCropPath = os.path.splitext(inputVolume.GetStorageNode().GetFileName())[0] + "_crop.nrrd"
        # Make a node with cropped image 
        sitkUtils.PushVolumeToSlicer(croppedImage, None, nodeName , 'vtkMRMLScalarVolumeNode' )
        crNodes = slicer.util.getNodesByClass("vtkMRMLScalarVolumeNode")
        for f in crNodes:
            if nodeName in f.GetName():
                 f.SetName(nodeName) 
                 break         
            #endif
        #endfor    

        self.croppedNode = slicer.util.getNode(nodeName)
        print("self.inputCropPath : " + str(self.inputCropPath ))
                
        #-------------------------------------------------------
        # Resampling: this produces better looking models  
        #-------------------------------------------------------
       #Run slicer cli module: resample scalar volume
        params = {} 
        params['InputVolume']  = self.croppedNode
        params['OutputVolume'] = self.croppedNode #Resample the cropped image inplace
        params['outputPixelSpacing'] = str(self.RSx) + "," + str(self.RSy) + "," + str(self.RSz) 
        params['interpolationType'] = 'bspline'
        print("....... Resampling")
        slicer.cli.runSync(slicer.modules.resamplescalarvolume, None, params)

        # Save the resulted image to be used in elastix
        properties = {}
        properties["fileType"] = ".nrrd"
        self.inputCropPath = os.path.splitext(inputVolume.GetStorageNode().GetFileName())[0] + "_crop_iso.nrrd"                                    
        print(" Cropping and resampling are done !!! ")
        # Save cropped image in directory of the original volume
        slicer.util.saveNode( self.croppedNode, self.inputCropPath)
        return self.inputCropPath
Esempio n. 5
0
    def updateSegmentationMask(self,
                               extreme_points,
                               in_file,
                               modelInfo,
                               overwriteCurrentSegment=False):
        start = time.time()
        logging.debug('Update Segmentation Mask from: {}'.format(in_file))
        if in_file is None or os.path.exists(in_file) is False:
            return False

        segmentationNode = self.scriptedEffect.parameterSetNode(
        ).GetSegmentationNode()
        segmentation = segmentationNode.GetSegmentation()
        currentSegment = self.currentSegment()

        labelImage = sitk.ReadImage(in_file)
        labelmapVolumeNode = sitkUtils.PushVolumeToSlicer(
            labelImage, None, className='vtkMRMLLabelMapVolumeNode')

        numberOfExistingSegments = segmentation.GetNumberOfSegments()
        slicer.modules.segmentations.logic().ImportLabelmapToSegmentationNode(
            labelmapVolumeNode, segmentationNode)
        slicer.mrmlScene.RemoveNode(labelmapVolumeNode)

        modelLabels = modelInfo['labels']
        numberOfAddedSegments = segmentation.GetNumberOfSegments(
        ) - numberOfExistingSegments
        logging.debug('Adding {} segments'.format(numberOfAddedSegments))
        addedSegmentIds = [
            segmentation.GetNthSegmentID(numberOfExistingSegments + i)
            for i in range(numberOfAddedSegments)
        ]
        for i, segmentId in enumerate(addedSegmentIds):
            segment = segmentation.GetSegment(segmentId)
            if i == 0 and overwriteCurrentSegment and currentSegment:
                logging.debug(
                    'Update current segment with id: {} => {}'.format(
                        segmentId, segment.GetName()))
                # Copy labelmap representation to the current segment then remove the imported segment
                labelmap = slicer.vtkOrientedImageData()
                segmentationNode.GetBinaryLabelmapRepresentation(
                    segmentId, labelmap)
                self.scriptedEffect.modifySelectedSegmentByLabelmap(
                    labelmap, slicer.qSlicerSegmentEditorAbstractEffect.
                    ModificationModeSet)
                segmentationNode.RemoveSegment(segmentId)
            else:
                logging.debug(
                    'Setting new segmentation with id: {} => {}'.format(
                        segmentId, segment.GetName()))
                if i < len(modelLabels):
                    segment.SetName(modelLabels[i])
                else:
                    # we did not get enough labels (for exampe annotation_mri_prostate_cg_and_pz model returns a labelmap with
                    # 2 labels but in the model infor only 1 label is provided)
                    segment.SetName("unknown {}".format(i))

        # Save extreme points into first segment
        if extreme_points:
            logging.debug('Extreme Points: {}'.format(extreme_points))
            if overwriteCurrentSegment and currentSegment:
                segment = currentSegment
            else:
                segment = segmentation.GetNthSegment(numberOfExistingSegments)
            if segment:
                segment.SetTag("AIAA.DExtr3DExtremePoints",
                               json.dumps(extreme_points))

        os.unlink(in_file)
        logging.info(
            "Time consumed by updateSegmentationMask: {0:3.1f}".format(
                time.time() - start))
        return True
    def run(self, inputVolume, fiducialMarker):
        """
    Run the actual algorithm
    """

        inputVolume_origin = inputVolume.GetOrigin()
        inputVolume_spacing = inputVolume.GetSpacing()
        inputVolume_size = inputVolume.GetImageData().GetDimensions()

        spine_img = sitkUtils.PullVolumeFromSlicer(inputVolume)

        size_of_bbox = np.ceil(
            np.array([128, 128, 64]) / np.array(inputVolume_spacing)).astype(
                np.int)

        fiducial_coords_world_hold = [0, 0, 0, 0]
        numFids = fiducialMarker.GetNumberOfFiducials()

        for idx in range(numFids):

            fiducialMarker.GetNthFiducialWorldCoordinates(
                idx, fiducial_coords_world_hold)

            fiducial_coords_world = fiducial_coords_world_hold

            fiducial_coords_world[0] = fiducial_coords_world[0] * (-1)
            fiducial_coords_world[1] = fiducial_coords_world[1] * (-1)

            # Bounding box is [128, 128, 64] in mm with respect to the world coordinates

            fiducial_coords = np.floor(
                spine_img.TransformPhysicalPointToIndex(
                    fiducial_coords_world[:3])).astype(np.int)

            ROI = sitk.RegionOfInterestImageFilter()
            ROI.SetSize([
                int(size_of_bbox[0]),
                int(size_of_bbox[1]),
                int(size_of_bbox[2])
            ])
            ROI_initial_index = fiducial_coords - size_of_bbox / 2
            ROI_initial_index = [
                roi_idx if roi_idx > 0 else 0 for roi_idx in ROI_initial_index
            ]
            ROI.SetIndex([
                int(ROI_initial_index[0]),
                int(ROI_initial_index[1]),
                int(ROI_initial_index[2])
            ])

            spine_img_cropped = ROI.Execute(spine_img)

            # Resample cropped spine image

            spacingOut = [1.0, 1.0, 1.0]
            resample = sitk.ResampleImageFilter()

            resample.SetReferenceImage(spine_img_cropped)
            resample.SetInterpolator(sitk.sitkLinear)

            shapeIn = spine_img_cropped.GetSize()
            spacingIn = spine_img_cropped.GetSpacing()

            newSize = [
                int(shapeIn[0] * spacingIn[0] / spacingOut[0]),
                int(shapeIn[1] * spacingIn[1] / spacingOut[1]),
                int(shapeIn[2] * spacingIn[2] / spacingOut[2])
            ]

            resample.SetSize(newSize)

            resample.SetOutputSpacing(spacingOut)
            spine_img_resampled = resample.Execute(spine_img_cropped)

            # Second cropping to ensure image is the right size. Could be off my a 1 due to rounding.

            ROI = sitk.RegionOfInterestImageFilter()
            ROI.SetSize([128, 128, 64])
            ROI.SetIndex([0, 0, 0])

            spine_img_resampled = ROI.Execute(spine_img_resampled)

            # Get the spine data in a numpy array.
            spine_data = sitk.GetArrayFromImage(spine_img_resampled)

            y_pred_np = self.segment_vertebrae(spine_data)

            y_pred_sitk = sitk.GetImageFromArray(y_pred_np)
            y_pred_sitk.CopyInformation(spine_img_resampled)

            resample_back = sitk.ResampleImageFilter()

            resample_back.SetReferenceImage(spine_img)

            affine = sitk.AffineTransform(3)

            resample_back.SetTransform(affine)

            resample_back.SetInterpolator(sitk.sitkNearestNeighbor)
            y_pred_sitk_full_size = resample_back.Execute(y_pred_sitk)

            #self.seg_pred = sitkUtils.PushVolumeToSlicer(y_pred_sitk)

            self.segVolumeNode = sitkUtils.PushVolumeToSlicer(
                y_pred_sitk_full_size,
                name='segPrediction',
                className='vtkMRMLLabelMapVolumeNode')

        return True
Esempio n. 7
0
    def generateSurfaceModel(self, markupsNode, modelNode,
                             pointDistanceFactor):

        svnode = slicer.mrmlScene.CreateNodeByClass('vtkMRMLScalarVolumeNode')

        print('Generating a surface model from tracking data... ')

        ## Generate a scalar volume node
        # Get the bounding box
        print('Calculating bounding box... ')
        bounds = [0.0] * 6
        markupsNode.GetBounds(bounds)
        print(bounds)

        b = numpy.array(bounds)
        b = b.reshape((3, 2))
        origin = numpy.mean(b, axis=1)
        fov = numpy.abs(b[:, 1] - b[:, 0])
        fovMax = numpy.max(fov)
        boundingBoxRange = (
            fovMax * 1.5
        ) / 2.0  # 1.5 times larger than the bounding box; from the center to the end (1/2 of each dimension)
        b[:, 0] = origin - boundingBoxRange
        b[:, 1] = origin + boundingBoxRange
        bounds = b.reshape(-1)
        print(bounds)
        res = 256

        print('Converting fiducials to poly data...')
        poly = self.fiducialsToPoly(markupsNode)

        #Note: Altenatively, vtkImageEllipsoidSource may be used to generate a volume.
        # Generate density field from points
        # Use fixed radius
        print('Running vtkPointDensityFilter...')
        dens = vtk.vtkPointDensityFilter()
        dens.SetInputData(poly)

        # TODO - is the resolution good enoguh?
        dens.SetSampleDimensions(res, res, res)
        dens.SetDensityEstimateToFixedRadius()
        # TODO - Does this radius work for every case?
        pixelSize = boundingBoxRange * 2 / res

        # Note: the algorithm fails when the bounding box is too small..
        if pixelSize < 0.5:
            pixelSize = 0.5

        radius = pixelSize
        dens.SetRadius(radius)
        #dens.SetDensityEstimateToRelativeRadius()
        #dens.SetRelativeRadius(2.5)
        #dens.SetDensityFormToVolumeNormalized()
        dens.SetDensityFormToNumberOfPoints()
        dens.SetModelBounds(bounds)
        dens.ComputeGradientOn()
        dens.Update()

        print('Creating an image node...')
        # Crete an image node - geometric parameters (origin, spacing) must be moved to the node object
        #imnode = slicer.vtkMRMLScalarVolumeNode()
        imnode = slicer.mrmlScene.CreateNodeByClass('vtkMRMLScalarVolumeNode')
        imnode.SetName('MRTracking_SurfaceMap_tmp')
        imdata = dens.GetOutput()
        imnode.SetAndObserveImageData(imdata)
        imnode.SetOrigin(imdata.GetOrigin())
        imnode.SetSpacing(imdata.GetSpacing())
        #imdata.SetOrigin([0.0, 0.0, 0.0])
        #imdata.SetSpacing([1.0, 1.0, 1.0])
        slicer.mrmlScene.AddNode(imnode)

        print('Applying BinaryThreshold...')
        image = sitkUtils.PullVolumeFromSlicer(imnode.GetID())
        binImage = sitk.BinaryThreshold(image,
                                        lowerThreshold=1.0,
                                        upperThreshold=256,
                                        insideValue=1,
                                        outsideValue=0)

        # Calculate the radius parameter for dilation and erosion
        radiusInPixel = int(numpy.ceil(pointDistanceFactor / pixelSize))
        if radiusInPixel < 1.0:
            radiusInPixel = 1

        # Dilate the target label
        print('Dilating the image...')
        dilateFilter = sitk.BinaryDilateImageFilter()
        dilateFilter.SetBoundaryToForeground(False)
        dilateFilter.SetKernelRadius(radiusInPixel)
        dilateFilter.SetKernelType(sitk.sitkBall)
        dilateFilter.SetForegroundValue(1)
        dilateFilter.SetBackgroundValue(0)
        dilateImage = dilateFilter.Execute(binImage)

        # Fill holes in the target label
        print('Filling holes...')
        fillHoleFilter = sitk.BinaryFillholeImageFilter()
        fillHoleFilter.SetForegroundValue(1)
        fillHoleFilter.SetFullyConnected(True)
        fillHoleImage = fillHoleFilter.Execute(dilateImage)

        # Erode the label
        print('Eroding the image...')
        erodeFilter = sitk.BinaryErodeImageFilter()
        erodeFilter.SetBoundaryToForeground(False)
        erodeFilter.SetKernelType(sitk.sitkBall)
        erodeFilter.SetKernelRadius(
            radiusInPixel - 1)  # 1 pixel smaller than the radius for dilation.
        erodeFilter.SetForegroundValue(1)
        erodeFilter.SetBackgroundValue(0)
        erodeImage = erodeFilter.Execute(fillHoleImage)

        print('Pushing the volume to the MRML scene...')
        sitkUtils.PushVolumeToSlicer(erodeImage, imnode.GetName(), 0, True)
        imdata = imnode.GetImageData()

        imdata.SetOrigin(imnode.GetOrigin())
        imdata.SetSpacing(imnode.GetSpacing())

        print('Running marching cubes...')
        poly = self.marchingCubes(imdata)
        modelNode.SetAndObservePolyData(poly)

        slicer.mrmlScene.RemoveNode(imnode)
        print('Done.')
Esempio n. 8
0
    def run(self, gtCTVolumeName, sCTVolumeName, maskVolumeName, outputVolume):
        """
    Run accuracy assessment.
    """

        # Get sitk/numpy images from Slicer
        gtCT_sitk = sitk.Cast(sitkUtils.PullVolumeFromSlicer(gtCTVolumeName),
                              sitk.sitkFloat32)
        sCT_sitk = sitk.Cast(sitkUtils.PullVolumeFromSlicer(sCTVolumeName),
                             sitk.sitkFloat32)
        mask_sitk = sitk.Cast(sitkUtils.PullVolumeFromSlicer(maskVolumeName),
                              sitk.sitkLabelUInt8)
        mask_sitk = sitk.LabelMapToBinary(mask_sitk)
        #TODO: investigate better if mask is binary or not here

        gtCT = sitk.GetArrayFromImage(gtCT_sitk).astype(np.float32)
        sCT = sitk.GetArrayFromImage(sCT_sitk).astype(np.float32)
        mask = self.binarizeNumpyMask(sitk.GetArrayFromImage(mask_sitk))

        # Compute MAE and ME
        img_difference = gtCT - sCT

        img_difference[mask == 0] = -1000
        img_difference_sitk = sitk.GetImageFromArray(img_difference)
        img_difference_sitk.CopyInformation(gtCT_sitk)

        img_difference[mask == 0] = np.nan
        mae = np.nanmean(np.abs(img_difference).flatten())
        me = np.nanmean(img_difference.flatten())

        # If the table does not exist, create it
        if self.hasTable == False:

            self.hasTable = True

            # Create table
            self.tableNode = slicer.mrmlScene.AddNewNodeByClass(
                "vtkMRMLTableNode")
            self.table = self.tableNode.GetTable()
            arrX = vtk.vtkFloatArray()
            arrX.SetName("HU")
            self.table.AddColumn(arrX)

            arrY = vtk.vtkFloatArray()
            arrY.SetName("DSC")
            self.table.AddColumn(arrY)

            # Create plot node
            plotSeriesNode = slicer.mrmlScene.AddNewNodeByClass(
                "vtkMRMLPlotSeriesNode", "Bone threshold segmentation")
            plotSeriesNode.SetAndObserveTableNodeID(self.tableNode.GetID())
            plotSeriesNode.SetXColumnName("HU")
            plotSeriesNode.SetYColumnName("DSC")
            plotSeriesNode.SetPlotType(
                slicer.vtkMRMLPlotSeriesNode.PlotTypeScatter)
            plotSeriesNode.SetMarkerStyle(
                slicer.vtkMRMLPlotSeriesNode.MarkerStyleSquare)
            plotSeriesNode.SetUniqueColor()

            # Create plot chart node
            self.plotChartNode = slicer.mrmlScene.AddNewNodeByClass(
                "vtkMRMLPlotChartNode")
            self.plotChartNode.AddAndObservePlotSeriesNodeID(
                plotSeriesNode.GetID())
            self.plotChartNode.SetTitle('Bone threshold assessment')
            self.plotChartNode.SetXAxisTitle('[HU]')
            self.plotChartNode.SetYAxisTitle('DSC')
            self.plotChartNode.LegendVisibilityOff()

        # Fill table with DSC value for bone
        thrs = np.arange(100.0, 1100.0, 100.0)
        self.table.SetNumberOfRows(len(thrs))

        overlap_measures_filter = sitk.LabelOverlapMeasuresImageFilter()

        for i, thr in enumerate(thrs):
            gtCT_bin = sitk.BinaryThreshold(sitk.Mask(gtCT_sitk,
                                                      mask_sitk,
                                                      outsideValue=-1000),
                                            lowerThreshold=thr,
                                            upperThreshold=1500.0,
                                            insideValue=1,
                                            outsideValue=0)
            sCT_bin = sitk.BinaryThreshold(sitk.Mask(sCT_sitk,
                                                     mask_sitk,
                                                     outsideValue=-1000),
                                           lowerThreshold=thr,
                                           upperThreshold=1500.0,
                                           insideValue=1,
                                           outsideValue=0)

            overlap_measures_filter.Execute(gtCT_bin, sCT_bin)
            dsc = overlap_measures_filter.GetDiceCoefficient()

            # TODO: empty table before each run?
            self.table.SetValue(i, 0, thr)
            self.table.SetValue(i, 1, dsc)

        # Switch to a layout that contains a plot view to create a plot widget
        layoutManager = slicer.app.layoutManager()
        layoutWithPlot = slicer.modules.plots.logic().GetLayoutWithPlot(
            layoutManager.layout)
        layoutManager.setLayout(layoutWithPlot)

        # Select chart in plot view
        plotWidget = layoutManager.plotWidget(0)
        plotViewNode = plotWidget.mrmlPlotViewNode()
        plotViewNode.SetPlotChartNodeID(self.plotChartNode.GetID())

        # Show diff image
        outputVolume = sitkUtils.PushVolumeToSlicer(img_difference_sitk,
                                                    outputVolume)
        setSliceViewerLayers(background=outputVolume)
        displayNode = outputVolume.GetDisplayNode()
        displayNode.SetAndObserveColorNodeID('vtkMRMLColorTableNodeRainbow')

        return mae, me
    def updateSegmentationMask(self, extreme_points, in_file, modelInfo):
        start = time.time()
        logging.debug('Update Segmentation Mask from: {}'.format(in_file))
        if in_file is None or os.path.exists(in_file) is False:
            return False

        segmentationNode = self.scriptedEffect.parameterSetNode(
        ).GetSegmentationNode()
        selectedSegmentId = self.scriptedEffect.parameterSetNode(
        ).GetSelectedSegmentID()

        segmentation = segmentationNode.GetSegmentation()
        segment = segmentation.GetSegment(selectedSegmentId)
        color = segment.GetColor()
        label = segment.GetName()

        labelImage = sitk.ReadImage(in_file)
        labelmapVolumeNode = sitkUtils.PushVolumeToSlicer(
            labelImage, None, className='vtkMRMLLabelMapVolumeNode')
        labelmapVolumeNode.SetName(label)
        # [success, labelmapVolumeNode] = slicer.util.loadLabelVolume(in_file, {'name': label}, returnNode=True)

        logging.debug(
            'Removing temp segmentation with id: {} with color: {}'.format(
                selectedSegmentId, color))
        segmentationNode.RemoveSegment(selectedSegmentId)

        originalSegments = dict()
        for i in range(segmentation.GetNumberOfSegments()):
            segmentId = segmentation.GetNthSegmentID(i)
            originalSegments[segmentId] = i

        slicer.modules.segmentations.logic().ImportLabelmapToSegmentationNode(
            labelmapVolumeNode, segmentationNode)
        slicer.mrmlScene.RemoveNode(labelmapVolumeNode)

        addedSegments = 0
        modelLabels = modelInfo.get('labels')
        for i in range(segmentation.GetNumberOfSegments()):
            segmentId = segmentation.GetNthSegmentID(i)
            segment = segmentation.GetSegment(segmentId)
            if originalSegments.get(segmentId) is not None:
                logging.debug(
                    'No change for existing segment with id: {} => {}'.format(
                        segmentId, segment.GetName()))
                continue

            logging.debug('Setting new segmentation with id: {} => {}'.format(
                segmentId, segment.GetName()))
            if addedSegments == 0:
                segment.SetColor(color)
                segment.SetName(label)

                self.scriptedEffect.parameterSetNode().SetSelectedSegmentID(
                    segmentId)
                logging.debug('Extreme Points: {}'.format(extreme_points))
                if extreme_points is not None:
                    segment.SetTag("DExtr3DExtremePoints",
                                   json.dumps(extreme_points))

            else:
                segment.SetName(modelLabels[addedSegments])
            addedSegments = addedSegments + 1
        logging.debug('Total Added Segments for {}: {}'.format(
            label, addedSegments))

        self.extremePoints[label] = extreme_points
        os.unlink(in_file)
        logging.info("++ Time consumed by updateSegmentationMask: {}".format(
            time.time() - start))
        return True