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 updateWindowLevelRectangle(self, sliceLayer, xyBounds):
    # conversion as done in LabelEffect.py:applyImageMask
    xlo, xhi, ylo, yhi, zlo, zhi = xyBounds
    if xlo == xhi or ylo == yhi: return
    sliceNode = sliceLayer.GetVolumeNode()
    sliceImage = sliceNode.GetImageData()
    if not sliceImage:
      return [0,0,0,0]
    xyToIJK = sliceLayer.GetXYToIJKTransform()
    tlIJK = xyToIJK.TransformPoint( (xlo, yhi, 0) )
    trIJK = xyToIJK.TransformPoint( (xhi, yhi, 0) )
    blIJK = xyToIJK.TransformPoint( (xlo, ylo, 0) )
    brIJK = xyToIJK.TransformPoint( (xhi, ylo, 0) )
    #
    # get the mask bounding box in ijk coordinates
    # - get the xy bounds
    # - transform to ijk
    # - clamp the bounds to the dimensions of the label image
    #

    # do the clamping of the four corners
    dims = sliceImage.GetDimensions()
    tl = [0,] * 3
    tr = [0,] * 3
    bl = [0,] * 3
    br = [0,] * 3
    corners = ((tlIJK, tl),(trIJK, tr),(blIJK, bl),(brIJK, br))
    for corner,clampedCorner in corners:
      for d in xrange(3):
        clamped = int(round(corner[d]))
        if clamped < 0: clamped = 0
        if clamped >= dims[d]: clamped = dims[d]-1
        clampedCorner[d] = clamped

    # calculate the statistics for the selected region
    clip = vtk.vtkImageClip()
    extentMin = [min(tl[0],min(tr[0],min(bl[0],br[0]))),min(tl[1],min(tr[1],min(bl[1],br[1]))),min(tl[2],min(tr[2],min(bl[2],br[2])))]
    extentMax = [max(tl[0],max(tr[0],max(bl[0],br[0]))),max(tl[1],max(tr[1],max(bl[1],br[1]))),max(tl[2],max(tr[2],max(bl[2],br[2])))]
    clip.SetOutputWholeExtent(extentMin[0],extentMax[0],extentMin[1],extentMax[1],extentMin[2],extentMax[2])
    if vtk.VTK_MAJOR_VERSION <= 5:
      clip.SetInput(sliceNode.GetImageData())
    else:
      clip.SetInputData(sliceNode.GetImageData())
    clip.ClipDataOn()
    clip.Update()

    stats = vtk.vtkImageHistogramStatistics()

    if vtk.VTK_MAJOR_VERSION <= 5:
      stats.SetInput(clip.GetOutput())
    else:
      stats.SetInputData(clip.GetOutput())
    stats.Update()

    minIntensity = stats.GetMinimum()
    maxIntensity = stats.GetMaximum()

    sliceNode.GetDisplayNode().SetAutoWindowLevel(False)
    sliceNode.GetDisplayNode().SetAutoWindowLevel(0)
    sliceNode.GetDisplayNode().SetWindowLevel(maxIntensity-minIntensity, (maxIntensity-minIntensity)/2.+minIntensity)
    sliceNode.GetDisplayNode().Modified()
Exemplo n.º 3
0
    def updateWindowLevelRectangle(self, sliceLayer, xyBounds):
        # conversion as done in LabelEffect.py:applyImageMask
        xlo, xhi, ylo, yhi, zlo, zhi = xyBounds
        if xlo == xhi or ylo == yhi:
            return
        sliceNode = sliceLayer.GetVolumeNode()
        sliceImage = sliceNode.GetImageData()
        if not sliceImage:
            return [0, 0, 0, 0]
        xyToIJK = sliceLayer.GetXYToIJKTransform()
        tlIJK = xyToIJK.TransformPoint((xlo, yhi, 0))
        trIJK = xyToIJK.TransformPoint((xhi, yhi, 0))
        blIJK = xyToIJK.TransformPoint((xlo, ylo, 0))
        brIJK = xyToIJK.TransformPoint((xhi, ylo, 0))
        #
        # get the mask bounding box in ijk coordinates
        # - get the xy bounds
        # - transform to ijk
        # - clamp the bounds to the dimensions of the label image
        #

        # do the clamping of the four corners
        dims = sliceImage.GetDimensions()
        tl = [0] * 3
        tr = [0] * 3
        bl = [0] * 3
        br = [0] * 3
        corners = ((tlIJK, tl), (trIJK, tr), (blIJK, bl), (brIJK, br))
        for corner, clampedCorner in corners:
            for d in xrange(3):
                clamped = int(round(corner[d]))
                if clamped < 0:
                    clamped = 0
                if clamped >= dims[d]:
                    clamped = dims[d] - 1
                clampedCorner[d] = clamped

        # calculate the statistics for the selected region
        clip = vtk.vtkImageClip()
        extentMin = [
            min(tl[0], min(tr[0], min(bl[0], br[0]))),
            min(tl[1], min(tr[1], min(bl[1], br[1]))),
            min(tl[2], min(tr[2], min(bl[2], br[2]))),
        ]
        extentMax = [
            max(tl[0], max(tr[0], max(bl[0], br[0]))),
            max(tl[1], max(tr[1], max(bl[1], br[1]))),
            max(tl[2], max(tr[2], max(bl[2], br[2]))),
        ]
        clip.SetOutputWholeExtent(extentMin[0], extentMax[0], extentMin[1], extentMax[1], extentMin[2], extentMax[2])
        if vtk.VTK_MAJOR_VERSION <= 5:
            clip.SetInput(sliceNode.GetImageData())
        else:
            clip.SetInputData(sliceNode.GetImageData())
        clip.ClipDataOn()
        clip.Update()

        stats = vtk.vtkImageHistogramStatistics()

        if vtk.VTK_MAJOR_VERSION <= 5:
            stats.SetInput(clip.GetOutput())
        else:
            stats.SetInputData(clip.GetOutput())
        stats.Update()

        minIntensity = stats.GetMinimum()
        maxIntensity = stats.GetMaximum()

        sliceNode.GetDisplayNode().SetAutoWindowLevel(False)
        sliceNode.GetDisplayNode().SetAutoWindowLevel(0)
        sliceNode.GetDisplayNode().SetWindowLevel(
            maxIntensity - minIntensity, (maxIntensity - minIntensity) / 2.0 + minIntensity
        )
        sliceNode.GetDisplayNode().Modified()
Exemplo n.º 4
0
  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!')
Exemplo n.º 6
0
  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