def installVolumeRenderActorPipeline(self): self.volume_mapper.SetInputData(self.img3D) ia = vtk.vtkImageHistogramStatistics() ia.SetInputData(self.img3D) ia.SetAutoRangePercentiles(90., 99.) ia.Update() cmin, cmax = ia.GetAutoRange() print("viewer: cmin cmax", cmin, cmax) # cmin, cmax = (1000,2000) # probably the level could be the median of the image within # the percentiles median = ia.GetMedian() # accomodates all values between the level an the percentiles #window = 2*max(abs(median-cmin),abs(median-cmax)) window = cmax - cmin viridis = colormaps.CILColorMaps.get_color_transfer_function( 'viridis', (cmin, cmax)) x = numpy.linspace(ia.GetMinimum(), ia.GetMaximum(), num=255) scaling = 0.1 opacity = colormaps.CILColorMaps.get_opacity_transfer_function( x, colormaps.relu, cmin, cmax, scaling) self.volume_property.SetColor(viridis) self.volume_property.SetScalarOpacity(opacity) self.volume_property.ShadeOn() self.volume_property.SetInterpolationTypeToLinear() self.ren.AddVolume(self.volume) self.volume_colormap_limits = (cmin, cmax) self.volume_render_initialised = True self.volume.VisibilityOff()
def __init__(self, image_data, **kw): # for zope self.__component_name__ = u'' self._algorithm = None self._image_data_object = image_data self.__reference_count = 1 self.__x_values = None self.__y_values = None self.__z_values = None self._header = {} # header values that don't map to DICOM easily self._dimensions = [] self.__stencil_data = None self.__stencil_owner = None self._filename = kw.get('filename', None) self.__histogram_stats = vtk.vtkImageHistogramStatistics() # DICOM-related stuff datadir = '/' if self._filename: datadir = os.path.dirname(self._filename) self.dicom_converter = BaseDicomConverter(datadir=datadir) self.station_id = '0001' self.parallax_base_uid = '1.2.826.0.1.3680043.9.1613' self._coordinate_system = CoordinateSystem.vtk_coords self._dicom_header = None self._dicom_slice_headers = [] # slice-by-slice dicom headers (buffer) self._dicom_mtime = -1 # make sure image_data is correct type if isinstance(image_data, vtk.vtkImageData): self.SetInputData(image_data) elif isinstance(image_data, vtk.vtkAlgorithmOutput): self.SetInputConnection(image_data) else: raise TypeError("MVImage must be created with a VTK image object") # Don't do this here - image may not have been loaded yet # Create default DICOM header #self.ClearDICOMHeader() # Create default dimensions self.SetDefaultDimensionInformation() if ('input' in kw) and isinstance(kw['input'], MVImage): ci = kw['input'] self.CopyInfo(ci) if ci.GetXSlicePositions() is not None: self.__x_values = ci.GetXSlicePositions().copy() if ci.GetYSlicePositions() is not None: self.__y_values = ci.GetYSlicePositions().copy() if ci.GetZSlicePositions() is not None: self.__z_values = ci.GetZSlicePositions().copy() if 'slice_headers' in kw: self.SetSliceDICOMHeaders(kw['slice_headers'])
def auto_image_range(image, percentiles=(1, 99)): """Compute range for color transfer function.""" stats = vtk.vtkImageHistogramStatistics() stats.SetInputData(image) stats.AutomaticBinningOn() stats.SetMaximumNumberOfBins(512) stats.SetAutoRangePercentiles(percentiles) stats.UpdateWholeExtent() return tuple(stats.GetAutoRange())
def computeStatistics(self, segmentID): requestedKeys = self.getRequestedKeys() segmentationNode = slicer.mrmlScene.GetNodeByID( self.getParameterNode().GetParameter("Segmentation")) grayscaleNode = slicer.mrmlScene.GetNodeByID( self.getParameterNode().GetParameter("ScalarVolume")) if len(requestedKeys) == 0: return {} stencil = self.getStencilForVolume(segmentationNode, segmentID, grayscaleNode) if not stencil: return {} cubicMMPerVoxel = reduce(lambda x, y: x * y, grayscaleNode.GetSpacing()) ccPerCubicMM = 0.001 stat = vtk.vtkImageAccumulate() stat.SetInputData(grayscaleNode.GetImageData()) stat.SetStencilData(stencil.GetOutput()) stat.Update() medians = vtk.vtkImageHistogramStatistics() medians.SetInputData(grayscaleNode.GetImageData()) medians.SetStencilData(stencil.GetOutput()) medians.Update() # create statistics list stats = {} if "voxel_count" in requestedKeys: stats["voxel_count"] = stat.GetVoxelCount() if "volume_mm3" in requestedKeys: stats["volume_mm3"] = stat.GetVoxelCount() * cubicMMPerVoxel if "volume_cm3" in requestedKeys: stats["volume_cm3"] = stat.GetVoxelCount( ) * cubicMMPerVoxel * ccPerCubicMM if stat.GetVoxelCount() > 0: if "min" in requestedKeys: stats["min"] = stat.GetMin()[0] if "max" in requestedKeys: stats["max"] = stat.GetMax()[0] if "mean" in requestedKeys: stats["mean"] = stat.GetMean()[0] if "stdev" in requestedKeys: stats["stdev"] = stat.GetStandardDeviation()[0] if "median" in requestedKeys: stats["median"] = medians.GetMedian() return stats
def compare_stats(sitkimg, vtkimg): """ Compare the statistics of a SimpleITK image and a VTK image. """ # Compute the VTK image histogram statistics histo = vtk.vtkImageHistogramStatistics() histo.SetInputData(vtkimg) histo.Update() print(histo.GetStandardDeviation()) vtkstats = [ histo.GetMinimum(), histo.GetMaximum(), histo.GetMean(), histo.GetStandardDeviation() ] print("\nvtk median = ", histo.GetMedian()) print("\nVTK source image stats") printStats(vtkstats) # Compute the SimpleITK image statistics stats = sitk.StatisticsImageFilter() stats.Execute(sitkimg) sitkstats = [ stats.GetMinimum(), stats.GetMaximum(), stats.GetMean(), stats.GetSigma() ] print("\nSimpleITK image stats") printStats(sitkstats) # compare the statistics of the VTK and SimpleITK images ok = True for v, s in zip(vtkstats, sitkstats): x = v - s if v != 0.0: y = abs(x / v) else: y = abs(x) if (y > .0001): print("Bad!", v, s, "\terror =", y) ok = False return ok
def SetInputData(self, data_object): if self._algorithm is None: self._algorithm = vtk.vtkTrivialProducer() self._algorithm.SetOutput(data_object) self._image_data_object = data_object if self.__histogram_stats is None: self.__histogram_stats = vtk.vtkImageHistogramStatistics() # VTK-6 if vtk.vtkVersion().GetVTKMajorVersion() > 5: self.__histogram_stats.SetInputConnection(self._algorithm) else: self.__histogram_stats.SetInput(self._image_data_object)
def run(self, enableScreenshots=0, screenshotScaleFactor=1): """ Run the actual algorithm """ slicer.util.delayDisplay('Running the algorithm', 500) 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 slicer.util.delayDisplay("Conventional view", 500) # 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) slicer.util.delayDisplay( "Placed a fiducial at %g, %g, %g" % (eye[0], eye[1], eye[2]), 500) # 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) slicer.util.delayDisplay("Panned and zoomed", 500) # Get the seed widget seed location startingSeedDisplayCoords = [0.0, 0.0, 0.0] helper = self.getFiducialSliceDisplayableManagerHelper('Red') if helper is not 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) slicer.util.delayDisplay("Red Slice only", 500) # Switch to conventional layout print 'Calling set layout back to conventional' lm.setLayout(slicer.vtkMRMLLayoutNode.SlicerLayoutConventionalView) print 'Done calling set layout back to conventional' slicer.util.delayDisplay("Conventional layout", 500) # Get the current seed widget seed location endingSeedDisplayCoords = [0.0, 0.0, 0.0] helper = self.getFiducialSliceDisplayableManagerHelper('Red') if helper is not 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) slicer.util.delayDisplay( "Difference between starting and ending seed display coordinates = %g" % diff) if diff > self.maximumDisplayDifference: # double check against the RAS coordinates of the underlying volume since the display could have changed with a FOV adjustment. sliceView = sliceWidget.sliceView() volumeRAS = sliceView.convertXYZToRAS(endingSeedDisplayCoords) seedRAS = [0, 0, 0] fidNode.GetNthFiducialPosition(0, seedRAS) rasDiff = math.pow((seedRAS[0] - volumeRAS[0]), 2) + math.pow( (seedRAS[1] - volumeRAS[1]), 2) + math.pow( (seedRAS[2] - volumeRAS[2]), 2) if rasDiff != 0.0: rasDiff = math.sqrt(rasDiff) print 'Checking the difference between fiducial RAS position', seedRAS, 'and volume RAS as derived from the fiducial display position', volumeRAS, ': ', rasDiff if rasDiff > self.maximumRASDifference: slicer.util.delayDisplay( "RAS coordinate difference is too large as well!\nExpected < %g but got %g" % (self.maximumRASDifference, rasDiff)) return False else: slicer.util.delayDisplay( "RAS coordinate difference is %g which is < %g, test passes." % (rasDiff, self.maximumRASDifference)) 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() slicer.util.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 slicer.util.delayDisplay('Test passed!') return True
def test_FiducialLayoutSwitchBug1914(self): # test difference in display location and then in RAS if this is too fine maximumDisplayDifference = 1.0 # for future testing: take into account the volume voxel size maximumRASDifference = 1.0 enableScreenshots = 0 screenshotScaleFactor = 1 logic = FiducialLayoutSwitchBug1914Logic() logging.info( "ctest, please don't truncate my output: CTEST_FULL_OUTPUT") self.delayDisplay('Running the algorithm') # 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 mrHeadVolume = SampleData.downloadSample("MRHead") # Place a point on the red slice eye = [33.4975, 79.4042, -10.2143] markupNode = slicer.mrmlScene.AddNewNodeByClass( "vtkMRMLMarkupsFiducialNode") markupNode.AddControlPoint(eye) self.delayDisplay( f"Placed a point at {eye[0]:g}, {eye[1]:g}, {eye[2]:g}") # 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 = logic.getPointSliceDisplayableManagerHelper('Red') if helper is not None: seedWidget = helper.GetWidget(markupNode) 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', 'Point starting position', slicer.qMRMLScreenShotDialog.Red) # Switch to red slice only lm.setLayout(slicer.vtkMRMLLayoutNode.SlicerLayoutOneUpRedSliceView) self.delayDisplay("Red Slice only") # Switch to conventional layout print('Calling set layout back to conventional') lm.setLayout(slicer.vtkMRMLLayoutNode.SlicerLayoutConventionalView) print('Done calling set layout back to conventional') self.delayDisplay("Conventional layout") # Get the current seed widget seed location endingSeedDisplayCoords = [0.0, 0.0, 0.0] helper = logic.getPointSliceDisplayableManagerHelper('Red') if helper is not None: seedWidget = helper.GetWidget(markupNode) 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', 'Point 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 > maximumDisplayDifference: # double check against the RAS coordinates of the underlying volume since the display could have changed with a FOV adjustment. sliceView = sliceWidget.sliceView() volumeRAS = sliceView.convertXYZToRAS(endingSeedDisplayCoords) seedRAS = [0, 0, 0] markupNode.GetNthControlPointPosition(0, seedRAS) rasDiff = math.pow((seedRAS[0] - volumeRAS[0]), 2) + math.pow( (seedRAS[1] - volumeRAS[1]), 2) + math.pow( (seedRAS[2] - volumeRAS[2]), 2) if rasDiff != 0.0: rasDiff = math.sqrt(rasDiff) print('Checking the difference between point RAS position', seedRAS, 'and volume RAS as derived from the point display position', volumeRAS, ': ', rasDiff) if rasDiff > maximumRASDifference: raise Exception( f"RAS coordinate difference is too large as well!\nExpected < {maximumRASDifference:g} but got {rasDiff:g}" ) else: self.delayDisplay( f"RAS coordinate difference is {rasDiff:g} which is < {maximumRASDifference:g}, test passes." ) 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 point 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)) self.delayDisplay('Test passed!')
def __init__(self, dimx=600, dimy=600, renWin=None, iren=None, ren=None, debug=False): '''creates the rendering pipeline''' # Handle arguments if renWin is not None: self.renWin = renWin else: self.renWin = vtk.vtkRenderWindow() if iren is not None: self.iren = iren else: self.iren = vtk.vtkRenderWindowInteractor() # create a rendering window and renderer if ren is not None: self.ren = ren else: self.ren = vtk.vtkRenderer() self.renWin.SetSize(dimx, dimy) self.renWin.AddRenderer(self.ren) # img 3D as slice self.img3D = None self.slicenos = [0, 0, 0] self.sliceOrientation = SLICE_ORIENTATION_XY self.sliceActor = vtk.vtkImageActor() self.voi = vtk.vtkExtractVOI() self.wl = vtk.vtkImageMapToWindowLevelColors() self.ia = vtk.vtkImageHistogramStatistics() self.sliceActorNo = 0 # Viewer Event manager self.event = ViewerEventManager() # create a renderwindowinteractor self.style = CILInteractorStyle(self) self.iren.SetInteractorStyle(self.style) self.iren.SetRenderWindow(self.renWin) # Render decimation self.decimate = vtk.vtkDecimatePro() self.ren.SetBackground(.1, .2, .4) self.actors = {} # Help text self.helpActor = vtk.vtkActor2D() self.helpActor.GetPositionCoordinate( ).SetCoordinateSystemToNormalizedDisplay() self.helpActor.GetPositionCoordinate().SetValue(0.1, 0.5) self.helpActor.VisibilityOff() self.ren.AddActor(self.helpActor) # volume render volumeMapper = vtk.vtkSmartVolumeMapper() #volumeMapper = vtk.vtkFixedPointVolumeRayCastMapper() self.volume_mapper = volumeMapper volumeProperty = vtk.vtkVolumeProperty() self.volume_property = volumeProperty # The volume holds the mapper and the property and # can be used to position/orient the volume. volume = vtk.vtkVolume() volume.SetMapper(volumeMapper) volume.SetProperty(volumeProperty) self.volume = volume self.volume_render_initialised = False # axis orientation widget om = vtk.vtkAxesActor() ori = vtk.vtkOrientationMarkerWidget() ori.SetOutlineColor(0.9300, 0.5700, 0.1300) ori.SetInteractor(self.iren) ori.SetOrientationMarker(om) ori.SetViewport(0.0, 0.0, 0.4, 0.4) ori.SetEnabled(1) ori.InteractiveOff() self.orientation_marker = ori self.iren.Initialize()
def run(self,enableScreenshots=0,screenshotScaleFactor=1): """ Run the actual algorithm """ slicer.util.delayDisplay('Running the algorithm',500) 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 slicer.util.delayDisplay("Conventional view",500) # 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) slicer.util.delayDisplay("Placed a fiducial at %g, %g, %g" % (eye[0], eye[1], eye[2]),500) # 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) slicer.util.delayDisplay("Panned and zoomed",500) # 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) slicer.util.delayDisplay("Red Slice only",500) # Switch to conventional layout print 'Calling set layout back to conventional' lm.setLayout(slicer.vtkMRMLLayoutNode.SlicerLayoutConventionalView) print 'Done calling set layout back to conventional' slicer.util.delayDisplay("Conventional layout",500) # 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) slicer.util.delayDisplay("Difference between starting and ending seed display coordinates = %g" % diff) if diff > self.maximumDisplayDifference: # double check against the RAS coordinates of the underlying volume since the display could have changed with a FOV adjustment. sliceView = sliceWidget.sliceView() volumeRAS = sliceView.convertXYZToRAS(endingSeedDisplayCoords) seedRAS = [0,0,0] fidNode.GetNthFiducialPosition(0,seedRAS) rasDiff = math.pow((seedRAS[0] - volumeRAS[0]),2) + math.pow((seedRAS[1] - volumeRAS[1]),2) + math.pow((seedRAS[2] - volumeRAS[2]),2) if rasDiff != 0.0: rasDiff = math.sqrt(rasDiff) print 'Checking the difference between fiducial RAS position',seedRAS,'and volume RAS as derived from the fiducial display position',volumeRAS,': ',rasDiff if rasDiff > self.maximumRASDifference: slicer.util.delayDisplay("RAS coordinate difference is too large as well!\nExpected < %g but got %g" % (self.maximumRASDifference, rasDiff)) return False else: slicer.util.delayDisplay("RAS coordinate difference is %g which is < %g, test passes." % (rasDiff, self.maximumRASDifference)) 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() slicer.util.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 slicer.util.delayDisplay('Test passed!') return True
def __init__(self, grayscaleNode, labelNode, colorNode=None, nodeBaseName=None, fileName=None): #import numpy self.keys = ("Index", "Count", "Volume mm^3", "Volume cc", "Min", "Max", "Mean", "Median", "StdDev") cubicMMPerVoxel = reduce(lambda x, y: x * y, labelNode.GetSpacing()) ccPerCubicMM = 0.001 # TODO: progress and status updates # this->InvokeEvent(vtkLabelStatisticsLogic::StartLabelStats, (void*)"start label stats") self.labelNode = labelNode self.colorNode = colorNode self.nodeBaseName = nodeBaseName if not self.nodeBaseName: self.nodeBaseName = labelNode.GetName() if labelNode.GetName( ) else 'Labels' self.labelStats = {} self.labelStats['Labels'] = [] if (not labelNode.GetImageData() or not labelNode.GetImageData().GetPointData() or not labelNode.GetImageData().GetPointData().GetScalars()): # No input label data return if (not grayscaleNode.GetImageData() or not grayscaleNode.GetImageData().GetPointData() or not grayscaleNode.GetImageData().GetPointData().GetScalars()): # No input grayscale image data return stataccum = vtk.vtkImageAccumulate() stataccum.SetInputConnection(labelNode.GetImageDataConnection()) stataccum.Update() lo = int(stataccum.GetMin()[0]) hi = int(stataccum.GetMax()[0]) for i in range(lo, hi + 1): # this->SetProgress((float)i/hi); # std::string event_message = "Label "; std::stringstream s; s << i; event_message.append(s.str()); # this->InvokeEvent(vtkLabelStatisticsLogic::LabelStatsOuterLoop, (void*)event_message.c_str()); # logic copied from slicer3 LabelStatistics # to create the binary volume of the label # //logic copied from slicer2 LabelStatistics MaskStat # // create the binary volume of the label thresholder = vtk.vtkImageThreshold() thresholder.SetInputConnection(labelNode.GetImageDataConnection()) thresholder.SetInValue(1) thresholder.SetOutValue(0) thresholder.ReplaceOutOn() thresholder.ThresholdBetween(i, i) thresholder.SetOutputScalarType( grayscaleNode.GetImageData().GetScalarType()) thresholder.Update() # this.InvokeEvent(vtkLabelStatisticsLogic::LabelStatsInnerLoop, (void*)"0.25"); # use vtk's statistics class with the binary labelmap as a stencil stencil = vtk.vtkImageToImageStencil() stencil.SetInputConnection(thresholder.GetOutputPort()) stencil.ThresholdBetween(1, 1) # this.InvokeEvent(vtkLabelStatisticsLogic::LabelStatsInnerLoop, (void*)"0.5") stat1 = vtk.vtkImageAccumulate() stat1.SetInputConnection(grayscaleNode.GetImageDataConnection()) stencil.Update() stat1.SetStencilData(stencil.GetOutput()) stat1.Update() medians = vtk.vtkImageHistogramStatistics() medians.SetInputConnection(grayscaleNode.GetImageDataConnection()) stencil.Update() medians.SetStencilData(stencil.GetOutput()) medians.Update() # this.InvokeEvent(vtkLabelStatisticsLogic::LabelStatsInnerLoop, (void*)"0.75") if stat1.GetVoxelCount() > 0: # add an entry to the LabelStats list self.labelStats["Labels"].append(i) self.labelStats[i, "Index"] = i self.labelStats[i, "Count"] = stat1.GetVoxelCount() self.labelStats[i, "Volume mm^3"] = self.labelStats[ i, "Count"] * cubicMMPerVoxel self.labelStats[i, "Volume cc"] = self.labelStats[ i, "Volume mm^3"] * ccPerCubicMM self.labelStats[i, "Min"] = stat1.GetMin()[0] self.labelStats[i, "Max"] = stat1.GetMax()[0] self.labelStats[i, "Mean"] = stat1.GetMean()[0] self.labelStats[i, "Median"] = medians.GetMedian() self.labelStats[i, "StdDev"] = stat1.GetStandardDeviation()[0]
def computeStatistics(self, segmentID): import vtkSegmentationCorePython as vtkSegmentationCore requestedKeys = self.getRequestedKeys() segmentationNode = slicer.mrmlScene.GetNodeByID(self.getParameterNode().GetParameter("Segmentation")) grayscaleNode = slicer.mrmlScene.GetNodeByID(self.getParameterNode().GetParameter("ScalarVolume")) if len(requestedKeys)==0: return {} containsLabelmapRepresentation = segmentationNode.GetSegmentation().ContainsRepresentation( vtkSegmentationCore.vtkSegmentationConverter.GetSegmentationBinaryLabelmapRepresentationName()) if not containsLabelmapRepresentation: return {} if (not grayscaleNode or not grayscaleNode.GetImageData() or not grayscaleNode.GetImageData().GetPointData() or not grayscaleNode.GetImageData().GetPointData().GetScalars()): # Input grayscale node does not contain valid image data return {} # Get geometry of grayscale volume node as oriented image data # reference geometry in reference node coordinate system referenceGeometry_Reference = vtkSegmentationCore.vtkOrientedImageData() referenceGeometry_Reference.SetExtent(grayscaleNode.GetImageData().GetExtent()) ijkToRasMatrix = vtk.vtkMatrix4x4() grayscaleNode.GetIJKToRASMatrix(ijkToRasMatrix) referenceGeometry_Reference.SetGeometryFromImageToWorldMatrix(ijkToRasMatrix) # Get transform between grayscale volume and segmentation segmentationToReferenceGeometryTransform = vtk.vtkGeneralTransform() slicer.vtkMRMLTransformNode.GetTransformBetweenNodes(segmentationNode.GetParentTransformNode(), grayscaleNode.GetParentTransformNode(), segmentationToReferenceGeometryTransform) cubicMMPerVoxel = reduce(lambda x,y: x*y, referenceGeometry_Reference.GetSpacing()) ccPerCubicMM = 0.001 segmentLabelmap = vtkSegmentationCore.vtkOrientedImageData() segmentationNode.GetBinaryLabelmapRepresentation(segmentID, segmentLabelmap) if (not segmentLabelmap or not segmentLabelmap.GetPointData() or not segmentLabelmap.GetPointData().GetScalars()): # No input label data return {} segmentLabelmap_Reference = vtkSegmentationCore.vtkOrientedImageData() vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage( segmentLabelmap, referenceGeometry_Reference, segmentLabelmap_Reference, False, # nearest neighbor interpolation False, # no padding segmentationToReferenceGeometryTransform) # 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(segmentLabelmap_Reference) thresh.ThresholdByLower(0) thresh.SetInValue(backgroundValue) thresh.SetOutValue(labelValue) thresh.SetOutputScalarType(vtk.VTK_UNSIGNED_CHAR) thresh.Update() # Use binary labelmap as a stencil stencil = vtk.vtkImageToImageStencil() stencil.SetInputData(thresh.GetOutput()) stencil.ThresholdByUpper(labelValue) stencil.Update() stat = vtk.vtkImageAccumulate() stat.SetInputData(grayscaleNode.GetImageData()) stat.SetStencilData(stencil.GetOutput()) stat.Update() medians = vtk.vtkImageHistogramStatistics() medians.SetInputData(grayscaleNode.GetImageData()) medians.SetStencilData(stencil.GetOutput()) medians.Update() # create statistics list stats = {} if "voxel_count" in requestedKeys: stats["voxel_count"] = stat.GetVoxelCount() if "volume_mm3" in requestedKeys: stats["volume_mm3"] = stat.GetVoxelCount() * cubicMMPerVoxel if "volume_cm3" in requestedKeys: stats["volume_cm3"] = stat.GetVoxelCount() * cubicMMPerVoxel * ccPerCubicMM if stat.GetVoxelCount()>0: if "min" in requestedKeys: stats["min"] = stat.GetMin()[0] if "max" in requestedKeys: stats["max"] = stat.GetMax()[0] if "mean" in requestedKeys: stats["mean"] = stat.GetMean()[0] if "stdev" in requestedKeys: stats["stdev"] = stat.GetStandardDeviation()[0] if "median" in requestedKeys: stats["median"] = medians.GetMedian() return stats
def __init__(self, grayscaleNode, labelNode, colorNode=None, nodeBaseName=None, fileName=None): #import numpy self.keys = ("Index", "Count", "Volume mm^3", "Volume cc", "Min", "Max", "Mean", "Median", "StdDev") cubicMMPerVoxel = reduce(lambda x,y: x*y, labelNode.GetSpacing()) ccPerCubicMM = 0.001 # TODO: progress and status updates # this->InvokeEvent(vtkLabelStatisticsLogic::StartLabelStats, (void*)"start label stats") self.labelNode = labelNode self.colorNode = colorNode self.nodeBaseName = nodeBaseName if not self.nodeBaseName: self.nodeBaseName = labelNode.GetName() if labelNode.GetName() else 'Labels' self.labelStats = {} self.labelStats['Labels'] = [] if (not labelNode.GetImageData() or not labelNode.GetImageData().GetPointData() or not labelNode.GetImageData().GetPointData().GetScalars()): # No input label data return if (not grayscaleNode.GetImageData() or not grayscaleNode.GetImageData().GetPointData() or not grayscaleNode.GetImageData().GetPointData().GetScalars()): # No input grayscale image data return stataccum = vtk.vtkImageAccumulate() stataccum.SetInputConnection(labelNode.GetImageDataConnection()) stataccum.Update() lo = int(stataccum.GetMin()[0]) hi = int(stataccum.GetMax()[0]) for i in range(lo,hi+1): # this->SetProgress((float)i/hi); # std::string event_message = "Label "; std::stringstream s; s << i; event_message.append(s.str()); # this->InvokeEvent(vtkLabelStatisticsLogic::LabelStatsOuterLoop, (void*)event_message.c_str()); # logic copied from slicer3 LabelStatistics # to create the binary volume of the label # //logic copied from slicer2 LabelStatistics MaskStat # // create the binary volume of the label thresholder = vtk.vtkImageThreshold() thresholder.SetInputConnection(labelNode.GetImageDataConnection()) thresholder.SetInValue(1) thresholder.SetOutValue(0) thresholder.ReplaceOutOn() thresholder.ThresholdBetween(i,i) thresholder.SetOutputScalarType(grayscaleNode.GetImageData().GetScalarType()) thresholder.Update() # this.InvokeEvent(vtkLabelStatisticsLogic::LabelStatsInnerLoop, (void*)"0.25"); # use vtk's statistics class with the binary labelmap as a stencil stencil = vtk.vtkImageToImageStencil() stencil.SetInputConnection(thresholder.GetOutputPort()) stencil.ThresholdBetween(1, 1) # this.InvokeEvent(vtkLabelStatisticsLogic::LabelStatsInnerLoop, (void*)"0.5") stat1 = vtk.vtkImageAccumulate() stat1.SetInputConnection(grayscaleNode.GetImageDataConnection()) stencil.Update() stat1.SetStencilData(stencil.GetOutput()) stat1.Update() medians = vtk.vtkImageHistogramStatistics() medians.SetInputConnection(grayscaleNode.GetImageDataConnection()) stencil.Update() medians.SetStencilData(stencil.GetOutput()) medians.Update() # this.InvokeEvent(vtkLabelStatisticsLogic::LabelStatsInnerLoop, (void*)"0.75") if stat1.GetVoxelCount() > 0: # add an entry to the LabelStats list self.labelStats["Labels"].append(i) self.labelStats[i,"Index"] = i self.labelStats[i,"Count"] = stat1.GetVoxelCount() self.labelStats[i,"Volume mm^3"] = self.labelStats[i,"Count"] * cubicMMPerVoxel self.labelStats[i,"Volume cc"] = self.labelStats[i,"Volume mm^3"] * ccPerCubicMM self.labelStats[i,"Min"] = stat1.GetMin()[0] self.labelStats[i,"Max"] = stat1.GetMax()[0] self.labelStats[i,"Mean"] = stat1.GetMean()[0] self.labelStats[i,"Median"] = medians.GetMedian() self.labelStats[i,"StdDev"] = stat1.GetStandardDeviation()[0]
def computeStatistics(self, segmentID): import vtkSegmentationCorePython as vtkSegmentationCore requestedKeys = self.getRequestedKeys() segmentationNode = slicer.mrmlScene.GetNodeByID(self.getParameterNode().GetParameter("Segmentation")) grayscaleNode = slicer.mrmlScene.GetNodeByID(self.getParameterNode().GetParameter("ScalarVolume")) if len(requestedKeys)==0: return {} containsLabelmapRepresentation = segmentationNode.GetSegmentation().ContainsRepresentation( vtkSegmentationCore.vtkSegmentationConverter.GetSegmentationBinaryLabelmapRepresentationName()) if not containsLabelmapRepresentation: return {} if grayscaleNode is None or grayscaleNode.GetImageData() is None: return {} # Get geometry of grayscale volume node as oriented image data # reference geometry in reference node coordinate system referenceGeometry_Reference = vtkSegmentationCore.vtkOrientedImageData() referenceGeometry_Reference.SetExtent(grayscaleNode.GetImageData().GetExtent()) ijkToRasMatrix = vtk.vtkMatrix4x4() grayscaleNode.GetIJKToRASMatrix(ijkToRasMatrix) referenceGeometry_Reference.SetGeometryFromImageToWorldMatrix(ijkToRasMatrix) # Get transform between grayscale volume and segmentation segmentationToReferenceGeometryTransform = vtk.vtkGeneralTransform() slicer.vtkMRMLTransformNode.GetTransformBetweenNodes(segmentationNode.GetParentTransformNode(), grayscaleNode.GetParentTransformNode(), segmentationToReferenceGeometryTransform) cubicMMPerVoxel = reduce(lambda x,y: x*y, referenceGeometry_Reference.GetSpacing()) ccPerCubicMM = 0.001 segment = segmentationNode.GetSegmentation().GetSegment(segmentID) segBinaryLabelName = vtkSegmentationCore.vtkSegmentationConverter.GetSegmentationBinaryLabelmapRepresentationName() segmentLabelmap = segment.GetRepresentation(segBinaryLabelName) segmentLabelmap_Reference = vtkSegmentationCore.vtkOrientedImageData() vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage( segmentLabelmap, referenceGeometry_Reference, segmentLabelmap_Reference, False, # nearest neighbor interpolation False, # no padding segmentationToReferenceGeometryTransform) # 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(segmentLabelmap_Reference) thresh.ThresholdByLower(0) thresh.SetInValue(backgroundValue) thresh.SetOutValue(labelValue) thresh.SetOutputScalarType(vtk.VTK_UNSIGNED_CHAR) thresh.Update() # Use binary labelmap as a stencil stencil = vtk.vtkImageToImageStencil() stencil.SetInputData(thresh.GetOutput()) stencil.ThresholdByUpper(labelValue) stencil.Update() stat = vtk.vtkImageAccumulate() stat.SetInputData(grayscaleNode.GetImageData()) stat.SetStencilData(stencil.GetOutput()) stat.Update() medians = vtk.vtkImageHistogramStatistics() medians.SetInputData(grayscaleNode.GetImageData()) medians.SetStencilData(stencil.GetOutput()) medians.Update() # create statistics list stats = {} if "voxel_count" in requestedKeys: stats["voxel_count"] = stat.GetVoxelCount() if "volume_mm3" in requestedKeys: stats["volume_mm3"] = stat.GetVoxelCount() * cubicMMPerVoxel if "volume_cm3" in requestedKeys: stats["volume_cm3"] = stat.GetVoxelCount() * cubicMMPerVoxel * ccPerCubicMM if stat.GetVoxelCount()>0: if "min" in requestedKeys: stats["min"] = stat.GetMin()[0] if "max" in requestedKeys: stats["max"] = stat.GetMax()[0] if "mean" in requestedKeys: stats["mean"] = stat.GetMean()[0] if "stdev" in requestedKeys: stats["stdev"] = stat.GetStandardDeviation()[0] if "median" in requestedKeys: stats["median"] = medians.GetMedian() return stats