def runMasking(self, ijkPoints, seedLabelmap, outputLabelmap):
    kernelSizePixel = self.getKernelSizePixel()

    self.floodFillingFilterIsland = vtk.vtkImageThresholdConnectivity()
    self.floodFillingFilterIsland.SetInputData(seedLabelmap)
    self.floodFillingFilterIsland.SetInValue(BACKGROUND_VALUE)
    self.floodFillingFilterIsland.ReplaceInOn()
    self.floodFillingFilterIsland.ReplaceOutOff()
    self.floodFillingFilterIsland.ThresholdBetween(LABEL_VALUE, LABEL_VALUE)
    self.floodFillingFilterIsland.SetSeedPoints(ijkPoints)

    self.dilate = vtk.vtkImageDilateErode3D()
    self.dilate.SetInputConnection(self.floodFillingFilterIsland.GetOutputPort())
    self.dilate.SetDilateValue(LABEL_VALUE)
    self.dilate.SetErodeValue(BACKGROUND_VALUE)
    self.dilate.SetKernelSize(
      2*kernelSizePixel[0]-1,
      2*kernelSizePixel[1]-1,
      2*kernelSizePixel[2]-1)
    self.dilate.Update()

    self.imageMask = vtk.vtkImageMask()
    self.imageMask.SetInputConnection(self.thresh.GetOutputPort())
    self.imageMask.SetMaskedOutputValue(BACKGROUND_VALUE)
    self.imageMask.NotMaskOn()
    self.imageMask.SetMaskInputData(self.dilate.GetOutput())

    self.floodFillingFilter = vtk.vtkImageThresholdConnectivity()
    self.floodFillingFilter.SetInputConnection(self.imageMask.GetOutputPort())
    self.floodFillingFilter.SetInValue(LABEL_VALUE)
    self.floodFillingFilter.SetOutValue(BACKGROUND_VALUE)
    self.floodFillingFilter.ThresholdBetween(LABEL_VALUE, LABEL_VALUE)
    self.floodFillingFilter.SetSeedPoints(ijkPoints)
    self.floodFillingFilter.Update()
    outputLabelmap.ShallowCopy(self.floodFillingFilter.GetOutput())
