def computeDifference(self, fieldA, fieldB, roi, differenceVolume):
        referenceVolume = self.createVectorVolumeFromRoi(
            roi, self.ReferenceVolumeSpacingMm)
        referenceVolume.SetName('ReferenceVolume')
        slicer.mrmlScene.AddNode(referenceVolume)
        resampledFieldA = self.resampleVolume(fieldA, referenceVolume)
        resampledFieldB = self.resampleVolume(fieldB, referenceVolume)
        subtractor = vtk.vtkImageMathematics()
        subtractor.SetOperationToSubtract()
        subtractor.SetInput1Data(resampledFieldA.GetImageData())
        subtractor.SetInput2Data(resampledFieldB.GetImageData())
        differenceVolume.SetImageDataConnection(subtractor.GetOutputPort())
        ijkToRasMatrix = vtk.vtkMatrix4x4()
        referenceVolume.GetIJKToRASMatrix(ijkToRasMatrix)
        differenceVolume.SetIJKToRASMatrix(ijkToRasMatrix)

        differenceVolumeDisplayNode = slicer.vtkMRMLVectorVolumeDisplayNode()
        slicer.mrmlScene.AddNode(differenceVolumeDisplayNode)
        differenceVolumeDisplayNode.SetAndObserveColorNodeID(
            "vtkMRMLColorTableNodeRainbow")
        differenceVolume.SetAndObserveNthDisplayNodeID(
            0, differenceVolumeDisplayNode.GetID())

        slicer.mrmlScene.RemoveNode(resampledFieldA)
        slicer.mrmlScene.RemoveNode(resampledFieldB)
        slicer.mrmlScene.RemoveNode(referenceVolume)
    def run(self, referenceVolumeNode, secondaryVolumeNode):

        referenceImageData = referenceVolumeNode.GetImageData()
        secondaryImageData = secondaryVolumeNode.GetImageData()

        # Apply image convolution to input imagedata
        imageMath = vtk.vtkImageMathematics()
        imageMath.SetInput1(referenceImageData)
        imageMath.SetInput2(secondaryImageData)
        imageMath.SetOperationToSubtract()
        imageMath.Update()

        imageAccumulate = vtk.vtkImageAccumulate()
        imageAccumulate.SetInput(referenceImageData)
        imageAccumulate.IgnoreZeroOn()
        imageAccumulate.Update()
        referenceVolumeVoxelCount = imageAccumulate.GetVoxelCount()

        # Update the volume with convolutionl operation result
        imageAccumulate2 = vtk.vtkImageAccumulate()
        imageAccumulate2.SetInput(imageMath.GetOutput())
        imageAccumulate2.IgnoreZeroOn()
        imageAccumulate2.Update()
        differenceVolumeVoxelCount = imageAccumulate2.GetVoxelCount()

        self._volumeSimilarity = (
            referenceVolumeVoxelCount -
            differenceVolumeVoxelCount) / referenceVolumeVoxelCount
  def onHelloWorldButtonClicked(self):
    print "Hello World !"
    
    #frame volume sera el scalar volume de referencia#
    self.__mvNode = self.mvSelector.currentNode()
    
    #NODO REFERENCIA
    frameVolume = slicer.vtkMRMLScalarVolumeNode()
    frameVolume.SetScene(slicer.mrmlScene)
    slicer.mrmlScene.AddNode(frameVolume)
    
    
    
    nComponents = self.__mvNode.GetNumberOfFrames()
    f=int(self.__veInitial.value)
    frameId = min(f,nComponents-1)
    
    ras2ijk = vtk.vtkMatrix4x4()
    ijk2ras = vtk.vtkMatrix4x4()
    self.__mvNode.GetRASToIJKMatrix(ras2ijk)
    self.__mvNode.GetIJKToRASMatrix(ijk2ras)
    frameImage = frameVolume.GetImageData()
    if frameImage == None:
        frameVolume.SetRASToIJKMatrix(ras2ijk)
        frameVolume.SetIJKToRASMatrix(ijk2ras)
    
    mvImage = self.__mvNode.GetImageData()
    

    for i in range(nComponents-1):
      extract = vtk.vtkImageExtractComponents()
      extract.SetInput(mvImage)
      extract.SetComponents(i)
      extract.Update()
      
      if i == 0:
          frameVolume.SetAndObserveImageData(extract.GetOutput())
      elif i < frameId+1 :
          s=vtk.vtkImageMathematics()
          s.SetOperationToAdd()  
          s.SetInput1(frameVolume.GetImageData())
          s.SetInput2(extract.GetOutput())
          s.Update()
          frameVolume.SetAndObserveImageData(s.GetOutput())

          
    frameName = 'Holaaa'
    frameVolume.SetName(frameName)
    

    
    selectionNode = slicer.app.applicationLogic().GetSelectionNode()
    selectionNode.SetReferenceActiveVolumeID(frameVolume.GetID())
    slicer.app.applicationLogic().PropagateVolumeSelection(0)