Beispiel #2
0
    def processInteractionEvents(self, callerInteractor, eventId, viewWidget):
        import vtkSegmentationCorePython as vtkSegmentationCore

        abortEvent = False

        # Only allow in modes where segment selection is needed
        if not self.currentOperationRequiresSegmentSelection():
            return False

        # Only allow for slice views
        if viewWidget.className() != "qMRMLSliceWidget":
            return abortEvent

        if eventId != vtk.vtkCommand.LeftButtonPressEvent:
            return abortEvent

        abortEvent = True

        # Generate merged labelmap of all visible segments
        segmentationNode = self.scriptedEffect.parameterSetNode(
        ).GetSegmentationNode()
        visibleSegmentIds = vtk.vtkStringArray()
        segmentationNode.GetDisplayNode().GetVisibleSegmentIDs(
            visibleSegmentIds)
        if visibleSegmentIds.GetNumberOfValues() == 0:
            logging.info(
                "Smoothing operation skipped: there are no visible segments")
            return abortEvent

        self.scriptedEffect.saveStateForUndo()

        # This can be a long operation - indicate it to the user
        qt.QApplication.setOverrideCursor(qt.Qt.WaitCursor)

        operationName = self.scriptedEffect.parameter("Operation")

        if operationName == ADD_SELECTED_ISLAND:
            inputLabelImage = vtkSegmentationCore.vtkOrientedImageData()
            if not segmentationNode.GenerateMergedLabelmapForAllSegments(
                    inputLabelImage, vtkSegmentationCore.vtkSegmentation.
                    EXTENT_UNION_OF_SEGMENTS_PADDED, None, visibleSegmentIds):
                logging.error(
                    'Failed to apply smoothing: cannot get list of visible segments'
                )
                qt.QApplication.restoreOverrideCursor()
                return abortEvent
        else:
            selectedSegmentLabelmap = self.scriptedEffect.selectedSegmentLabelmap(
            )
            # We need to know exactly the value of the segment voxels, apply threshold to make force the selected label value
            labelValue = 1
            backgroundValue = 0
            thresh = vtk.vtkImageThreshold()
            thresh.SetInputData(selectedSegmentLabelmap)
            thresh.ThresholdByLower(0)
            thresh.SetInValue(backgroundValue)
            thresh.SetOutValue(labelValue)
            thresh.SetOutputScalarType(selectedSegmentLabelmap.GetScalarType())
            thresh.Update()
            # Create oriented image data from output
            import vtkSegmentationCorePython as vtkSegmentationCore
            inputLabelImage = vtkSegmentationCore.vtkOrientedImageData()
            inputLabelImage.ShallowCopy(thresh.GetOutput())
            selectedSegmentLabelmapImageToWorldMatrix = vtk.vtkMatrix4x4()
            selectedSegmentLabelmap.GetImageToWorldMatrix(
                selectedSegmentLabelmapImageToWorldMatrix)
            inputLabelImage.SetImageToWorldMatrix(
                selectedSegmentLabelmapImageToWorldMatrix)

        xy = callerInteractor.GetEventPosition()
        ijk = self.xyToIjk(xy, viewWidget, inputLabelImage)
        pixelValue = inputLabelImage.GetScalarComponentAsFloat(
            ijk[0], ijk[1], ijk[2], 0)

        try:

            floodFillingFilter = vtk.vtkImageThresholdConnectivity()
            floodFillingFilter.SetInputData(inputLabelImage)
            seedPoints = vtk.vtkPoints()
            origin = inputLabelImage.GetOrigin()
            spacing = inputLabelImage.GetSpacing()
            seedPoints.InsertNextPoint(origin[0] + ijk[0] * spacing[0],
                                       origin[1] + ijk[1] * spacing[1],
                                       origin[2] + ijk[2] * spacing[2])
            floodFillingFilter.SetSeedPoints(seedPoints)
            floodFillingFilter.ThresholdBetween(pixelValue, pixelValue)

            if operationName == ADD_SELECTED_ISLAND:
                floodFillingFilter.SetInValue(1)
                floodFillingFilter.SetOutValue(0)
                floodFillingFilter.Update()
                modifierLabelmap = self.scriptedEffect.defaultModifierLabelmap(
                )
                modifierLabelmap.DeepCopy(floodFillingFilter.GetOutput())
                self.scriptedEffect.modifySelectedSegmentByLabelmap(
                    modifierLabelmap, slicer.
                    qSlicerSegmentEditorAbstractEffect.ModificationModeAdd)

            elif pixelValue != 0:  # if clicked on empty part then there is nothing to remove or keep

                if operationName == KEEP_SELECTED_ISLAND:
                    floodFillingFilter.SetInValue(1)
                    floodFillingFilter.SetOutValue(0)
                else:  # operationName == REMOVE_SELECTED_ISLAND:
                    floodFillingFilter.SetInValue(1)
                    floodFillingFilter.SetOutValue(0)

                floodFillingFilter.Update()
                modifierLabelmap = self.scriptedEffect.defaultModifierLabelmap(
                )
                modifierLabelmap.DeepCopy(floodFillingFilter.GetOutput())

                if operationName == KEEP_SELECTED_ISLAND:
                    self.scriptedEffect.modifySelectedSegmentByLabelmap(
                        modifierLabelmap, slicer.
                        qSlicerSegmentEditorAbstractEffect.ModificationModeSet)
                else:  # operationName == REMOVE_SELECTED_ISLAND:
                    self.scriptedEffect.modifySelectedSegmentByLabelmap(
                        modifierLabelmap,
                        slicer.qSlicerSegmentEditorAbstractEffect.
                        ModificationModeRemove)

        except IndexError:
            logging.error('apply: Failed to threshold master volume!')
        finally:
            qt.QApplication.restoreOverrideCursor()

        return abortEvent
  def processInteractionEvents(self, callerInteractor, eventId, viewWidget):
    import vtkSegmentationCorePython as vtkSegmentationCore

    abortEvent = False

    # Only allow in modes where segment selection is needed
    if not self.currentOperationRequiresSegmentSelection():
      return False

    # Only allow for slice views
    if viewWidget.className() != "qMRMLSliceWidget":
      return abortEvent

    if eventId != vtk.vtkCommand.LeftButtonPressEvent:
      return abortEvent

    abortEvent = True

    # Generate merged labelmap of all visible segments
    segmentationNode = self.scriptedEffect.parameterSetNode().GetSegmentationNode()
    visibleSegmentIds = vtk.vtkStringArray()
    segmentationNode.GetDisplayNode().GetVisibleSegmentIDs(visibleSegmentIds)
    if visibleSegmentIds.GetNumberOfValues() == 0:
      logging.info("Smoothing operation skipped: there are no visible segments")
      return abortEvent

    self.scriptedEffect.saveStateForUndo()

    # This can be a long operation - indicate it to the user
    qt.QApplication.setOverrideCursor(qt.Qt.WaitCursor)

    operationName = self.scriptedEffect.parameter("Operation")

    if operationName == ADD_SELECTED_ISLAND:
      inputLabelImage = vtkSegmentationCore.vtkOrientedImageData()
      if not segmentationNode.GenerateMergedLabelmapForAllSegments(inputLabelImage,
                                                                   vtkSegmentationCore.vtkSegmentation.EXTENT_UNION_OF_SEGMENTS_PADDED,
                                                                   None, visibleSegmentIds):
        logging.error('Failed to apply smoothing: cannot get list of visible segments')
        qt.QApplication.restoreOverrideCursor()
        return abortEvent
    else:
      selectedSegmentLabelmap = self.scriptedEffect.selectedSegmentLabelmap()
      # We need to know exactly the value of the segment voxels, apply threshold to make force the selected label value
      labelValue = 1
      backgroundValue = 0
      thresh = vtk.vtkImageThreshold()
      thresh.SetInputData(selectedSegmentLabelmap)
      thresh.ThresholdByLower(0)
      thresh.SetInValue(backgroundValue)
      thresh.SetOutValue(labelValue)
      thresh.SetOutputScalarType(selectedSegmentLabelmap.GetScalarType())
      thresh.Update()
      # Create oriented image data from output
      import vtkSegmentationCorePython as vtkSegmentationCore
      inputLabelImage = vtkSegmentationCore.vtkOrientedImageData()
      inputLabelImage.ShallowCopy(thresh.GetOutput())
      selectedSegmentLabelmapImageToWorldMatrix = vtk.vtkMatrix4x4()
      selectedSegmentLabelmap.GetImageToWorldMatrix(selectedSegmentLabelmapImageToWorldMatrix)
      inputLabelImage.SetImageToWorldMatrix(selectedSegmentLabelmapImageToWorldMatrix)

    xy = callerInteractor.GetEventPosition()
    ijk = self.xyToIjk(xy, viewWidget, inputLabelImage)
    pixelValue = inputLabelImage.GetScalarComponentAsFloat(ijk[0], ijk[1], ijk[2], 0)

    try:

      floodFillingFilter = vtk.vtkImageThresholdConnectivity()
      floodFillingFilter.SetInputData(inputLabelImage)
      seedPoints = vtk.vtkPoints()
      origin = inputLabelImage.GetOrigin()
      spacing = inputLabelImage.GetSpacing()
      seedPoints.InsertNextPoint(origin[0]+ijk[0]*spacing[0], origin[1]+ijk[1]*spacing[1], origin[2]+ijk[2]*spacing[2])
      floodFillingFilter.SetSeedPoints(seedPoints)
      floodFillingFilter.ThresholdBetween(pixelValue, pixelValue)

      if operationName == ADD_SELECTED_ISLAND:
        floodFillingFilter.SetInValue(1)
        floodFillingFilter.SetOutValue(0)
        floodFillingFilter.Update()
        modifierLabelmap = self.scriptedEffect.defaultModifierLabelmap()
        modifierLabelmap.DeepCopy(floodFillingFilter.GetOutput())
        self.scriptedEffect.modifySelectedSegmentByLabelmap(modifierLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeAdd)

      elif pixelValue != 0: # if clicked on empty part then there is nothing to remove or keep

        if operationName == KEEP_SELECTED_ISLAND:
          floodFillingFilter.SetInValue(1)
          floodFillingFilter.SetOutValue(0)
        else: # operationName == REMOVE_SELECTED_ISLAND:
          floodFillingFilter.SetInValue(1)
          floodFillingFilter.SetOutValue(0)

        floodFillingFilter.Update()
        modifierLabelmap = self.scriptedEffect.defaultModifierLabelmap()
        modifierLabelmap.DeepCopy(floodFillingFilter.GetOutput())

        if operationName == KEEP_SELECTED_ISLAND:
          self.scriptedEffect.modifySelectedSegmentByLabelmap(modifierLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeSet)
        else: # operationName == REMOVE_SELECTED_ISLAND:
          self.scriptedEffect.modifySelectedSegmentByLabelmap(modifierLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeRemove)

    except IndexError:
      logging.error('apply: Failed to threshold master volume!')
    finally:
      qt.QApplication.restoreOverrideCursor()

    return abortEvent