Beispiel #4
0
    def onHelloWorldButtonClicked(self):
        print "Hello World !"

        #frame volume sera el scalar volume de referencia#
        self.__mvNode = self.mvSelector.currentNode()

        #NODO REFERENCIA
        frameVolume = slicer.vtkMRMLScalarVolumeNode()
        frameVolume.SetScene(slicer.mrmlScene)
        slicer.mrmlScene.AddNode(frameVolume)

        nComponents = self.__mvNode.GetNumberOfFrames()
        f = int(self.__veInitial.value)
        frameId = min(f, nComponents - 1)

        ras2ijk = vtk.vtkMatrix4x4()
        ijk2ras = vtk.vtkMatrix4x4()
        self.__mvNode.GetRASToIJKMatrix(ras2ijk)
        self.__mvNode.GetIJKToRASMatrix(ijk2ras)
        frameImage = frameVolume.GetImageData()
        if frameImage == None:
            frameVolume.SetRASToIJKMatrix(ras2ijk)
            frameVolume.SetIJKToRASMatrix(ijk2ras)

        mvImage = self.__mvNode.GetImageData()

        for i in range(nComponents - 1):
            extract = vtk.vtkImageExtractComponents()
            extract.SetInput(mvImage)
            extract.SetComponents(i)
            extract.Update()

            if i == 0:
                frameVolume.SetAndObserveImageData(extract.GetOutput())
            elif i < frameId + 1:
                s = vtk.vtkImageMathematics()
                s.SetOperationToAdd()
                s.SetInput1(frameVolume.GetImageData())
                s.SetInput2(extract.GetOutput())
                s.Update()
                frameVolume.SetAndObserveImageData(s.GetOutput())

        frameName = 'Holaaa'
        frameVolume.SetName(frameName)

        selectionNode = slicer.app.applicationLogic().GetSelectionNode()
        selectionNode.SetReferenceActiveVolumeID(frameVolume.GetID())
        slicer.app.applicationLogic().PropagateVolumeSelection(0)
 def run(self,inputVolume1,inputVolume2,outputVolume,mathOperationType):
   """
   Run the actual algorithm
   """
   math = vtk.vtkImageMathematics()
   math.SetInput1(inputVolume1.GetImageData())
   math.SetInput2(inputVolume2.GetImageData())
   if mathOperationType == "Add":
     math.SetOperationToAdd()
   elif mathOperationType == "Subtract":
     math.SetOperationToSubtract()
   else:
     pass
   math.Update()
   
   outputVolume.CopyOrientation(input1VolumeNode)
   outputVolume.SetAndObserveImageData(math.GetOutput())
   
   return True
  def getSNR(self):
    qu=QCLib.QCUtil()
    imfirst=self.first.GetImageData()
    imsecond=self.second.GetImageData()

    if imfirst.GetScalarTypeMin()>=0: #unsigned
      imfirst.SetScalarType(imfirst.GetScalarType()-1)

    if imsecond.GetScalarTypeMin()>=0: #unsigned
      imsecond.SetScalarType(imsecond.GetScalarType()-1)

    stat=qu.getROIstats(self.first,self.label)
    statfirst=stat.values()[0]

    mathv=vtk.vtkImageMathematics()
    mathv.SetInput1Data(imfirst)
    mathv.SetInput2Data(imsecond)
    mathv.SetOperationToSubtract()
    mathv.Update()

    imsub=mathv.GetOutput()

    if imsub.GetScalarTypeMin()>=0: #unsigned
      imsub.SetScalarType(imsub.GetScalarType()-1)

    stat=qu.getROIstatsIM(imsub,self.label.GetImageData())
    statsub=stat.values()[0]

    len=statfirst.__len__()

    SNRvalues={}
    for n in range(len):
      stat={}
      statfirstn=statfirst.values()[n]
      statsubn=statsub.values()[n]
      stat['count']=statfirstn['count']
      stat['mean']=statfirstn['mean']
      stat['sd']=statfirstn['sd']
      stat['N']=statsubn['sd']
      SNRvalues[statfirst.keys()[n]]=stat

    return SNRvalues
  def computeDifference(self, fieldA, fieldB, roi, differenceVolume):
    referenceVolume = self.createVectorVolumeFromRoi(roi, self.ReferenceVolumeSpacingMm)
    referenceVolume.SetName('ReferenceVolume')
    slicer.mrmlScene.AddNode( referenceVolume )
    resampledFieldA = self.resampleVolume(fieldA, referenceVolume)
    resampledFieldB = self.resampleVolume(fieldB, referenceVolume)
    subtractor = vtk.vtkImageMathematics()
    subtractor.SetOperationToSubtract()
    subtractor.SetInput1Data(resampledFieldA.GetImageData())
    subtractor.SetInput2Data(resampledFieldB.GetImageData())
    differenceVolume.SetImageDataConnection(subtractor.GetOutputPort())
    ijkToRasMatrix = vtk.vtkMatrix4x4()
    referenceVolume.GetIJKToRASMatrix(ijkToRasMatrix)
    differenceVolume.SetIJKToRASMatrix(ijkToRasMatrix)

    differenceVolumeDisplayNode = slicer.vtkMRMLVectorVolumeDisplayNode()
    slicer.mrmlScene.AddNode( differenceVolumeDisplayNode )
    differenceVolumeDisplayNode.SetAndObserveColorNodeID("vtkMRMLColorTableNodeRainbow");
    differenceVolume.SetAndObserveNthDisplayNodeID(0, differenceVolumeDisplayNode.GetID());

    slicer.mrmlScene.RemoveNode( resampledFieldA )
    slicer.mrmlScene.RemoveNode( resampledFieldB )
    slicer.mrmlScene.RemoveNode( referenceVolume )
  def loadPetSeries(self, loadable):
    """Use the conversion factor to load the volume into Slicer"""

    conversionFactor = loadable.slope

    # Create volume node
    imageNode = self.scalarVolumePlugin.loadFilesWithArchetype(loadable.files, loadable.name)
    if imageNode:  
      # apply the conversion factor
      multiplier = vtk.vtkImageMathematics()
      multiplier.SetOperationToMultiplyByK()
      multiplier.SetConstantK(float(conversionFactor))
      if vtk.VTK_MAJOR_VERSION <= 5:
        multiplier.SetInput1(imageNode.GetImageData())
      else:
        multiplier.SetInput1Data(imageNode.GetImageData())
      multiplier.Update()
      imageNode.GetImageData().DeepCopy(multiplier.GetOutput())
      
      # create list of DICOM instance UIDs corresponding to the loaded files
      instanceUIDs = ""
      for dicomFile in loadable.files:
        uid = slicer.dicomDatabase.fileValue(dicomFile,self.tags['sopInstanceUID'])
        if uid == "":
          uid = "Unknown"
        instanceUIDs += uid + " "
      instanceUIDs = instanceUIDs[:-1]  # strip last space
      
      # get the instance UID for the RWVM object
      derivedItemUID = ""
      try:
        derivedItemUID = slicer.dicomDatabase.fileValue(loadable.rwvFile,self.tags['sopInstanceUID'])
      except AttributeError:
        # no derived items
        pass
      
      # Set Attributes
      imageNode.SetAttribute('DICOM.MeasurementUnitsCodeMeaning',loadable.unitName)
      imageNode.SetAttribute('DICOM.MeasurementUnitsCodeValue',loadable.units)
      # Keep references to the PET instances, as these may be needed to
      # establish correspondence between slice annotations and acutal slices,
      # but also keep the RWVM instance UID ... it's confusing, but not sure
      # if there is a better way in Slicer for now
      imageNode.SetAttribute("DICOM.instanceUIDs", instanceUIDs)
      imageNode.SetAttribute("DICOM.RWV.instanceUID", derivedItemUID)
    
      # automatically select the volume to display
      volumeLogic = slicer.modules.volumes.logic()
      appLogic = slicer.app.applicationLogic()
      selNode = appLogic.GetSelectionNode()
      selNode.SetReferenceActiveVolumeID(imageNode.GetID())
      appLogic.PropagateVolumeSelection()
      
      # Change display
      displayNode = imageNode.GetVolumeDisplayNode()
      displayNode.SetInterpolate(0)
      if loadable.referencedModality == 'PT':
        radiopharmaceuticalCode = ''
        try:
          radiopharmaceuticalCode = loadable.RadiopharmaceuticalCodeValue
          imageNode.SetAttribute('DICOM.RadiopharmaceuticalCodeValue',radiopharmaceuticalCode)
          print('Found Radiopharmaceutical Code ' + radiopharmaceuticalCode)
        except AttributeError:
          imageNode.SetAttribute('DICOM.RadiopharmaceuticalCodeValue','unknown')
          # use radionuclide info instead
          radionuclideCode = ''
          try:
            radionuclideCode = loadable.RadionuclideCodeValue
            imageNode.SetAttribute('DICOM.RadionuclideCodeValue',radionuclideCode)
            print('Found Radionuclide Code ' + radionuclideCode)
          except AttributeError:
            imageNode.SetAttribute('DICOM.RadionuclideCodeValue','unknown')
        if radiopharmaceuticalCode == 'C-B1031': # FDG
          displayNode.AutoWindowLevelOff()
          displayNode.SetWindowLevel(6,3)
          displayNode.SetAndObserveColorNodeID('vtkMRMLColorTableNodeInvertedGrey')
        elif radiopharmaceuticalCode == 'C-B1036': # FLT
          displayNode.AutoWindowLevelOff()
          displayNode.SetWindowLevel(4,2)
          displayNode.SetAndObserveColorNodeID('vtkMRMLColorTableNodeInvertedGrey')
        else: # Default W/L if no info about radiopharmaceutical can be found, often FDG
          displayNode.AutoWindowLevelOff()
          displayNode.SetWindowLevel(6,3)
          displayNode.SetAndObserveColorNodeID('vtkMRMLColorTableNodeInvertedGrey')     
      else:
        displayNode.SetAutoWindowLevel(1)

      # Change name
      name = (loadable.name).replace(' ','_')
      imageNode.SetName(name)
      
      # create Subject Hierarchy nodes for the loaded series
      self.addSeriesInSubjectHierarchy(loadable,imageNode)

    return imageNode
  def load(self,loadable):
    """Use the conversion factor to load the volume into Slicer"""

    conversionFactor = loadable.slope

    # Create volume node
    imageNode = self.scalarVolumePlugin.loadFilesWithArchetype(loadable.files, loadable.name)
    if imageNode:  
      # apply the conversion factor
      multiplier = vtk.vtkImageMathematics()
      multiplier.SetOperationToMultiplyByK()
      multiplier.SetConstantK(float(conversionFactor))
      multiplier.SetInput1Data(imageNode.GetImageData())
      multiplier.Update()
      imageNode.GetImageData().DeepCopy(multiplier.GetOutput())
      # create Subject Hierarchy nodes for the loaded series
      self.addSeriesInSubjectHierarchy(loadable,imageNode)
      
      # create list of DICOM instance UIDs corresponding to the loaded files
      instanceUIDs = ""
      for dicomFile in loadable.files:
        uid = slicer.dicomDatabase.fileValue(dicomFile,self.tags['sopInstanceUID'])
        if uid == "":
          uid = "Unknown"
        instanceUIDs += uid + " "
      instanceUIDs = instanceUIDs[:-1]  # strip last space
      
      # get the instance UID for the RWVM object
      derivedItemUID = ""
      try:
        derivedItemUID = slicer.dicomDatabase.fileValue(loadable.derivedItems[0],self.tags['sopInstanceUID'])
      except AttributeError:
        # no derived items
        pass
      
      # Set Attributes
      patientName = self.__getSeriesInformation(loadable.files, self.tags['patientName'])
      patientBirthDate = self.__getSeriesInformation(loadable.files, self.tags['patientBirthDate'])
      patientSex = self.__getSeriesInformation(loadable.files, self.tags['patientSex'])
      patientHeight = self.__getSeriesInformation(loadable.files, self.tags['patientHeight'])
      patientWeight = self.__getSeriesInformation(loadable.files, self.tags['patientWeight'])
      
      imageNode.SetAttribute('DICOM.PatientID', loadable.patientID)  
      imageNode.SetAttribute('DICOM.PatientName', patientName)
      imageNode.SetAttribute('DICOM.PatientBirthDate', patientBirthDate)
      imageNode.SetAttribute('DICOM.PatientSex', patientSex)
      imageNode.SetAttribute('DICOM.PatientHeight', patientHeight)
      imageNode.SetAttribute('DICOM.PatientWeight', patientWeight)
      imageNode.SetAttribute('DICOM.StudyDate', loadable.studyDate)
      imageNode.SetAttribute('DICOM.MeasurementUnitsCodeMeaning',loadable.unitName)
      imageNode.SetAttribute('DICOM.MeasurementUnitsCodeValue',loadable.units)
      imageNode.SetAttribute("DICOM.instanceUIDs", instanceUIDs)
      imageNode.SetAttribute("DICOM.RealWorldValueMappingUID", derivedItemUID)
    
      # automatically select the volume to display
      volumeLogic = slicer.modules.volumes.logic()
      appLogic = slicer.app.applicationLogic()
      selNode = appLogic.GetSelectionNode()
      selNode.SetReferenceActiveVolumeID(imageNode.GetID())
      appLogic.PropagateVolumeSelection()
      
      # Change display
      displayNode = imageNode.GetVolumeDisplayNode()
      displayNode.SetInterpolate(0)
      
      # Change name
      name = (loadable.name).replace(' ','_')
      imageNode.SetName(name)

    return imageNode
  def test_ResectionVolume1(self):
    """ Ideally you should have several levels of tests.  At the lowest level
    tests sould exercise the functionality of the logic with different inputs
    (both valid and invalid).  At higher levels your tests should emulate the
    way the user would interact with your code and confirm that it still works
    the way you intended.
    One of the most important features of the tests is that it should alert other
    developers when their changes will have an impact on the behavior of your
    module.  For example, if a developer removes a feature that you depend on,
    your test should break so they know that the feature is needed.
    """

    self.delayDisplay("Starting the test")
    #
    # first, get some data
    #

    resectionVolumeWidget = slicer.modules.ResectionVolumeWidget
    # Confirm that generate surface checkbox will not stay checked
    resectionVolumeWidget.generateSurface.setChecked(True)
    self.assertTrue(resectionVolumeWidget.generateSurface.isChecked() == False)

    # Data is in local directory currently for initial development
    slicer.util.loadMarkupsFiducialList("C:\SlicerTestData\ResectionVolumePoints.fcsv")
    slicer.util.loadModel("C:\SlicerTestData\ResectionVolumeModel.vtk")
    slicer.util.loadLabelVolume("C:\SlicerTestData\ResectionVolumeTestLabel.nrrd")
    slicer.util.loadLabelVolume("C:\SlicerTestData\RecoloredResectionVolumeTestLabel.nrrd")

    # Set fiducial points node
    fiducialNode = slicer.util.getNode("ResectionVolumePoints")
    resectionVolumeWidget.fiducialSelector.setCurrentNode(fiducialNode)

    # Confirm that generate surface checkbox will not stay checked
    resectionVolumeWidget.generateSurface.setChecked(True)
    self.assertTrue(resectionVolumeWidget.generateSurface.isChecked() == False)

    # Set model node
    testModelNode = slicer.mrmlScene.CreateNodeByClass("vtkMRMLModelNode")
    testModelNode.SetName("ResectionVolumeModelTest")
    slicer.mrmlScene.AddNode(testModelNode)
    resectionVolumeWidget.modelSelector.setCurrentNode(testModelNode)

    # Check the generate surface box
    resectionVolumeWidget.generateSurface.setChecked(True)

    # Confirm that generate surface checkbox stays checked
    self.assertTrue(resectionVolumeWidget.generateSurface.isChecked())

    # Compare newly generated model with loaded model by determining if
    # the maximum distance between the 2 sets of polydata is less than
    # a desired value
    loadedModelNode = slicer.util.getNode("ResectionVolumeModel")
    distanceFilter = vtk.vtkDistancePolyDataFilter()
    distanceFilter.SetInputData(0, testModelNode.GetPolyData())
    distanceFilter.SetInputData(1, loadedModelNode.GetPolyData())
    distanceFilter.Update()
    distancePolyData = distanceFilter.GetOutput()
    distanceRange = distancePolyData.GetScalarRange()
    maxDistance = max(abs(distanceRange[0]),abs(distanceRange[1]))
    self.assertTrue(maxDistance < 0.0001) # What value for cutoff

    # Recolor the test label
    labelNode = slicer.util.getNode("ResectionVolumeTestLabel")
    loadedLabelNode = slicer.util.getNode("RecoloredResectionVolumeTestLabel")
    resectionVolumeWidget.labelSelector.setCurrentNode(labelNode)
    resectionVolumeWidget.initialLabelValueSelector.setValue(1)
    resectionVolumeWidget.outputLabelValueSelector.setValue(2)
    resectionVolumeWidget.onRecolorLabelMap()

    # Compare the recolored test label with the loaded recolored test label
    # by subtracting the 2 images (which should be the same) and then finding
    # the min/max values, (which should be 0)
    imageMath = vtk.vtkImageMathematics()
    imageMath.SetOperationToSubtract()
    imageMath.SetInput1Data(labelNode.GetImageData())
    imageMath.SetInput2Data(loadedLabelNode.GetImageData())
    imageMath.Update()

    imageStatistics = vtk.vtkImageHistogramStatistics()
    imageStatistics.SetInputData(imageMath.GetOutput())
    minimumValue = imageStatistics.GetMinimum()
    maximumValue = imageStatistics.GetMaximum()
    self.assertTrue(minimumValue == maximumValue == 0)

    self.delayDisplay('Test passed!')
    def test_ResectionVolume1(self):
        """ Ideally you should have several levels of tests.  At the lowest level
    tests sould exercise the functionality of the logic with different inputs
    (both valid and invalid).  At higher levels your tests should emulate the
    way the user would interact with your code and confirm that it still works
    the way you intended.
    One of the most important features of the tests is that it should alert other
    developers when their changes will have an impact on the behavior of your
    module.  For example, if a developer removes a feature that you depend on,
    your test should break so they know that the feature is needed.
    """

        self.delayDisplay("Starting the test")

        slicer.util.selectModule('ResectionVolume')
        resectionVolumeWidget = slicer.modules.ResectionVolumeWidget

        # Confirm that generate surface checkbox will not stay checked
        resectionVolumeWidget.generateSurface.setChecked(True)
        self.assertTrue(
            resectionVolumeWidget.generateSurface.isChecked() == False)

        # Data is in local directory currently for initial development
        dir = os.path.dirname(__file__)
        slicer.util.loadMarkupsFiducialList(
            dir + "/TestData/ResectionVolumePoints.fcsv")
        slicer.util.loadModel(dir + "/TestData/ResectionVolumeModel.vtk")
        slicer.util.loadLabelVolume(dir +
                                    "/TestData/ResectionVolumeTestLabel.nrrd")
        slicer.util.loadLabelVolume(
            dir + "/TestData/RecoloredResectionVolumeTestLabel.nrrd")

        # Set fiducial points node
        fiducialNode = slicer.util.getNode("ResectionVolumePoints")
        resectionVolumeWidget.fiducialSelector.setCurrentNode(fiducialNode)

        # Confirm that generate surface checkbox will not stay checked
        resectionVolumeWidget.generateSurface.setChecked(True)
        self.assertTrue(
            resectionVolumeWidget.generateSurface.isChecked() == False)

        # Set model node
        testModelNode = slicer.mrmlScene.CreateNodeByClass("vtkMRMLModelNode")
        testModelNode.SetName("ResectionVolumeModelTest")
        slicer.mrmlScene.AddNode(testModelNode)
        resectionVolumeWidget.modelSelector.setCurrentNode(testModelNode)

        # Check the generate surface box
        resectionVolumeWidget.generateSurface.setChecked(True)

        # Confirm that generate surface checkbox stays checked
        self.assertTrue(resectionVolumeWidget.generateSurface.isChecked())

        # Compare newly generated model with loaded model by determining if
        # the maximum distance between the 2 sets of polydata is less than
        # a desired value
        loadedModelNode = slicer.util.getNode("ResectionVolumeModel")
        distanceFilter = vtk.vtkDistancePolyDataFilter()
        distanceFilter.SetInputData(0, testModelNode.GetPolyData())
        distanceFilter.SetInputData(1, loadedModelNode.GetPolyData())
        distanceFilter.Update()
        distancePolyData = distanceFilter.GetOutput()
        distanceRange = distancePolyData.GetScalarRange()
        maxDistance = max(abs(distanceRange[0]), abs(distanceRange[1]))
        self.assertTrue(maxDistance < 0.0001)  # What value for cutoff
        self.delayDisplay('Generate Model Test Passed!')

        # Recolor the test label
        labelNode = slicer.util.getNode("ResectionVolumeTestLabel")
        loadedLabelNode = slicer.util.getNode(
            "RecoloredResectionVolumeTestLabel")
        resectionVolumeWidget.labelSelector.setCurrentNode(labelNode)
        resectionVolumeWidget.initialLabelValueSelector.setValue(1)
        resectionVolumeWidget.outputLabelValueSelector.setValue(2)
        resectionVolumeWidget.onRecolorLabelMap()

        # Compare the recolored test label with the loaded recolored test label
        # by subtracting the 2 images (which should be the same) and then finding
        # the min/max values, (which should be 0)
        imageMath = vtk.vtkImageMathematics()
        imageMath.SetOperationToSubtract()
        imageMath.SetInput1Data(labelNode.GetImageData())
        imageMath.SetInput2Data(loadedLabelNode.GetImageData())
        imageMath.Update()

        imageStatistics = vtk.vtkImageHistogramStatistics()
        imageStatistics.SetInputData(imageMath.GetOutput())
        minimumValue = imageStatistics.GetMinimum()
        maximumValue = imageStatistics.GetMaximum()
        self.assertTrue(minimumValue == maximumValue == 0)

        self.delayDisplay('Test passed!')