Beispiel #4
0
        cnt += 1

# Print idx and seed position coordinates
print "idx: ", idx_seed
print "seed position: ", pos_seed

# Seed input
seed = vtk.vtkPoints()
for i in range(len(pos_seed)):
    ix = pos_seed[i][0]
    iy = pos_seed[i][1]
    iz = pos_seed[i][2]
    seed.InsertNextPoint([ix, iy, iz])

# Image Threshold Connectivity
connectivityFilter = vtk.vtkImageThresholdConnectivity()
connectivityFilter.SetInputConnection(reader.GetOutputPort())
connectivityFilter.SetSeedPoints(seed)
connectivityFilter.ThresholdByUpper(1)
connectivityFilter.ReplaceInOn()
connectivityFilter.SetInValue(1)
connectivityFilter.ReplaceOutOn()
connectivityFilter.SetOutValue(0)
connectivityFilter.Update()

# Surface extraction using Marching Cube algorithm
vmc2 = surfextract(connectivityFilter)

# Write output as STL file
saveSTL(vmc2, "bonus_connectivity_imgthresh")
Beispiel #5
0
    def processInteractionEvents(self, callerInteractor, eventId, viewWidget):
        abortEvent = False

        # Only allow for slice views
        if viewWidget.className() != "qMRMLSliceWidget":
            return abortEvent

        if eventId == vtk.vtkCommand.LeftButtonPressEvent:
            self.scriptedEffect.saveStateForUndo()

            # Get master volume image data
            import vtkSegmentationCorePython as vtkSegmentationCore
            masterImageData = self.scriptedEffect.masterVolumeImageData()
            selectedSegmentLabelmap = self.scriptedEffect.selectedSegmentLabelmap(
            )

            # Get modifier labelmap
            modifierLabelmap = self.scriptedEffect.defaultModifierLabelmap()

            xy = callerInteractor.GetEventPosition()
            ijk = self.xyToIjk(xy, viewWidget, masterImageData)

            pixelValue = masterImageData.GetScalarComponentAsFloat(
                ijk[0], ijk[1], ijk[2], 0)

            useSegmentationAsStencil = False

            try:

                # This can be a long operation - indicate it to the user
                qt.QApplication.setOverrideCursor(qt.Qt.WaitCursor)

                # Perform thresholding
                floodFillingFilter = vtk.vtkImageThresholdConnectivity()
                floodFillingFilter.SetInputData(masterImageData)
                seedPoints = vtk.vtkPoints()
                origin = masterImageData.GetOrigin()
                spacing = masterImageData.GetSpacing()
                seedPoints.InsertNextPoint(origin[0] + ijk[0] * spacing[0],
                                           origin[1] + ijk[1] * spacing[1],
                                           origin[2] + ijk[2] * spacing[2])
                floodFillingFilter.SetSeedPoints(seedPoints)

                neighborhoodSizeMm = self.neighborhoodSizeMmSlider.value
                floodFillingFilter.SetNeighborhoodRadius(
                    neighborhoodSizeMm, neighborhoodSizeMm, neighborhoodSizeMm)
                floodFillingFilter.SetNeighborhoodFraction(0.5)

                if useSegmentationAsStencil:
                    stencilFilter = vtk.vtkImageToImageStencil()
                    stencilFilter.SetInputData(selectedSegmentLabelmap)
                    stencilFilter.ThresholdByLower(0)
                    stencilFilter.Update()
                    floodFillingFilter.SetStencilData(
                        stencilFilter.GetOutput())

                pixelValueTolerance = float(
                    self.intensityToleranceSlider.value)
                floodFillingFilter.ThresholdBetween(
                    pixelValue - pixelValueTolerance,
                    pixelValue + pixelValueTolerance)

                floodFillingFilter.SetInValue(1)
                floodFillingFilter.SetOutValue(0)
                floodFillingFilter.Update()
                modifierLabelmap.DeepCopy(floodFillingFilter.GetOutput())
            except IndexError:
                logging.error('apply: Failed to threshold master volume!')
            finally:
                qt.QApplication.restoreOverrideCursor()

            # Apply changes
            self.scriptedEffect.modifySelectedSegmentByLabelmap(
                modifierLabelmap,
                slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeAdd)
            abortEvent = True

        return abortEvent