Beispiel #12
0
  def preview(self,color=None):

    if not self.editUtil.getBackgroundImage() or not self.editUtil.getLabelImage():
      return

    #
    # make a lookup table where inside the threshold is opaque and colored
    # by the label color, while the background is transparent (black)
    # - apply the threshold operation to the currently visible background
    #   (output of the layer logic's vtkImageReslice instance)
    #

    if not color:
      color = self.getPaintColor

    if not self.lut:
      self.lut = vtk.vtkLookupTable()

    self.lut.SetRampToLinear()
    self.lut.SetNumberOfTableValues( 3 )
    self.lut.SetTableRange( 0, 2 )
    self.lut.SetTableValue( 0,  0, 0, 0,  0 )
    r,g,b,a = color
    self.lut.SetTableValue( 1,  r, g, b,  a/3 )
    self.lut.SetTableValue( 2,  r, g, b,  a )

    if not self.map:
      self.map = vtk.vtkImageMapToRGBA()
    self.map.SetOutputFormatToRGBA()
    self.map.SetLookupTable( self.lut )

    if not self.thresh:
      self.thresh = vtk.vtkImageThreshold()
    sliceLogic = self.sliceWidget.sliceLogic()
    backgroundLogic = sliceLogic.GetBackgroundLayer()

    self.thresh.SetInput( backgroundLogic.GetReslice().GetOutput() )
    self.thresh.ThresholdBetween( self.min, self.max )
    self.thresh.SetInValue( 1 )
    self.thresh.SetOutValue( 0 )
    self.thresh.SetOutputScalarTypeToUnsignedChar()

    if not self.outter_thresh:
      self.outter_thresh = vtk.vtkImageThreshold()

    sliceLogic = self.sliceWidget.sliceLogic()
    backgroundLogic = sliceLogic.GetBackgroundLayer()

    self.outter_thresh.SetInput( backgroundLogic.GetReslice().GetOutput() )
    self.outter_thresh.ThresholdBetween( self.outer_min, self.outer_max )
    self.outter_thresh.SetInValue( 1 )
    self.outter_thresh.SetOutValue( 0 )
    self.outter_thresh.SetOutputScalarTypeToUnsignedChar()

    if not self.add_thresh:
      self.add_thresh = vtk.vtkImageMathematics()

    self.add_thresh.SetInput1( self.thresh.GetOutput() )
    self.add_thresh.SetInput2( self.outter_thresh.GetOutput() )
    self.add_thresh.SetOperationToAdd()

    self.map.SetInput( self.add_thresh.GetOutput() )

    self.map.Update()

    self.cursorMapper.SetInput( self.map.GetOutput() )
    self.cursorActor.VisibilityOn()

    self.sliceView.scheduleRender()
    def run(self, enableScreenshots=0, screenshotScaleFactor=1):
        """
    Run the actual algorithm
    """

        self.delayDisplay('Running the aglorithm')

        self.enableScreenshots = enableScreenshots
        self.screenshotScaleFactor = screenshotScaleFactor

        # Start in conventional layout
        lm = slicer.app.layoutManager()
        lm.setLayout(slicer.vtkMRMLLayoutNode.SlicerLayoutConventionalView)
        # without this delayed display, when running from the cmd line Slicer starts
        # up in a different layout and the seed won't get rendered in the right spot
        self.delayDisplay("Conventional view")

        # Download MRHead from sample data
        import SampleData
        sampleDataLogic = SampleData.SampleDataLogic()
        print("Getting MR Head Volume")
        mrHeadVolume = sampleDataLogic.downloadMRHead()

        # Place a fiducial on the red slice
        markupsLogic = slicer.modules.markups.logic()
        eye = [33.4975, 79.4042, -10.2143]
        fidIndex = markupsLogic.AddFiducial(eye[0], eye[1], eye[2])
        fidID = markupsLogic.GetActiveListID()
        fidNode = slicer.mrmlScene.GetNodeByID(fidID)
        self.delayDisplay("Placed a fiducial")

        # Pan and zoom
        sliceWidget = slicer.app.layoutManager().sliceWidget('Red')
        sliceLogic = sliceWidget.sliceLogic()
        compositeNode = sliceLogic.GetSliceCompositeNode()
        sliceNode = sliceLogic.GetSliceNode()
        sliceNode.SetXYZOrigin(-71.7, 129.7, 0.0)
        sliceNode.SetFieldOfView(98.3, 130.5, 1.0)
        self.delayDisplay("Panned and zoomed")

        # Get the seed widget seed location
        startingSeedDisplayCoords = [0.0, 0.0, 0.0]
        helper = self.getFiducialSliceDisplayableManagerHelper('Red')
        if helper != None:
            seedWidget = helper.GetWidget(fidNode)
            seedRepresentation = seedWidget.GetSeedRepresentation()
            handleRep = seedRepresentation.GetHandleRepresentation(fidIndex)
            startingSeedDisplayCoords = handleRep.GetDisplayPosition()
            print('Starting seed display coords = %d, %d, %d' %
                  (startingSeedDisplayCoords[0], startingSeedDisplayCoords[1],
                   startingSeedDisplayCoords[2]))
        self.takeScreenshot('FiducialLayoutSwitchBug1914-StartingPosition',
                            'Fiducial starting position',
                            slicer.qMRMLScreenShotDialog().Red)

        # Switch to red slice only
        lm.setLayout(slicer.vtkMRMLLayoutNode.SlicerLayoutOneUpRedSliceView)
        self.delayDisplay("Red Slice only")

        # Switch to conventional layout
        lm.setLayout(slicer.vtkMRMLLayoutNode.SlicerLayoutConventionalView)
        self.delayDisplay("Conventional layout")

        # Get the current seed widget seed location
        endingSeedDisplayCoords = [0.0, 0.0, 0.0]
        helper = self.getFiducialSliceDisplayableManagerHelper('Red')
        if helper != None:
            seedWidget = helper.GetWidget(fidNode)
            seedRepresentation = seedWidget.GetSeedRepresentation()
            handleRep = seedRepresentation.GetHandleRepresentation(fidIndex)
            endingSeedDisplayCoords = handleRep.GetDisplayPosition()
            print('Ending seed display coords = %d, %d, %d' %
                  (endingSeedDisplayCoords[0], endingSeedDisplayCoords[1],
                   endingSeedDisplayCoords[2]))
        self.takeScreenshot('FiducialLayoutSwitchBug1914-EndingPosition',
                            'Fiducial ending position',
                            slicer.qMRMLScreenShotDialog().Red)

        # Compare to original seed widget location
        diff = math.pow(
            (startingSeedDisplayCoords[0] - endingSeedDisplayCoords[0]),
            2) + math.pow(
                (startingSeedDisplayCoords[1] - endingSeedDisplayCoords[1]),
                2) + math.pow((startingSeedDisplayCoords[2] -
                               endingSeedDisplayCoords[2]), 2)
        if diff != 0.0:
            diff = math.sqrt(diff)
        self.delayDisplay(
            "Difference between starting and ending seed display coordinates = %g"
            % diff)

        if diff > 1.0:
            # raise Exception("Display coordinate difference is too large!\nExpected < 1.0 but got %g" % (diff))
            print(
                "Display coordinate difference is too large!\nExpected < 1.0 but got %g"
                % (diff))
            return False

        if enableScreenshots == 1:
            # compare the screen snapshots
            startView = slicer.mrmlScene.GetFirstNodeByName(
                'FiducialLayoutSwitchBug1914-StartingPosition')
            startShot = startView.GetScreenShot()
            endView = slicer.mrmlScene.GetFirstNodeByName(
                'FiducialLayoutSwitchBug1914-EndingPosition')
            endShot = endView.GetScreenShot()
            imageMath = vtk.vtkImageMathematics()
            imageMath.SetOperationToSubtract()
            imageMath.SetInput1(startShot)
            imageMath.SetInput2(endShot)
            imageMath.Update()
            shotDiff = imageMath.GetOutput()
            # save it as a scene view
            annotationLogic = slicer.modules.annotations.logic()
            annotationLogic.CreateSnapShot(
                "FiducialLayoutSwitchBug1914-Diff",
                "Difference between starting and ending fiducial seed positions",
                slicer.qMRMLScreenShotDialog().Red, screenshotScaleFactor,
                shotDiff)
            # calculate the image difference
            imageStats = vtk.vtkImageHistogramStatistics()
            imageStats.SetInput(shotDiff)
            imageStats.GenerateHistogramImageOff()
            imageStats.Update()
            meanVal = imageStats.GetMean()
            self.delayDisplay("Mean of image difference = %g" % meanVal)
            if meanVal > 5.0:
                # raise Exception("Image difference is too great!\nExpected <= 5.0, but got %g" % (meanVal))
                print(
                    "Image difference is too great!\nExpected <= 5.0, but got %g"
                    % (meanVal))
                return False

        self.delayDisplay('Test passed!')
        return True
    def performInitialization( self, image, lowerThreshold, upperThreshold, sourceSeedIds, targetSeedIds, ignoreSideBranches=0 ):
        '''
        '''
        # import the vmtk libraries
        try:
            #from libvtkvmtkSegmentationPython import *
            import libvtkvmtkSegmentationPython as s
        except ImportError:
            print "FAILURE: Unable to import the SlicerVmtk libraries!"

        cast = vtk.vtkImageCast()
        cast.SetInput( image )
        cast.SetOutputScalarTypeToFloat()
        cast.Update()
        image = cast.GetOutput()

        scalarRange = image.GetScalarRange()

        imageDimensions = image.GetDimensions()
        maxImageDimensions = max( imageDimensions )

        threshold = vtk.vtkImageThreshold()
        threshold.SetInput( image )
        threshold.ThresholdBetween( lowerThreshold, upperThreshold )
        threshold.ReplaceInOff()
        threshold.ReplaceOutOn()
        threshold.SetOutValue( scalarRange[0] - scalarRange[1] )
        threshold.Update()

        thresholdedImage = threshold.GetOutput()

        scalarRange = thresholdedImage.GetScalarRange()

        shiftScale = vtk.vtkImageShiftScale()
        shiftScale.SetInput( thresholdedImage )
        shiftScale.SetShift( -scalarRange[0] )
        shiftScale.SetScale( 1.0 / ( scalarRange[1] - scalarRange[0] ) )
        shiftScale.Update()

        speedImage = shiftScale.GetOutput()

        if ignoreSideBranches:
            # ignore sidebranches, use colliding fronts
            fastMarching = s.vtkvmtkCollidingFrontsImageFilter()
            fastMarching.SetInput( speedImage )
            fastMarching.SetSeeds1( sourceSeedIds )
            fastMarching.SetSeeds2( targetSeedIds )
            fastMarching.ApplyConnectivityOn()
            fastMarching.StopOnTargetsOn()
            fastMarching.Update()

            subtract = vtk.vtkImageMathematics()
            subtract.SetInput( fastMarching.GetOutput() )
            subtract.SetOperationToAddConstant()
            subtract.SetConstantC( -10 * fastMarching.GetNegativeEpsilon() )
            subtract.Update()

        else:
            fastMarching = s.vtkvmtkFastMarchingUpwindGradientImageFilter()
            fastMarching.SetInput( speedImage )
            fastMarching.SetSeeds( sourceSeedIds )
            fastMarching.GenerateGradientImageOn()
            fastMarching.SetTargetOffset( 0.0 )
            fastMarching.SetTargets( targetSeedIds )
            if targetSeedIds.GetNumberOfIds() > 0:
                fastMarching.SetTargetReachedModeToOneTarget()
            else:
                fastMarching.SetTargetReachedModeToNoTargets()
            fastMarching.Update()

            if targetSeedIds.GetNumberOfIds() > 0:
                subtract = vtk.vtkImageMathematics()
                subtract.SetInput( fastMarching.GetOutput() )
                subtract.SetOperationToAddConstant()
                subtract.SetConstantC( -fastMarching.GetTargetValue() )
                subtract.Update()

            else:
                subtract = vtk.vtkImageThreshold()
                subtract.SetInput( fastMarching.GetOutput() )
                subtract.ThresholdByLower( 2000 )  # TODO find robuste value
                subtract.ReplaceInOff()
                subtract.ReplaceOutOn()
                subtract.SetOutValue( -1 )
                subtract.Update()

        outImageData = vtk.vtkImageData()
        outImageData.DeepCopy( subtract.GetOutput() )
        outImageData.Update()


        return outImageData
Beispiel #15
0
    def performInitialization(self,
                              image,
                              lowerThreshold,
                              upperThreshold,
                              sourceSeedIds,
                              targetSeedIds,
                              ignoreSideBranches=0):
        '''
        '''
        # import the vmtk libraries
        try:
            import vtkvmtkSegmentationPython as vtkvmtkSegmentation
        except ImportError:
            logging.error("Unable to import the SlicerVmtk libraries")

        cast = vtk.vtkImageCast()
        cast.SetInputData(image)
        cast.SetOutputScalarTypeToFloat()
        cast.Update()
        image = cast.GetOutput()

        scalarRange = image.GetScalarRange()

        imageDimensions = image.GetDimensions()
        maxImageDimensions = max(imageDimensions)

        threshold = vtk.vtkImageThreshold()
        threshold.SetInputData(image)
        threshold.ThresholdBetween(lowerThreshold, upperThreshold)
        threshold.ReplaceInOff()
        threshold.ReplaceOutOn()
        threshold.SetOutValue(scalarRange[0] - scalarRange[1])
        threshold.Update()

        thresholdedImage = threshold.GetOutput()

        scalarRange = thresholdedImage.GetScalarRange()

        shiftScale = vtk.vtkImageShiftScale()
        shiftScale.SetInputData(thresholdedImage)
        shiftScale.SetShift(-scalarRange[0])
        shiftScale.SetScale(1.0 / (scalarRange[1] - scalarRange[0]))
        shiftScale.Update()

        speedImage = shiftScale.GetOutput()

        if ignoreSideBranches:
            # ignore sidebranches, use colliding fronts
            fastMarching = vtkvmtkSegmentation.vtkvmtkCollidingFrontsImageFilter(
            )
            fastMarching.SetInputData(speedImage)
            fastMarching.SetSeeds1(sourceSeedIds)
            fastMarching.SetSeeds2(targetSeedIds)
            fastMarching.ApplyConnectivityOn()
            fastMarching.StopOnTargetsOn()
            fastMarching.Update()

            subtract = vtk.vtkImageMathematics()
            subtract.SetInputData(fastMarching.GetOutput())
            subtract.SetOperationToAddConstant()
            subtract.SetConstantC(-10 * fastMarching.GetNegativeEpsilon())
            subtract.Update()

        else:
            fastMarching = vtkvmtkSegmentation.vtkvmtkFastMarchingUpwindGradientImageFilter(
            )
            fastMarching.SetInputData(speedImage)
            fastMarching.SetSeeds(sourceSeedIds)
            fastMarching.GenerateGradientImageOn()
            fastMarching.SetTargetOffset(0.0)
            fastMarching.SetTargets(targetSeedIds)
            if targetSeedIds.GetNumberOfIds() > 0:
                fastMarching.SetTargetReachedModeToOneTarget()
            else:
                fastMarching.SetTargetReachedModeToNoTargets()
            fastMarching.Update()

            if targetSeedIds.GetNumberOfIds() > 0:
                subtract = vtk.vtkImageMathematics()
                subtract.SetInputData(fastMarching.GetOutput())
                subtract.SetOperationToAddConstant()
                subtract.SetConstantC(-fastMarching.GetTargetValue())
                subtract.Update()

            else:
                subtract = vtk.vtkImageThreshold()
                subtract.SetInputData(fastMarching.GetOutput())
                subtract.ThresholdByLower(2000)  # TODO find robuste value
                subtract.ReplaceInOff()
                subtract.ReplaceOutOn()
                subtract.SetOutValue(-1)
                subtract.Update()

        outImageData = vtk.vtkImageData()
        outImageData.DeepCopy(subtract.GetOutput())

        return outImageData
  def loadPetSeries(self, loadable):
    """Use the conversion factor to load the volume into Slicer"""

    conversionFactor = loadable.slope

    # Create volume node
    imageNode = self.scalarVolumePlugin.loadFilesWithArchetype(loadable.files, loadable.name)
    if imageNode:
      # apply the conversion factor
      multiplier = vtk.vtkImageMathematics()
      multiplier.SetOperationToMultiplyByK()
      multiplier.SetConstantK(float(conversionFactor))
      if vtk.VTK_MAJOR_VERSION <= 5:
        multiplier.SetInput1(imageNode.GetImageData())
      else:
        multiplier.SetInput1Data(imageNode.GetImageData())
      multiplier.Update()
      imageNode.GetImageData().DeepCopy(multiplier.GetOutput())

      # create list of DICOM instance UIDs corresponding to the loaded files
      instanceUIDs = ""
      for dicomFile in loadable.files:
        uid = slicer.dicomDatabase.fileValue(dicomFile,self.tags['sopInstanceUID'])
        if uid == "":
          uid = "Unknown"
        instanceUIDs += uid + " "
      instanceUIDs = instanceUIDs[:-1]  # strip last space

      # get the instance UID for the RWVM object
      derivedItemUID = ""
      try:
        derivedItemUID = slicer.dicomDatabase.fileValue(loadable.rwvFile,self.tags['sopInstanceUID'])
      except AttributeError:
        # no derived items
        pass

      if loadable.quantity:
        imageNode.SetVoxelValueQuantity(loadable.quantity)
      if loadable.units:
        imageNode.SetVoxelValueUnits(loadable.units)

      # Keep references to the PET instances, as these may be needed to
      # establish correspondence between slice annotations and acutal slices,
      # but also keep the RWVM instance UID ... it's confusing, but not sure
      # if there is a better way in Slicer for now
      imageNode.SetAttribute("DICOM.instanceUIDs", instanceUIDs)
      imageNode.SetAttribute("DICOM.RWV.instanceUID", derivedItemUID)

      # automatically select the volume to display
      volumeLogic = slicer.modules.volumes.logic()
      appLogic = slicer.app.applicationLogic()
      selNode = appLogic.GetSelectionNode()
      selNode.SetReferenceActiveVolumeID(imageNode.GetID())
      appLogic.PropagateVolumeSelection()

      # Change display
      displayNode = imageNode.GetVolumeDisplayNode()
      displayNode.SetInterpolate(0)
      if loadable.referencedModality == 'PT':
        radiopharmaceuticalCode = ''
        try:
          radiopharmaceuticalCode = loadable.RadiopharmaceuticalCodeValue
          imageNode.SetAttribute('DICOM.RadiopharmaceuticalCodeValue',radiopharmaceuticalCode)
          print('Found Radiopharmaceutical Code ' + radiopharmaceuticalCode)
        except AttributeError:
          imageNode.SetAttribute('DICOM.RadiopharmaceuticalCodeValue','unknown')
          # use radionuclide info instead
          radionuclideCode = ''
          try:
            radionuclideCode = loadable.RadionuclideCodeValue
            imageNode.SetAttribute('DICOM.RadionuclideCodeValue',radionuclideCode)
            print('Found Radionuclide Code ' + radionuclideCode)
          except AttributeError:
            imageNode.SetAttribute('DICOM.RadionuclideCodeValue','unknown')
        if radiopharmaceuticalCode == 'C-B1031': # FDG
          displayNode.AutoWindowLevelOff()
          displayNode.SetWindowLevel(6,3)
          displayNode.SetAndObserveColorNodeID('vtkMRMLColorTableNodeInvertedGrey')
        elif radiopharmaceuticalCode == 'C-B1036': # FLT
          displayNode.AutoWindowLevelOff()
          displayNode.SetWindowLevel(4,2)
          displayNode.SetAndObserveColorNodeID('vtkMRMLColorTableNodeInvertedGrey')
        else: # Default W/L if no info about radiopharmaceutical can be found, often FDG
          displayNode.AutoWindowLevelOff()
          displayNode.SetWindowLevel(6,3)
          displayNode.SetAndObserveColorNodeID('vtkMRMLColorTableNodeInvertedGrey')
      else:
        displayNode.SetAutoWindowLevel(1)

      # Change name
      name = (loadable.name).replace(' ','_')
      imageNode.SetName(name)

      # create Subject Hierarchy nodes for the loaded series
      self.addSeriesInSubjectHierarchy(loadable,imageNode)

    return imageNode
  def run(self,enableScreenshots=0,screenshotScaleFactor=1):
    """
    Run the actual algorithm
    """

    self.delayDisplay('Running the aglorithm')

    self.enableScreenshots = enableScreenshots
    self.screenshotScaleFactor = screenshotScaleFactor

    # Start in conventional layout
    lm = slicer.app.layoutManager()
    lm.setLayout(slicer.vtkMRMLLayoutNode.SlicerLayoutConventionalView)
    # without this delayed display, when running from the cmd line Slicer starts
    # up in a different layout and the seed won't get rendered in the right spot
    self.delayDisplay("Conventional view")

    # Download MRHead from sample data
    import SampleData
    sampleDataLogic = SampleData.SampleDataLogic()
    print("Getting MR Head Volume")
    mrHeadVolume = sampleDataLogic.downloadMRHead()

    # Place a fiducial on the red slice
    markupsLogic = slicer.modules.markups.logic()
    eye = [33.4975, 79.4042, -10.2143]
    fidIndex = markupsLogic.AddFiducial(eye[0], eye[1], eye[2])
    fidID = markupsLogic.GetActiveListID()
    fidNode = slicer.mrmlScene.GetNodeByID(fidID)
    self.delayDisplay("Placed a fiducial")

    # Pan and zoom
    sliceWidget = slicer.app.layoutManager().sliceWidget('Red')
    sliceLogic = sliceWidget.sliceLogic()
    compositeNode = sliceLogic.GetSliceCompositeNode()
    sliceNode = sliceLogic.GetSliceNode()
    sliceNode.SetXYZOrigin(-71.7, 129.7, 0.0)
    sliceNode.SetFieldOfView(98.3, 130.5, 1.0)
    self.delayDisplay("Panned and zoomed")

    # Get the seed widget seed location
    startingSeedDisplayCoords = [0.0, 0.0, 0.0]
    helper = self.getFiducialSliceDisplayableManagerHelper('Red')
    if helper != None:
     seedWidget = helper.GetWidget(fidNode)
     seedRepresentation = seedWidget.GetSeedRepresentation()
     handleRep = seedRepresentation.GetHandleRepresentation(fidIndex)
     startingSeedDisplayCoords = handleRep.GetDisplayPosition()
     print('Starting seed display coords = %d, %d, %d' % (startingSeedDisplayCoords[0], startingSeedDisplayCoords[1], startingSeedDisplayCoords[2]))
    self.takeScreenshot('FiducialLayoutSwitchBug1914-StartingPosition','Fiducial starting position',slicer.qMRMLScreenShotDialog().Red)

    # Switch to red slice only
    lm.setLayout(slicer.vtkMRMLLayoutNode.SlicerLayoutOneUpRedSliceView)
    self.delayDisplay("Red Slice only")

    # Switch to conventional layout
    lm.setLayout(slicer.vtkMRMLLayoutNode.SlicerLayoutConventionalView)
    self.delayDisplay("Conventional layout")

    # Get the current seed widget seed location
    endingSeedDisplayCoords = [0.0, 0.0, 0.0]
    helper = self.getFiducialSliceDisplayableManagerHelper('Red')
    if helper != None:
     seedWidget = helper.GetWidget(fidNode)
     seedRepresentation = seedWidget.GetSeedRepresentation()
     handleRep = seedRepresentation.GetHandleRepresentation(fidIndex)
     endingSeedDisplayCoords = handleRep.GetDisplayPosition()
     print('Ending seed display coords = %d, %d, %d' % (endingSeedDisplayCoords[0], endingSeedDisplayCoords[1], endingSeedDisplayCoords[2]))
    self.takeScreenshot('FiducialLayoutSwitchBug1914-EndingPosition','Fiducial ending position',slicer.qMRMLScreenShotDialog().Red)

    # Compare to original seed widget location
    diff = math.pow((startingSeedDisplayCoords[0] - endingSeedDisplayCoords[0]),2) + math.pow((startingSeedDisplayCoords[1] - endingSeedDisplayCoords[1]),2) + math.pow((startingSeedDisplayCoords[2] - endingSeedDisplayCoords[2]),2)
    if diff != 0.0:
      diff = math.sqrt(diff)
    self.delayDisplay("Difference between starting and ending seed display coordinates = %g" % diff)

    if diff > 1.0:
      # raise Exception("Display coordinate difference is too large!\nExpected < 1.0 but got %g" % (diff))
      print("Display coordinate difference is too large!\nExpected < 1.0 but got %g" % (diff))
      return False

    if enableScreenshots == 1:
      # compare the screen snapshots
      startView = slicer.mrmlScene.GetFirstNodeByName('FiducialLayoutSwitchBug1914-StartingPosition')
      startShot = startView.GetScreenShot()
      endView = slicer.mrmlScene.GetFirstNodeByName('FiducialLayoutSwitchBug1914-EndingPosition')
      endShot = endView.GetScreenShot()
      imageMath = vtk.vtkImageMathematics()
      imageMath.SetOperationToSubtract()
      imageMath.SetInput1(startShot)
      imageMath.SetInput2(endShot)
      imageMath.Update()
      shotDiff = imageMath.GetOutput()
      # save it as a scene view
      annotationLogic = slicer.modules.annotations.logic()
      annotationLogic.CreateSnapShot("FiducialLayoutSwitchBug1914-Diff", "Difference between starting and ending fiducial seed positions",slicer.qMRMLScreenShotDialog().Red, screenshotScaleFactor, shotDiff)
      # calculate the image difference
      imageStats = vtk.vtkImageHistogramStatistics()
      imageStats.SetInput(shotDiff)
      imageStats.GenerateHistogramImageOff()
      imageStats.Update()
      meanVal = imageStats.GetMean()
      self.delayDisplay("Mean of image difference = %g" % meanVal)
      if meanVal > 5.0:
        # raise Exception("Image difference is too great!\nExpected <= 5.0, but got %g" % (meanVal))
        print("Image difference is too great!\nExpected <= 5.0, but got %g" % (meanVal))
        return False

    self.delayDisplay('Test passed!')
    return True
  def GetDistanceMap(self,edgeImg,altedgeImg):
    tmpimage=vtk.vtkImageData()
    
    cast=vtk.vtkImageCast()
    cast.SetOutputScalarTypeToDouble()
    cast.SetInputData(edgeImg)
    cast.Update()

    #invert edge image edge=0 and background=2x
    Math=vtk.vtkImageMathematics()
    Math.SetInput1Data(cast.GetOutput())
    Math.SetConstantC(0)
    Math.SetConstantK(2)
    Math.SetOperationToReplaceCByK()
    Math.Update()
    tmpimage.DeepCopy(Math.GetOutput())

    Math.SetInput1Data(tmpimage)
    Math.SetConstantC(1)
    Math.SetConstantK(0)
    Math.Update()
    cast.SetInputData(Math.GetOutput())
    cast.Update()
    tmpimage.DeepCopy(cast.GetOutput())

    tmpimage2=vtk.vtkImageData()

    #calculate distance map
    if self.distalg==0:
      dm=slicer.vtkITKSignedDistanceTransform()
      # tmpimage.SetSpacing(self.input.GetSpacing())
      # dm.SetUseImageSpacing(True)
      dm.SetAlgorithmToSignedMaurer()
      dm.SetInputData(tmpimage)
      dm.Update()
      tmpimage2.DeepCopy(dm.GetOutput())
    elif self.distalg==1:
      dm=slicer.vtkITKSignedDistanceTransform()
      dm.SetAlgorithmToApproximateSigned()
      dm.SetInputData(tmpimage)
      dm.Update()
      tmpimage2.DeepCopy(dm.GetOutput())
    elif self.distalg==2:
      dm=slicer.vtkITKSignedDistanceTransform()
      # tmpimage.SetSpacing(self.input.GetSpacing())
      # dm.SetUseImageSpacing(True)
      dm.SetAlgorithmToSignedDanielsson()
      dm.SetObjectValue(2)
      dm.SetInputData(tmpimage)
      dm.Update()
      tmpimage2.DeepCopy(dm.GetOutput())
    elif self.distalg==3:
      dm=vtk.vtkImageEuclideanDistance()
      #tmpimage.SetSpacing(self.input.GetSpacing())
      dm.InitializeOn()
      #dm.ConsiderAnisotropyOn()
      dm.SetInputData(tmpimage)
      dm.Update()
      Math.SetInputData(dm.GetOutput())
      Math.SetOperationToSquareRoot()
      Math.Update()
      tmpimage2.DeepCopy(Math.GetOutput())

    if not altedgeImg:
      altedgeImg=tmpimage2

    qu=QCLib.QCUtil()
    rect=qu.minRectangle(self.ROI)
    for i in range(rect['xmin'].__len__()):
      if rect['xmin'][i]>=0:
        index=i
        break
    xmin=rect['xmin'][index]
    xmax=rect['xmax'][index]
    ymin=rect['ymin'][index]
    ymax=rect['ymax'][index]

    distMap=vtk.vtkImageData()
    distMap.DeepCopy(edgeImg)
    for x in range(xmin,xmax+1):
      for y in range(ymin,ymax+1):
        isedge=math.copysign(edgeImg.GetScalarComponentAsDouble(x,y,index,0)-1,1)
        if self.distalg!=3:
          val=math.copysign((math.fabs(tmpimage2.GetScalarComponentAsDouble(x,y,index,0))+1)*isedge,altedgeImg.GetScalarComponentAsDouble(x,y,index,0))
        else:
          val=math.copysign((math.fabs(tmpimage2.GetScalarComponentAsDouble(x,y,index,0)))*isedge,altedgeImg.GetScalarComponentAsDouble(x,y,index,0))
        distMap.SetScalarComponentFromDouble(x,y,index,0,val)

    return distMap
  def load(self,loadable):
    """Use the conversion factor to load the volume into Slicer"""

    conversionFactor = loadable.slope

    # Create volume node
    imageNode = self.scalarVolumePlugin.loadFilesWithArchetype(loadable.files, loadable.name)
    if imageNode:  
      # apply the conversion factor
      multiplier = vtk.vtkImageMathematics()
      multiplier.SetOperationToMultiplyByK()
      multiplier.SetConstantK(float(conversionFactor))
      if vtk.VTK_MAJOR_VERSION <= 5:
        multiplier.SetInput1(imageNode.GetImageData())
      else:
        multiplier.SetInput1Data(imageNode.GetImageData())
      multiplier.Update()
      imageNode.GetImageData().DeepCopy(multiplier.GetOutput())
      
      # create list of DICOM instance UIDs corresponding to the loaded files
      instanceUIDs = ""
      for dicomFile in loadable.files:
        uid = slicer.dicomDatabase.fileValue(dicomFile,self.tags['sopInstanceUID'])
        if uid == "":
          uid = "Unknown"
        instanceUIDs += uid + " "
      instanceUIDs = instanceUIDs[:-1]  # strip last space
      
      # get the instance UID for the RWVM object
      derivedItemUID = ""
      try:
        derivedItemUID = slicer.dicomDatabase.fileValue(loadable.rwvFile,self.tags['sopInstanceUID'])
      except AttributeError:
        # no derived items
        pass
      
      # Set Attributes
      imageNode.SetAttribute('DICOM.MeasurementUnitsCodeMeaning',loadable.unitName)
      imageNode.SetAttribute('DICOM.MeasurementUnitsCodeValue',loadable.units)
      # Keep references to the PET instances, as these may be needed to
      # establish correspondence between slice annotations and acutal slices,
      # but also keep the RWVM instance UID ... it's confusing, but not sure
      # if there is a better way in Slicer for now
      imageNode.SetAttribute("DICOM.instanceUIDs", instanceUIDs)
      imageNode.SetAttribute("DICOM.RWV.instanceUID", derivedItemUID)
    
      # automatically select the volume to display
      volumeLogic = slicer.modules.volumes.logic()
      appLogic = slicer.app.applicationLogic()
      selNode = appLogic.GetSelectionNode()
      selNode.SetReferenceActiveVolumeID(imageNode.GetID())
      appLogic.PropagateVolumeSelection()
      
      # Change display
      displayNode = imageNode.GetVolumeDisplayNode()
      displayNode.SetInterpolate(0)
      
      # Change name
      name = (loadable.name).replace(' ','_')
      imageNode.SetName(name)
      
      # create Subject Hierarchy nodes for the loaded series
      self.addSeriesInSubjectHierarchy(loadable,imageNode)

    return imageNode