Beispiel #6
0
    def segmentFromSeeds(self, images,  image_pos_pat, image_ori_pat, seeds, iren, xplane, yplane, zplane):
        """ segmentFromSeeds: Extracts VOI from seeds
        
        INPUTS:
        =======        
        images: (vtkImageData)   list of Input image to Transform
        seeds: vtkPoints    list of seeded coordinates from picker
        OUTPUTS:
        =======
        transformed_image (vtkImageData)    Transformed imaged mapped to dicom coords frame
        transform (vtkTransform)            Transform used
        
        """
        for postS in range(1,len(images)):
            print "\n Segmenting image post no : %s " % str(postS)
            
            subimage = self.loadDisplay.subImage(images, postS)            
            
            # Proceed to build reference frame for display objects based on DICOM coords   
            [transformed_image, transform_cube] = self.loadDisplay.dicomTransform(subimage, image_pos_pat, image_ori_pat)
            
            # Calculate the center of the volume
            transformed_image.UpdateInformation() 
                    
            print "\nBoxwidget placed..."
            #################################################################
            # The box widget observes the events invoked by the render window
            # interactor.  These events come from user interaction in the render
            # window.
            # Place the interactor initially. The output of the reader is used to
            # place the box widget.
            self.boxWidget = vtk.vtkBoxWidget()
            self.boxWidget.SetInteractor(iren)
            self.boxWidget.SetPlaceFactor(1)
            self.boxWidget.SetInput(transformed_image)
            if( self.boundsPlane_presel != []):
                self.boxWidget.PlaceWidget( self.boundsPlane_presel )
            
            # Construct a bounding box around the seeds  
            init_seedsBounds = [0,0,0,0,0,0]
            seeds.GetBounds( init_seedsBounds )
            
            if postS == 1:        
                # polygonal data --> image stencil:
                # create a simple box VOI mask shape using previously found boundsPlane_preselected
                VOIStencil = vtk.vtkROIStencilSource()
                VOIStencil.SetShapeToBox()
                VOIStencil.SetBounds( init_seedsBounds )    
                VOIStencil.SetInformationInput(transformed_image)
                VOIStencil.Update()
            
                # cut the corresponding VOI region and set the background:
                extractVOI_imgstenc = vtk.vtkImageStencil()
                extractVOI_imgstenc.SetInput(transformed_image)
                extractVOI_imgstenc.SetStencil(VOIStencil.GetOutput())
                extractVOI_imgstenc.ReverseStencilOff()
                extractVOI_imgstenc.SetBackgroundValue(0.0)
                extractVOI_imgstenc.Update()
                
                allSeededIm = vtk.vtkImageData()
                allSeededIm.DeepCopy( extractVOI_imgstenc.GetOutput() )
        
                # Add some bounding box radius
                self.boxWidget.PlaceWidget( init_seedsBounds )
                self.boundsPlane_presel = init_seedsBounds
                print "seeds.GetBounds"
                print init_seedsBounds
                        
                self.boxWidget.AddObserver("InteractionEvent", self.SelectPolygons)
                self.boxWidget.On()
            
                # turn off planes
                xplane.Off()
                yplane.Off()
                iren.Start()
                self.boxWidget.Off()
            
            # polygonal data --> image stencil:
            print "\n Create vtkPolyDataToImageStencil with bounds:"
            print self.boundsPlane_presel
            
            # create a simple box VOI mask shape using previously found boundsPlane_preselected
            VOIStencil = vtk.vtkROIStencilSource()
            VOIStencil.SetShapeToBox()
            VOIStencil.SetBounds( self.boundsPlane_presel )    
            VOIStencil.SetInformationInput(transformed_image)
            VOIStencil.Update()
                                    
            # cut the corresponding VOI region and set the background:
            extractVOI_imgstenc = vtk.vtkImageStencil()
            extractVOI_imgstenc.SetInput(transformed_image)
            extractVOI_imgstenc.SetStencil(VOIStencil.GetOutput())
            extractVOI_imgstenc.ReverseStencilOff()
            extractVOI_imgstenc.SetBackgroundValue(0.0)
            extractVOI_imgstenc.Update()
                
            # add subsecuent VOI stencils
            addsegROI = vtk.vtkImageMathematics()
            addsegROI.SetInput(0, allSeededIm)
            addsegROI.SetInput(1, extractVOI_imgstenc.GetOutput())
            addsegROI.SetOperationToAdd()
            addsegROI.Update()
      
            # turn off the box
            allSeededIm = addsegROI.GetOutput()

        avegSeededIm = vtk.vtkImageMathematics()
        avegSeededIm.SetInput(0, allSeededIm)
        avegSeededIm.SetOperationToMultiplyByK()
        avegSeededIm.SetConstantK( 0.2 )        
        avegSeededIm.Update()
        
        # take out average image
        finalSeedIm = avegSeededIm.GetOutput()
        xplane.SetInput( finalSeedIm )
        yplane.SetInput( finalSeedIm )
        zplane.SetInput( finalSeedIm )            
        
        image_scalar_range = finalSeedIm.GetScalarRange() 
        lThre = image_scalar_range[0]
        uThre = image_scalar_range[1]
        print "\n Image Scalar Range:"
        print image_scalar_range[0], image_scalar_range[1]
        print "Uper thresholding by"
        print uThre*0.25
        
        ## Display histogram 
        scalars = finalSeedIm.GetPointData().GetScalars()
        np_scalars = vtk_to_numpy(scalars)        
        pylab.figure()
        pylab.hist(np_scalars.flatten(), histtype='bar')
        pylab.show()
                
        # Now performed threshold on initialized VOI        
        # vtkImageThresholdConnectivity will perform a flood fill on an image, given upper and lower pixel intensity 
        # thresholds. It works similarly to vtkImageThreshold, but also allows the user to set seed points to limit
        # the threshold operation to contiguous regions of the image. The filled region, or the "inside", will be passed 
        # through to the output by default, while the "outside" will be replaced with zeros. The scalar type of the output is the same as the input.
        thresh_sub = vtk.vtkImageThresholdConnectivity() 
        thresh_sub.SetSeedPoints(seeds)
        thresh_sub.SetNeighborhoodRadius(3, 3, 2) #The radius of the neighborhood that must be within the threshold values in order for the voxel to be included in the mask. The default radius is zero (one single voxel). The radius is measured in voxels
        thresh_sub.SetNeighborhoodFraction(0.10) #The fraction of the neighborhood that must be within the thresholds. The default value is 0.5.
        thresh_sub.ThresholdBetween(0.25*uThre, uThre); 
        thresh_sub.SetInput( finalSeedIm )
        thresh_sub.Update()
        
        xplane.SetInput( thresh_sub.GetOutput() )
        yplane.SetInput( thresh_sub.GetOutput()  )
        zplane.SetInput( thresh_sub.GetOutput()  )            
        iren.Start()
        
        # Convert VOIlesion into polygonal struct
        VOIlesion_poly = vtk.vtkMarchingCubes() 
        VOIlesion_poly.SetValue(0,255)
        VOIlesion_poly.SetInput(thresh_sub.GetOutput())
        VOIlesion_poly.ComputeNormalsOff()
        VOIlesion_poly.Update()
        
        # Recalculate num_voxels and vol_lesion on VOI
        nvoxels = VOIlesion_poly.GetOutput().GetNumberOfCells()
        print "\n Number of Voxels: %d" % nvoxels # After the filter has executed, use GetNumberOfVoxels() to find out how many voxels were filled.

        return VOIlesion_poly.GetOutput()
    def testImageThresholdConnectivity(self):

        # This script is for testing the 3D flood fill filter.

        # Image pipeline

        renWin = vtk.vtkRenderWindow()
        renWin.SetSize(192, 256)

        reader = vtk.vtkImageReader()
        reader.ReleaseDataFlagOff()
        reader.SetDataByteOrderToLittleEndian()
        reader.SetDataExtent(0, 63, 0, 63, 2, 5)
        reader.SetDataSpacing(3.2, 3.2, 1.5)
        reader.SetFilePrefix(VTK_DATA_ROOT + "/Data/headsq/quarter")
        reader.SetDataMask(0x7fff)

        seeds = vtk.vtkPoints()
        seeds.InsertNextPoint(0, 0, 0)
        seeds.InsertNextPoint(100.8, 100.8, 0)

        replacein = ["ReplaceInOn", "ReplaceInOff"]
        replaceout = ["ReplaceOutOn", "ReplaceOutOff"]
        thresholds = [
            "ThresholdByLower(800)", "ThresholdByUpper(1200)",
            "ThresholdBetween(800, 1200)"
        ]

        thresh = list()
        map = list()
        act = list()
        ren = list()

        k = 0
        for rin in replacein:
            for rout in replaceout:
                for t in thresholds:

                    thresh.append(vtk.vtkImageThresholdConnectivity())
                    thresh[k].SetSeedPoints(seeds)
                    thresh[k].SetInValue(2000)
                    thresh[k].SetOutValue(0)
                    eval('thresh[k].' + rin + '()')
                    eval('thresh[k].' + rout + '()')
                    thresh[k].SetInputConnection(reader.GetOutputPort())
                    eval('thresh[k].' + t)

                    map.append(vtk.vtkImageMapper())
                    map[k].SetInputConnection(thresh[k].GetOutputPort())
                    if k < 3:
                        map[k].SetColorWindow(255)
                        map[k].SetColorLevel(127.5)
                    else:
                        map[k].SetColorWindow(2000)
                        map[k].SetColorLevel(1000)

                    act.append(vtk.vtkActor2D())
                    act[k].SetMapper(map[k])

                    ren.append(vtk.vtkRenderer())
                    ren[k].AddActor2D(act[k])

                    renWin.AddRenderer(ren[k])

                    k += 1

        ren[0].SetViewport(0, 0, .33333, .25)
        ren[1].SetViewport(.33333, 0, .66667, .25)
        ren[2].SetViewport(.66667, 0, 1, .25)
        ren[3].SetViewport(0, .25, .33333, .5)
        ren[4].SetViewport(.33333, .25, .66667, .5)
        ren[5].SetViewport(.66667, .25, 1, .5)
        ren[6].SetViewport(0, .5, .33333, .75)
        ren[7].SetViewport(.33333, .5, .66667, .75)
        ren[8].SetViewport(.66667, .5, 1, .75)
        ren[9].SetViewport(0, .75, .33333, 1)
        ren[10].SetViewport(.33333, .75, .66667, 1)
        ren[11].SetViewport(.66667, .75, 1, 1)

        # render and interact with data

        iRen = vtk.vtkRenderWindowInteractor()
        iRen.SetRenderWindow(renWin)
        renWin.Render()

        img_file = "TestImageThresholdConnectivity.png"
        vtk.test.Testing.compareImage(
            iRen.GetRenderWindow(),
            vtk.test.Testing.getAbsImagePath(img_file),
            threshold=25)
        vtk.test.Testing.interact()
Beispiel #8
0
  def apply(self, ijkPoints):
    kernelSizePixel = self.getKernelSizePixel()
    if kernelSizePixel[0]<=0 and kernelSizePixel[1]<=0 and kernelSizePixel[2]<=0:
      return

    qt.QApplication.setOverrideCursor(qt.Qt.WaitCursor)

    # Get parameter set node
    parameterSetNode = self.scriptedEffect.parameterSetNode()

    # Get parameters
    minimumThreshold = self.scriptedEffect.doubleParameter("MinimumThreshold")
    maximumThreshold = self.scriptedEffect.doubleParameter("MaximumThreshold")

    # Get modifier labelmap
    modifierLabelmap = self.scriptedEffect.defaultModifierLabelmap()

    # Get master volume image data
    masterImageData = self.scriptedEffect.masterVolumeImageData()

    # Set intensity range
    oldMasterVolumeIntensityMask = parameterSetNode.GetMasterVolumeIntensityMask()
    parameterSetNode.MasterVolumeIntensityMaskOn()
    oldIntensityMaskRange = parameterSetNode.GetMasterVolumeIntensityMaskRange()
    intensityRange = [265.00, 1009.00]
    if oldMasterVolumeIntensityMask:
      intensityRange = [max(oldIntensityMaskRange[0], minimumThreshold), min(oldIntensityMaskRange[1], maximumThreshold)]
    parameterSetNode.SetMasterVolumeIntensityMaskRange(intensityRange)

    roiNode = lumbarSeed ##self.roiSelector.currentNode()
    clippedMasterImageData = masterImageData
    if roiNode is not None:
      worldToImageMatrix = vtk.vtkMatrix4x4()
      masterImageData.GetWorldToImageMatrix(worldToImageMatrix)

      bounds = [0,0,0,0,0,0]
      roiNode.GetRASBounds(bounds)
      corner1RAS = [bounds[0], bounds[2], bounds[4], 1]
      corner1IJK = [0, 0, 0, 0]
      worldToImageMatrix.MultiplyPoint(corner1RAS, corner1IJK)

      corner2RAS = [bounds[1], bounds[3], bounds[5], 1]
      corner2IJK = [0, 0, 0, 0]
      worldToImageMatrix.MultiplyPoint(corner2RAS, corner2IJK)

      extent = [0, -1, 0, -1, 0, -1]
      for i in range(3):
          lowerPoint = min(corner1IJK[i], corner2IJK[i])
          upperPoint = max(corner1IJK[i], corner2IJK[i])
          extent[2*i] = int(math.floor(lowerPoint))
          extent[2*i+1] = int(math.ceil(upperPoint))

      imageToWorldMatrix = vtk.vtkMatrix4x4()
      masterImageData.GetImageToWorldMatrix(imageToWorldMatrix)
      clippedMasterImageData = slicer.vtkOrientedImageData()
      self.padder = vtk.vtkImageConstantPad()
      self.padder.SetInputData(masterImageData)
      self.padder.SetOutputWholeExtent(extent)
      self.padder.Update()
      clippedMasterImageData.ShallowCopy(self.padder.GetOutput())
      clippedMasterImageData.SetImageToWorldMatrix(imageToWorldMatrix)

    # Pipeline
    self.thresh = vtk.vtkImageThreshold()
    self.thresh.SetInValue(LABEL_VALUE)
    self.thresh.SetOutValue(BACKGROUND_VALUE)
    self.thresh.SetInputData(clippedMasterImageData)
    self.thresh.ThresholdBetween(minimumThreshold, maximumThreshold)
    self.thresh.SetOutputScalarTypeToUnsignedChar()
    self.thresh.Update()

    self.erode = vtk.vtkImageDilateErode3D()
    self.erode.SetInputConnection(self.thresh.GetOutputPort())
    self.erode.SetDilateValue(BACKGROUND_VALUE)
    self.erode.SetErodeValue(LABEL_VALUE)
    self.erode.SetKernelSize(
      kernelSizePixel[0],
      kernelSizePixel[1],
      kernelSizePixel[2])

    self.erodeCast = vtk.vtkImageCast()
    self.erodeCast.SetInputConnection(self.erode.GetOutputPort())
    self.erodeCast.SetOutputScalarTypeToUnsignedInt()
    self.erodeCast.Update()

    # Remove small islands
    self.islandMath = vtkITK.vtkITKIslandMath()
    self.islandMath.SetInputConnection(self.erodeCast.GetOutputPort())
    self.islandMath.SetFullyConnected(False)
    self.islandMath.SetMinimumSize(125)  # remove regions smaller than 5x5x5 voxels

    self.islandThreshold = vtk.vtkImageThreshold()
    self.islandThreshold.SetInputConnection(self.islandMath.GetOutputPort())
    self.islandThreshold.ThresholdByLower(BACKGROUND_VALUE)
    self.islandThreshold.SetInValue(BACKGROUND_VALUE)
    self.islandThreshold.SetOutValue(LABEL_VALUE)
    self.islandThreshold.SetOutputScalarTypeToUnsignedChar()
    self.islandThreshold.Update()

    # Points may be outside the region after it is eroded.
    # Snap the points to LABEL_VALUE voxels,
    snappedIJKPoints = self.snapIJKPointsToLabel(ijkPoints, self.islandThreshold.GetOutput())
    if snappedIJKPoints.GetNumberOfPoints() == 0:
      qt.QApplication.restoreOverrideCursor()
      return

    # Convert points to real data coordinates. Required for vtkImageThresholdConnectivity.
    seedPoints = vtk.vtkPoints()
    origin = masterImageData.GetOrigin()
    spacing = masterImageData.GetSpacing()
    for i in range(snappedIJKPoints.GetNumberOfPoints()):
      ijkPoint = snappedIJKPoints.GetPoint(i)
      seedPoints.InsertNextPoint(
        origin[0]+ijkPoint[0]*spacing[0],
        origin[1]+ijkPoint[1]*spacing[1],
        origin[2]+ijkPoint[2]*spacing[2])

    segmentationAlgorithm = self.scriptedEffect.parameter(SEGMENTATION_ALGORITHM_PARAMETER_NAME)
    if segmentationAlgorithm == SEGMENTATION_ALGORITHM_MASKING:
      self.runMasking(seedPoints, self.islandThreshold.GetOutput(), modifierLabelmap)

    else:
      self.floodFillingFilterIsland = vtk.vtkImageThresholdConnectivity()
      self.floodFillingFilterIsland.SetInputConnection(self.islandThreshold.GetOutputPort())
      self.floodFillingFilterIsland.SetInValue(SELECTED_ISLAND_VALUE)
      self.floodFillingFilterIsland.ReplaceInOn()
      self.floodFillingFilterIsland.ReplaceOutOff()
      self.floodFillingFilterIsland.ThresholdBetween(265.00, 1009.00)
      self.floodFillingFilterIsland.SetSeedPoints(seedPoints)
      self.floodFillingFilterIsland.Update()

      self.maskCast = vtk.vtkImageCast()
      self.maskCast.SetInputData(self.thresh.GetOutput())
      self.maskCast.SetOutputScalarTypeToUnsignedChar()
      self.maskCast.Update()

      self.imageMask = vtk.vtkImageMask()
      self.imageMask.SetInputConnection(self.floodFillingFilterIsland.GetOutputPort())
      self.imageMask.SetMaskedOutputValue(OUTSIDE_THRESHOLD_VALUE)
      self.imageMask.SetMaskInputData(self.maskCast.GetOutput())
      self.imageMask.Update()

      imageMaskOutput = slicer.vtkOrientedImageData()
      imageMaskOutput.ShallowCopy(self.imageMask.GetOutput())
      imageMaskOutput.CopyDirections(clippedMasterImageData)

      imageToWorldMatrix = vtk.vtkMatrix4x4()
      imageMaskOutput.GetImageToWorldMatrix(imageToWorldMatrix)

      segmentOutputLabelmap = slicer.vtkOrientedImageData()
      if segmentationAlgorithm == SEGMENTATION_ALGORITHM_GROWCUT:
        self.runGrowCut(clippedMasterImageData, imageMaskOutput, segmentOutputLabelmap)
      elif segmentationAlgorithm == SEGMENTATION_ALGORITHM_WATERSHED:
        self.runWatershed(clippedMasterImageData, imageMaskOutput, segmentOutputLabelmap)
      else:
        logging.error("Unknown segmentation algorithm: \"" + segmentationAlgorithm + "\"")

      segmentOutputLabelmap.SetImageToWorldMatrix(imageToWorldMatrix)

      self.selectedSegmentThreshold = vtk.vtkImageThreshold()
      self.selectedSegmentThreshold.SetInputData(segmentOutputLabelmap)
      self.selectedSegmentThreshold.ThresholdBetween(SELECTED_ISLAND_VALUE, SELECTED_ISLAND_VALUE)
      self.selectedSegmentThreshold.SetInValue(LABEL_VALUE)
      self.selectedSegmentThreshold.SetOutValue(BACKGROUND_VALUE)
      self.selectedSegmentThreshold.SetOutputScalarType(modifierLabelmap.GetScalarType())
      self.selectedSegmentThreshold.Update()
      modifierLabelmap.ShallowCopy(self.selectedSegmentThreshold.GetOutput())

    self.scriptedEffect.saveStateForUndo()
    self.scriptedEffect.modifySelectedSegmentByLabelmap(modifierLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeAdd)

    parameterSetNode.SetMasterVolumeIntensityMask(oldMasterVolumeIntensityMask)
    parameterSetNode.SetMasterVolumeIntensityMaskRange(oldIntensityMaskRange)

    qt.QApplication.restoreOverrideCursor()
    def testImageThresholdConnectivity(self):

        # This script is for testing the 3D flood fill filter.

        # Image pipeline

        renWin = vtk.vtkRenderWindow()
        renWin.SetSize(192, 256)

        reader = vtk.vtkImageReader()
        reader.ReleaseDataFlagOff()
        reader.SetDataByteOrderToLittleEndian()
        reader.SetDataExtent(0, 63, 0, 63, 2, 5)
        reader.SetDataSpacing(3.2, 3.2, 1.5)
        reader.SetFilePrefix(VTK_DATA_ROOT + "/Data/headsq/quarter")
        reader.SetDataMask(0x7fff)

        seeds = vtk.vtkPoints()
        seeds.InsertNextPoint(0, 0, 0)
        seeds.InsertNextPoint(100.8, 100.8, 0)

        replacein = ["ReplaceInOn", "ReplaceInOff"]
        replaceout = ["ReplaceOutOn", "ReplaceOutOff"]
        thresholds = ["ThresholdByLower(800)", "ThresholdByUpper(1200)", "ThresholdBetween(800, 1200)"]

        thresh = list()
        map = list()
        act = list()
        ren = list()

        k = 0
        for rin in replacein:
            for rout in replaceout:
                for t in thresholds:

                    thresh.append(vtk.vtkImageThresholdConnectivity())
                    thresh[k].SetSeedPoints(seeds)
                    thresh[k].SetInValue(2000)
                    thresh[k].SetOutValue(0)
                    eval('thresh[k].' + rin + '()')
                    eval('thresh[k].' + rout + '()')
                    thresh[k].SetInputConnection(reader.GetOutputPort())
                    eval('thresh[k].' + t)

                    map.append(vtk.vtkImageMapper())
                    map[k].SetInputConnection(thresh[k].GetOutputPort())
                    if k < 3:
                        map[k].SetColorWindow(255)
                        map[k].SetColorLevel(127.5)
                    else:
                        map[k].SetColorWindow(2000)
                        map[k].SetColorLevel(1000)

                    act.append(vtk.vtkActor2D())
                    act[k].SetMapper(map[k])

                    ren.append(vtk.vtkRenderer())
                    ren[k].AddActor2D(act[k])

                    renWin.AddRenderer(ren[k])

                    k += 1

        ren[0].SetViewport(0, 0, .33333, .25)
        ren[1].SetViewport(.33333, 0, .66667, .25)
        ren[2].SetViewport(.66667, 0, 1, .25)
        ren[3].SetViewport(0, .25, .33333, .5)
        ren[4].SetViewport(.33333, .25, .66667, .5)
        ren[5].SetViewport(.66667, .25, 1, .5)
        ren[6].SetViewport(0, .5, .33333, .75)
        ren[7].SetViewport(.33333, .5, .66667, .75)
        ren[8].SetViewport(.66667, .5, 1, .75)
        ren[9].SetViewport(0, .75, .33333, 1)
        ren[10].SetViewport(.33333, .75, .66667, 1)
        ren[11].SetViewport(.66667, .75, 1, 1)

        # render and interact with data

        iRen = vtk.vtkRenderWindowInteractor()
        iRen.SetRenderWindow(renWin);
        renWin.Render()

        img_file = "TestImageThresholdConnectivity.png"
        vtk.test.Testing.compareImage(iRen.GetRenderWindow(), vtk.test.Testing.getAbsImagePath(img_file), threshold=25)
        vtk.test.Testing.interact()
    def floodFillFromPoint(self, ijk):
        """Fills the segment taking based on the current master volume.
    Input IJK position is voxel coordinates of master volume.
    """
        self.scriptedEffect.saveStateForUndo()

        # Get master volume image data
        import vtkSegmentationCorePython as vtkSegmentationCore
        masterImageData = self.getClippedMasterImageData()
        selectedSegmentLabelmap = self.scriptedEffect.selectedSegmentLabelmap()

        # Get modifier labelmap
        modifierLabelmap = self.scriptedEffect.defaultModifierLabelmap()

        pixelValue = masterImageData.GetScalarComponentAsFloat(
            ijk[0], ijk[1], ijk[2], 0)

        useSegmentationAsStencil = False

        # Perform thresholding
        floodFillingFilter = vtk.vtkImageThresholdConnectivity()
        floodFillingFilter.SetInputData(masterImageData)
        seedPoints = vtk.vtkPoints()
        origin = masterImageData.GetOrigin()
        spacing = masterImageData.GetSpacing()
        seedPoints.InsertNextPoint(origin[0] + ijk[0] * spacing[0],
                                   origin[1] + ijk[1] * spacing[1],
                                   origin[2] + ijk[2] * spacing[2])
        floodFillingFilter.SetSeedPoints(seedPoints)

        maskImageData = vtkSegmentationCore.vtkOrientedImageData()
        intensityBasedMasking = self.scriptedEffect.parameterSetNode(
        ).GetMasterVolumeIntensityMask()
        segmentationNode = self.scriptedEffect.parameterSetNode(
        ).GetSegmentationNode()
        success = segmentationNode.GenerateEditMask(
            maskImageData,
            self.scriptedEffect.parameterSetNode().GetMaskMode(),
            masterImageData,  # reference geometry
            self.scriptedEffect.parameterSetNode().GetSelectedSegmentID(),
            self.scriptedEffect.parameterSetNode().GetMaskSegmentID() if
            self.scriptedEffect.parameterSetNode().GetMaskSegmentID() else "",
            masterImageData if intensityBasedMasking else None,
            self.scriptedEffect.parameterSetNode(
            ).GetMasterVolumeIntensityMaskRange()
            if intensityBasedMasking else None)
        if success:
            stencil = vtk.vtkImageToImageStencil()
            stencil.SetInputData(maskImageData)
            stencil.ThresholdByLower(0)
            stencil.Update()
            floodFillingFilter.SetStencilData(stencil.GetOutput())
        else:
            logging.error("Failed to create edit mask")

        neighborhoodSizeMm = self.neighborhoodSizeMmSlider.value
        floodFillingFilter.SetNeighborhoodRadius(neighborhoodSizeMm,
                                                 neighborhoodSizeMm,
                                                 neighborhoodSizeMm)
        floodFillingFilter.SetNeighborhoodFraction(0.5)

        if useSegmentationAsStencil:
            stencilFilter = vtk.vtkImageToImageStencil()
            stencilFilter.SetInputData(selectedSegmentLabelmap)
            stencilFilter.ThresholdByLower(0)
            stencilFilter.Update()
            floodFillingFilter.SetStencilData(stencilFilter.GetOutput())

        pixelValueTolerance = float(self.intensityToleranceSlider.value)
        floodFillingFilter.ThresholdBetween(pixelValue - pixelValueTolerance,
                                            pixelValue + pixelValueTolerance)

        floodFillingFilter.SetInValue(1)
        floodFillingFilter.SetOutValue(0)
        floodFillingFilter.Update()
        modifierLabelmap.DeepCopy(floodFillingFilter.GetOutput())

        # Apply changes
        self.scriptedEffect.modifySelectedSegmentByLabelmap(
            modifierLabelmap,
            slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeAdd)