def hausdorffDistance(self,fiber1,fiber2): """ calculate the distance between two fiber bundles Based on code from Laurent Chauvin """ polyA = fiber1.GetPolyData() polyB = fiber2.GetPolyData() locA = vtk.vtkMergePoints() locB = vtk.vtkMergePoints() locA.SetDataSet(polyA) locB.SetDataSet(polyB) locs = (locA,locB) for loc in locs: loc.AutomaticOn() loc.BuildLocator() ptsA = polyA.GetPoints() ptsB = polyB.GetPoints() rangeA = ptsA.GetNumberOfPoints() rangeB = ptsB.GetNumberOfPoints() maxd = 0.0 maxd1 = 0.0 avgd = 0.0 avgd1 = 0.0 distanceA = vtk.vtkFloatArray() distanceA.SetName("Distance") for i in range(rangeA): pt = ptsA.GetPoint(i) bid = locB.FindClosestPoint(pt) ptb = ptsB.GetPoint(bid) d = self.pointDistance(pt,ptb) distanceA.InsertNextValue(d) avgd += d if d > maxd: maxd = d avgd = avgd / rangeA distanceB = vtk.vtkFloatArray() distanceB.SetName("Distance") for i in range(rangeB): pt = ptsB.GetPoint(i) bid = locA.FindClosestPoint(pt) ptb = ptsA.GetPoint(bid) d = self.pointDistance(pt,ptb) distanceB.InsertNextValue(d) avgd1 += d if d > maxd1: maxd1 = d avgd1 = avgd1 / rangeB polyA.GetPointData().SetScalars(distanceA) polyB.GetPointData().SetScalars(distanceB) return max(maxd,maxd1)
def __init__(self): self.__chartView = ctk.ctkVTKChartView() self.__bgxArray = vtk.vtkFloatArray() self.__bgyArray = vtk.vtkFloatArray() self.__bgxArray.SetName('') self.__bgyArray.SetName('1st multivolume') self.__chartTable = self.createNewVTKTable(self.__bgxArray, self.__bgyArray) self.__bgMultiVolumeNode = None self.__fgMultiVolumeNode = None self.__mvLabels = [] self.__xLogScaleEnabled = False self.__yLogScaleEnabled = False self.__mvRange = [0,0] self.__nFramesForBaselineCalculation = 1 self.__chartMode = None self.activateSignalIntensityMode() self.baselineAverageSignal = 0 self.__showLegend = False
def __init__(self): self.__chartView = ctk.ctkVTKChartView() self.__bgxArray = vtk.vtkFloatArray() self.__bgyArray = vtk.vtkFloatArray() self.__bgxArray.SetName('') self.__bgyArray.SetName('1st multivolume') self.__chartTable = self.createNewVTKTable(self.__bgxArray, self.__bgyArray) self.__bgMultiVolumeNode = None self.__fgMultiVolumeNode = None self.__mvLabels = [] self.__xLogScaleEnabled = False self.__yLogScaleEnabled = False self.__mvRange = [0, 0] self.__nFramesForBaselineCalculation = 1 self.__chartMode = None self.activateSignalIntensityMode() self.baselineAverageSignal = 0 self.__showLegend = False
def onThresholdValuesChanged(self,lower,upper): # Check if this is the first update of the threshold range if self.thresholdFlag == 1: newScalars = vtk.vtkFloatArray() newScalars.SetNumberOfComponents( self.scalars.GetNumberOfComponents() ) newScalars.SetNumberOfValues ( self.numberOfPoints ) newScalars.SetName( "NewScalars" ) # Set values of new scalars according to threshold for i in xrange( self.numberOfPoints ): value = self.scalars.GetValue( i ) if value < lower: newScalars.SetValue( i, 0 ) elif value > upper: newScalars.SetValue( i, self.range[1] ) else: newScalars.SetValue( i, value ) # Update the polydata with the new scalars self.polyData.GetPointData().AddArray( newScalars ) self.polyData.GetPointData().RemoveArray( "NRRDImage" ) self.polyData.Modified() self.outputModel.SetAndObservePolyData( self.polyData ) self.outputModel.GetDisplayNode().SetScalarVisibility( 1 ) self.outputModel.GetDisplayNode().SetActiveScalarName( "NewScalars" )
def onThresholdValuesChanged(self, lower, upper): # Check if this is the first update of the threshold range if self.thresholdFlag == 1: newScalars = vtk.vtkFloatArray() newScalars.SetNumberOfComponents( self.scalars.GetNumberOfComponents()) newScalars.SetNumberOfValues(self.numberOfPoints) newScalars.SetName("NewScalars") # Set values of new scalars according to threshold for i in xrange(self.numberOfPoints): value = self.scalars.GetValue(i) if value < lower: newScalars.SetValue(i, 0) elif value > upper: newScalars.SetValue(i, self.range[1]) else: newScalars.SetValue(i, value) # Update the polydata with the new scalars self.polyData.GetPointData().AddArray(newScalars) self.polyData.GetPointData().RemoveArray("NRRDImage") self.polyData.Modified() self.outputModel.SetAndObservePolyData(self.polyData) self.outputModel.GetDisplayNode().SetScalarVisibility(1) self.outputModel.GetDisplayNode().SetActiveScalarName("NewScalars")
def generateVTKFloatArrayFromNumpy(self, np_array): size = np_array.size vtk_float = vtk.vtkFloatArray() vtk_float.SetNumberOfComponents(1) for i in range(size): vtk_float.InsertNextTuple([np_array[i]]) return vtk_float
def __init__(self): self.__chartView = slicer.qMRMLPlotView() self.__chartView.setMRMLScene(slicer.mrmlScene) self.__chartViewNode = slicer.mrmlScene.AddNewNodeByClass( "vtkMRMLPlotViewNode") self.__chartView.setMRMLPlotViewNode(self.__chartViewNode) self.__chart = slicer.mrmlScene.AddNewNodeByClass( "vtkMRMLPlotChartNode") self.__chart.LegendVisibilityOff() self.__chart.SetAxisTitleFontSize(15) self.__chartViewNode.SetPlotChartNodeID(self.__chart.GetID()) self.__chartView.show() self.__bgxArray = vtk.vtkFloatArray() self.__bgyArray = vtk.vtkFloatArray() self.__bgxArray.SetName('x') self.__bgyArray.SetName('1st multivolume') self.__chartTableNode = self.createNewVTKTableNode( self.__bgxArray, self.__bgyArray) self.__chartTable = self.__chartTableNode.GetTable() self.__fgChartTableNode = None self.__bgPlot = None self.__fgPlot = None self.__bgMultiVolumeNode = None self.__fgMultiVolumeNode = None self.__mvLabels = [] self.__xLogScaleEnabled = False self.__yLogScaleEnabled = False self.__mvRange = [0, 0] self.__nFramesForBaselineCalculation = 1 self.__chartMode = None self.activateSignalIntensityMode() self.baselineAverageSignal = 0 self.__showLegend = False
def onProbeVolumeButtonClicked(self): # Set flag to prevent model from being thresholded without user input self.thresholdFlag = 0 wallModel = self.inputModelSelector.currentNode() inputVol = self.inputVolumeSelector.currentNode() self.polyData = vtk.vtkPolyData() if not (wallModel): qt.QMessageBox.critical(slicer.util.mainWindow(), 'Scar Visualization', 'Wall model is required to proceed.') elif not (inputVol): qt.QMessageBox.critical(slicer.util.mainWindow(), 'Scar Visualization', 'Input volume is required to proceed.') else: self.outputModel = slicer.vtkMRMLModelNode() self.outputModel.SetName("Output Model") slicer.mrmlScene.AddNode(self.outputModel) paramProbe = {} paramProbe['InputVolume'] = inputVol paramProbe['InputModel'] = wallModel paramProbe['OutputModel'] = self.outputModel # Pass parameters to Probe Volume Model slicer.cli.run(slicer.modules.probevolumewithmodel, None, paramProbe, wait_for_completion=True) # Set color of output model labelsColorNode = slicer.modules.colors.logic( ).GetColorTableNodeID(35) # Color Warm Tint 3 self.outputModel.GetDisplayNode().SetAndObserveColorNodeID( labelsColorNode) # Delete input model which is not required anymore slicer.mrmlScene.RemoveNode(wallModel) # Update threshold widget with scalar values from model self.polyData = self.outputModel.GetPolyData() self.numberOfPoints = self.polyData.GetNumberOfPoints() self.scalars = vtk.vtkFloatArray() self.scalars = self.polyData.GetPointData().GetScalars("NRRDImage") self.range = [0] * 2 numberOfComponents = self.scalars.GetNumberOfComponents() for i in xrange(numberOfComponents): self.scalars.GetRange(self.range, i) lowerThreshold = self.range[0] upperThreshold = self.range[1] # Set threshold range according to current model self.threshold.minimum = lowerThreshold self.threshold.maximum = upperThreshold self.thresholdFlag = 1
def onProbeVolumeButtonClicked(self): # Set flag to prevent model from being thresholded without user input self.thresholdFlag = 0 wallModel = self.inputModelSelector.currentNode() inputVol = self.inputVolumeSelector.currentNode() self.polyData = vtk.vtkPolyData() if not (wallModel): qt.QMessageBox.critical(slicer.util.mainWindow(), 'Scar Visualization', 'Wall model is required to proceed.') elif not (inputVol): qt.QMessageBox.critical(slicer.util.mainWindow(), 'Scar Visualization', 'Input volume is required to proceed.') else: self.outputModel = slicer.vtkMRMLModelNode() self.outputModel.SetName( "Output Model" ) slicer.mrmlScene.AddNode(self.outputModel) paramProbe = {} paramProbe['InputVolume'] = inputVol paramProbe['InputModel'] = wallModel paramProbe['OutputModel'] = self.outputModel # Pass parameters to Probe Volume Model slicer.cli.run( slicer.modules.probevolumewithmodel, None, paramProbe, wait_for_completion=True ) # Set color of output model labelsColorNode = slicer.modules.colors.logic().GetColorTableNodeID(35) # Color Warm Tint 3 self.outputModel.GetDisplayNode().SetAndObserveColorNodeID(labelsColorNode) # Delete input model which is not required anymore slicer.mrmlScene.RemoveNode( wallModel ) # Update threshold widget with scalar values from model self.polyData = self.outputModel.GetPolyData() self.numberOfPoints = self.polyData.GetNumberOfPoints() self.scalars = vtk.vtkFloatArray() self.scalars = self.polyData.GetPointData().GetScalars( "NRRDImage" ) self.range = [0] * 2 numberOfComponents = self.scalars.GetNumberOfComponents() for i in xrange ( numberOfComponents ): self.scalars.GetRange(self.range, i) lowerThreshold = self.range[0] upperThreshold = self.range[1] # Set threshold range according to current model self.threshold.minimum = lowerThreshold self.threshold.maximum = upperThreshold self.thresholdFlag = 1
def onApplyThreshold(self): min, max = self.getDistanceBound() newPoints = vtk.vtkPoints() newLines = vtk.vtkCellArray() newTensors = vtk.vtkFloatArray() newTensors.SetNumberOfComponents(9) newScalars = vtk.vtkFloatArray() points = self.inputPolyData.GetPoints() lines = self.inputPolyData.GetLines() tensors = self.inputPolyData.GetPointData().GetTensors() lines.InitTraversal() newId = 0 for length in self.distanceTable: if length <= self.thresholdMax.value and length >= self.thresholdMin.value: ids = vtk.vtkIdList() lines.GetNextCell(ids) newLine = vtk.vtkPolyLine() #print(ids.GetNumberOfIds()) newLine.GetPointIds().SetNumberOfIds(ids.GetNumberOfIds()) #print(((length-min)/(max-min))*100) for i in range(ids.GetNumberOfIds()): newPoints.InsertNextPoint(points.GetPoint(ids.GetId(i))) newLine.GetPointIds().SetId(i, newId) newScalars.InsertNextValue(((length - min) / (max - min))) newId += 1 tensorValue = [0] * 9 if (tensors != None): for j in range(9): tensorValue[j] = tensors.GetComponent( ids.GetId(i), j) newTensors.InsertNextTuple(tensorValue) newLines.InsertNextCell(newLine) self.outputPolyData = vtk.vtkPolyData() self.outputPolyData.SetPoints(newPoints) self.outputPolyData.SetLines(newLines) self.outputPolyData.GetPointData().SetTensors(newTensors) newScalars.SetName("Length") self.outputPolyData.GetPointData().AddArray(newScalars) self.outputNode.SetAndObservePolyData(self.outputPolyData) chartViewNodes = slicer.mrmlScene.GetNodesByClass( 'vtkMRMLChartViewNode') chartViewNodes.InitTraversal() chartViewNode = chartViewNodes.GetNextItemAsObject() arrayNode = slicer.mrmlScene.AddNode(slicer.vtkMRMLDoubleArrayNode()) array = arrayNode.GetArray() array.SetNumberOfTuples(10) step = (max - min) / 10 interMin = min interMax = min + step for i in range(10): numberOfFibers = 0 for length in self.distanceTable: if length <= interMax and length >= interMin and length <= self.thresholdMax.value and length >= self.thresholdMin.value: numberOfFibers += 1 array.SetComponent(i, 0, (interMin + interMax) / 2) array.SetComponent(i, 1, numberOfFibers) array.SetComponent(i, 2, 0) interMin += step interMax += step chartNode = slicer.mrmlScene.AddNode(slicer.vtkMRMLChartNode()) chartNode.AddArray("Fiber Length", arrayNode.GetID()) chartViewNode.SetChartNodeID(chartNode.GetID()) chartNode.SetProperty('default', 'title', 'Length Distribution') chartNode.SetProperty('default', 'xAxisLabel', 'Length') chartNode.SetProperty('default', 'yAxisLabel', 'Distribution') chartNode.SetProperty('default', 'type', 'Bar')
def setup( self ): self.parent.connect('mrmlSceneChanged(vtkMRMLScene*)', self.onVCMRMLSceneChanged) w = qt.QWidget() layout = qt.QGridLayout() w.setLayout(layout) self.layout.addWidget(w) w.show() self.layout = layout # create frames self.inputFrame = ctk.ctkCollapsibleButton() self.inputFrame.text = "Input" self.inputFrame.collapsed = 0 inputFrameLayout = qt.QFormLayout(self.inputFrame) self.layout.addWidget(self.inputFrame) self.ctrlFrame = ctk.ctkCollapsibleButton() self.ctrlFrame.text = "Frame control" self.ctrlFrame.collapsed = 0 ctrlFrameLayout = qt.QGridLayout(self.ctrlFrame) self.layout.addWidget(self.ctrlFrame) self.plotFrame = ctk.ctkCollapsibleButton() self.plotFrame.text = "Plotting" self.plotFrame.collapsed = 0 plotFrameLayout = qt.QGridLayout(self.plotFrame) self.layout.addWidget(self.plotFrame) self.plotSettingsFrame = ctk.ctkCollapsibleButton() self.plotSettingsFrame.text = "Settings" self.plotSettingsFrame.collapsed = 1 plotSettingsFrameLayout = qt.QGridLayout(self.plotSettingsFrame) plotFrameLayout.addWidget(self.plotSettingsFrame,0,1) label = qt.QLabel('Input multivolume') self.__mvSelector = slicer.qMRMLNodeComboBox() self.__mvSelector.nodeTypes = ['vtkMRMLMultiVolumeNode'] self.__mvSelector.setMRMLScene(slicer.mrmlScene) self.__mvSelector.connect('mrmlSceneChanged(vtkMRMLScene*)', self.onVCMRMLSceneChanged) self.__mvSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onInputChanged) self.__mvSelector.addEnabled = 0 inputFrameLayout.addRow(label, self.__mvSelector) label = qt.QLabel('Input secondary multivolume') self.fgSelector = slicer.qMRMLNodeComboBox() self.fgSelector.nodeTypes = ['vtkMRMLMultiVolumeNode'] self.fgSelector.setMRMLScene(slicer.mrmlScene) self.fgSelector.addEnabled = 0 self.fgSelector.noneEnabled = 1 self.fgSelector.toolTip = "Secondary multivolume will be used for the secondary \ plot in interactive charting. As an example, this can be used to overlay the \ curve obtained by fitting a model to the data" inputFrameLayout.addRow(label, self.fgSelector) # TODO: initialize the slider based on the contents of the labels array # slider to scroll over metadata stored in the vector container being explored self.__mdSlider = ctk.ctkSliderWidget() label = qt.QLabel('Current frame number') # "play" control self.playButton = qt.QPushButton('Play') self.playButton.toolTip = 'Iterate over multivolume frames' self.playButton.checkable = True ctrlFrameLayout.addWidget(label, 0, 0) ctrlFrameLayout.addWidget(self.__mdSlider, 0, 1) ctrlFrameLayout.addWidget(self.playButton, 0, 2) self.playButton.connect('toggled(bool)', self.onPlayButtonToggled) self.__mdSlider.connect('valueChanged(double)', self.onSliderChanged) label = qt.QLabel('Current frame copy') self.__vfSelector = slicer.qMRMLNodeComboBox() self.__vfSelector.nodeTypes = ['vtkMRMLScalarVolumeNode'] self.__vfSelector.setMRMLScene(slicer.mrmlScene) self.__vfSelector.connect('mrmlSceneChanged(vtkMRMLScene*)', self.onVFMRMLSceneChanged) self.__vfSelector.addEnabled = 1 self.__vfSelector.enabled = 0 # do not show "children" of vtkMRMLScalarVolumeNode self.__vfSelector.hideChildNodeTypes = ["vtkMRMLDiffusionWeightedVolumeNode", \ "vtkMRMLDiffusionTensorVolumeNode", "vtkMRMLVectorVolumeNode"] self.extractFrame = False self.extractButton = qt.QPushButton('Enable current frame copying') self.extractButton.checkable = True self.extractButton.connect('toggled(bool)', self.onExtractFrameToggled) ctrlFrameLayout.addWidget(label, 1, 0) ctrlFrameLayout.addWidget(self.__vfSelector,1,1,1,2) ctrlFrameLayout.addWidget(self.extractButton,2,0,1,3) # initialize slice observers (from DataProbe.py) # keep list of pairs: [observee,tag] so they can be removed easily self.styleObserverTags = [] # keep a map of interactor styles to sliceWidgets so we can easily get sliceLogic self.sliceWidgetsPerStyle = {} self.refreshObservers() # label map for probing label = qt.QLabel('Probed label volume') self.__fSelector = slicer.qMRMLNodeComboBox() self.__fSelector.nodeTypes = ['vtkMRMLScalarVolumeNode'] self.__fSelector.addAttribute('vtkMRMLScalarVolumeNode','LabelMap','1') self.__fSelector.toolTip = 'Label map to be probed' self.__fSelector.setMRMLScene(slicer.mrmlScene) self.__fSelector.addEnabled = 0 self.chartButton = qt.QPushButton('Chart') self.chartButton.checkable = False self.chartButton.connect('clicked()', self.onChartRequested) plotSettingsFrameLayout.addWidget(label,0,0) plotSettingsFrameLayout.addWidget(self.__fSelector,0,1) plotSettingsFrameLayout.addWidget(self.chartButton,0,2) self.iCharting = qt.QPushButton() self.iCharting.text = 'Enable interactive charting' self.iCharting.checkable = True plotSettingsFrameLayout.addWidget(self.iCharting,1,0,1,3) self.iCharting.setChecked(True) self.iCharting.connect('toggled(bool)', self.onInteractiveChartingChanged) groupLabel = qt.QLabel('Interactive plotting mode:') self.iChartingMode = qt.QButtonGroup() self.iChartingIntensity = qt.QRadioButton('Signal intensity') #self.iChartingIntensity.tooltip = 'Plot range adjusted dynamically to the range over the time course for the selected pixel' self.iChartingIntensityFixedAxes = qt.QRadioButton('Fixed range intensity') #self.iChartingIntensityFixedAxes.tooltip = "If checked, the extent of the vertical axis of the plot will be fixed to the range of the intensities in the input MultiVolume" self.iChartingPercent = qt.QRadioButton('Percent change') #self.iChartingPercent.tooltip = 'Percent change relative to the average of the first N frames (parameter set below)' self.iChartingIntensity.setChecked(1) self.groupWidget = qt.QWidget() self.groupLayout = qt.QFormLayout(self.groupWidget) self.groupLayout.addRow(groupLabel) self.groupLayout.addRow(self.iChartingIntensity) self.groupLayout.addRow(self.iChartingIntensityFixedAxes) self.groupLayout.addRow(self.iChartingPercent) self.baselineFrames = qt.QSpinBox() self.baselineFrames.minimum = 1 label = qt.QLabel('Number of frames for baseline calculation') self.groupLayout.addRow(label,self.baselineFrames) self.xLogScaleCheckBox = qt.QCheckBox() self.xLogScaleCheckBox.setChecked(0) label = qt.QLabel('Use log scale for X axis') self.groupLayout.addRow(self.xLogScaleCheckBox,label) self.xLogScaleCheckBox.connect('stateChanged(int)', self.onXLogScaleRequested) self.yLogScaleCheckBox = qt.QCheckBox() self.yLogScaleCheckBox.setChecked(0) label = qt.QLabel('Use log scale for Y axis') self.groupLayout.addRow(self.yLogScaleCheckBox,label) self.yLogScaleCheckBox.connect('stateChanged(int)', self.onYLogScaleRequested) plotSettingsFrameLayout.addWidget(self.groupWidget,2,0) # add chart container widget self.__chartView = ctk.ctkVTKChartView(w) plotFrameLayout.addWidget(self.__chartView,3,0,1,3) self.__chart = self.__chartView.chart() self.__chartTable = vtk.vtkTable() self.__xArray = vtk.vtkFloatArray() self.__yArray = vtk.vtkFloatArray() # will crash if there is no name self.__xArray.SetName('') self.__yArray.SetName('signal intensity') self.__chartTable.AddColumn(self.__xArray) self.__chartTable.AddColumn(self.__yArray)
def processEvent(self,observee,event): if not self.iCharting.checked: return if self.__mvNode == None: return mvImage = self.__mvNode.GetImageData() nComponents = self.__mvNode.GetNumberOfFrames() # TODO: use a timer to delay calculation and compress events if event == 'LeaveEvent': # reset all the readouts # TODO: reset the label text return if not self.sliceWidgetsPerStyle.has_key(observee): return sliceWidget = self.sliceWidgetsPerStyle[observee] sliceLogic = sliceWidget.sliceLogic() interactor = observee.GetInteractor() xy = interactor.GetEventPosition() xyz = sliceWidget.sliceView().convertDeviceToXYZ(xy); ras = sliceWidget.sliceView().convertXYZToRAS(xyz) bgLayer = sliceLogic.GetBackgroundLayer() fgLayer = sliceLogic.GetForegroundLayer() volumeNode = bgLayer.GetVolumeNode() fgVolumeNode = self.fgSelector.currentNode() if not volumeNode or volumeNode.GetID() != self.__mvNode.GetID(): return if volumeNode != self.__mvNode: return nameLabel = volumeNode.GetName() xyToIJK = bgLayer.GetXYToIJKTransform() ijkFloat = xyToIJK.TransformDoublePoint(xyz) ijk = [] for element in ijkFloat: try: index = int(round(element)) except ValueError: index = 0 ijk.append(index) extent = mvImage.GetExtent() if not (ijk[0]>=extent[0] and ijk[0]<=extent[1] and \ ijk[1]>=extent[2] and ijk[1]<=extent[3] and \ ijk[2]>=extent[4] and ijk[2]<=extent[5]): # pixel outside the valid extent return useFg = False if fgVolumeNode: fgxyToIJK = fgLayer.GetXYToIJKTransform() fgijkFloat = xyToIJK.TransformDoublePoint(xyz) fgijk = [] for element in fgijkFloat: try: index = int(round(element)) except ValueError: index = 0 fgijk.append(index) fgImage = fgVolumeNode.GetImageData() fgChartTable = vtk.vtkTable() if fgijk[0] == ijk[0] and fgijk[1] == ijk[1] and fgijk[2] == ijk[2] and \ fgImage.GetNumberOfScalarComponents() == mvImage.GetNumberOfScalarComponents(): useFg = True fgxArray = vtk.vtkFloatArray() fgxArray.SetNumberOfTuples(nComponents) fgxArray.SetNumberOfComponents(1) fgxArray.Allocate(nComponents) fgxArray.SetName('frame') fgyArray = vtk.vtkFloatArray() fgyArray.SetNumberOfTuples(nComponents) fgyArray.SetNumberOfComponents(1) fgyArray.Allocate(nComponents) fgyArray.SetName('signal intensity') # will crash if there is no name fgChartTable.AddColumn(fgxArray) fgChartTable.AddColumn(fgyArray) fgChartTable.SetNumberOfRows(nComponents) # get the vector of values at IJK for c in range(nComponents): val = mvImage.GetScalarComponentAsDouble(ijk[0],ijk[1],ijk[2],c) self.__chartTable.SetValue(c, 0, self.__mvLabels[c]) self.__chartTable.SetValue(c, 1, val) if useFg: fgValue = fgImage.GetScalarComponentAsDouble(ijk[0],ijk[1],ijk[2],c) fgChartTable.SetValue(c,0,self.__mvLabels[c]) fgChartTable.SetValue(c,1,fgValue) baselineAverageSignal = 0 if self.iChartingPercent.checked: # check if percent plotting was requested and recalculate nBaselines = min(self.baselineFrames.value,nComponents) for c in range(nBaselines): baselineAverageSignal += mvImage.GetScalarComponentAsDouble(ijk[0],ijk[1],ijk[2],c) baselineAverageSignal /= nBaselines if baselineAverageSignal != 0: for c in range(nComponents): intensity = mvImage.GetScalarComponentAsDouble(ijk[0],ijk[1],ijk[2],c) self.__chartTable.SetValue(c,1,(intensity/baselineAverageSignal-1)*100.) self.__chart.RemovePlot(0) self.__chart.RemovePlot(0) if self.iChartingPercent.checked and baselineAverageSignal != 0: self.__chart.GetAxis(0).SetTitle('change relative to baseline, %') else: self.__chart.GetAxis(0).SetTitle('signal intensity') tag = str(self.__mvNode.GetAttribute('MultiVolume.FrameIdentifyingDICOMTagName')) units = str(self.__mvNode.GetAttribute('MultiVolume.FrameIdentifyingDICOMTagUnits')) xTitle = tag+', '+units self.__chart.GetAxis(1).SetTitle(xTitle) if self.iChartingIntensityFixedAxes.checked == True: self.__chart.GetAxis(0).SetBehavior(vtk.vtkAxis.FIXED) self.__chart.GetAxis(0).SetRange(self.__mvRange[0],self.__mvRange[1]) else: self.__chart.GetAxis(0).SetBehavior(vtk.vtkAxis.AUTO) if useFg: plot = self.__chart.AddPlot(vtk.vtkChart.POINTS) plot.SetInput(self.__chartTable, 0, 1) fgplot = self.__chart.AddPlot(vtk.vtkChart.LINE) fgplot.SetInput(fgChartTable, 0, 1) else: plot = self.__chart.AddPlot(vtk.vtkChart.LINE) plot.SetInput(self.__chartTable, 0, 1) if self.xLogScaleCheckBox.checkState() == 2: title = self.__chart.GetAxis(1).GetTitle() self.__chart.GetAxis(1).SetTitle('log of '+title) if self.yLogScaleCheckBox.checkState() == 2: title = self.__chart.GetAxis(0).GetTitle() self.__chart.GetAxis(0).SetTitle('log of '+title)
def setup(self): self.parent.connect('mrmlSceneChanged(vtkMRMLScene*)', self.onVCMRMLSceneChanged) w = qt.QWidget() layout = qt.QGridLayout() w.setLayout(layout) self.layout.addWidget(w) w.show() self.layout = layout # create frames self.inputFrame = ctk.ctkCollapsibleButton() self.inputFrame.text = "Input" self.inputFrame.collapsed = 0 inputFrameLayout = qt.QFormLayout(self.inputFrame) self.layout.addWidget(self.inputFrame) self.ctrlFrame = ctk.ctkCollapsibleButton() self.ctrlFrame.text = "Frame control" self.ctrlFrame.collapsed = 0 ctrlFrameLayout = qt.QGridLayout(self.ctrlFrame) self.layout.addWidget(self.ctrlFrame) self.plotFrame = ctk.ctkCollapsibleButton() self.plotFrame.text = "Plotting" self.plotFrame.collapsed = 0 plotFrameLayout = qt.QGridLayout(self.plotFrame) self.layout.addWidget(self.plotFrame) label = qt.QLabel('Input multivolume') self.__mvSelector = slicer.qMRMLNodeComboBox() self.__mvSelector.nodeTypes = ['vtkMRMLMultiVolumeNode'] self.__mvSelector.setMRMLScene(slicer.mrmlScene) self.__mvSelector.connect('mrmlSceneChanged(vtkMRMLScene*)', self.onVCMRMLSceneChanged) self.__mvSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onInputChanged) self.__mvSelector.addEnabled = 0 inputFrameLayout.addRow(label, self.__mvSelector) ##self.layout.addWidget(label) ##self.layout.addWidget(self.__mvSelector) # TODO: initialize the slider based on the contents of the labels array # slider to scroll over metadata stored in the vector container being explored self.__mdSlider = ctk.ctkSliderWidget() #self.__mdSlider.setRange(0,10) #self.__mdSlider.setValue(5) label = qt.QLabel('Current frame number') ##self.layout.addWidget(label) ##self.layout.addWidget(self.__mdSlider) # "play" control self.playButton = qt.QPushButton('Play') self.playButton.toolTip = 'Iterate over multivolume frames' self.playButton.checkable = True ctrlFrameLayout.addWidget(label, 0, 0) ctrlFrameLayout.addWidget(self.__mdSlider, 0, 1) ctrlFrameLayout.addWidget(self.playButton, 0, 2) self.playButton.connect('toggled(bool)', self.onPlayButtonToggled) self.__mdSlider.connect('valueChanged(double)', self.onSliderChanged) label = qt.QLabel('Current frame copy') self.__vfSelector = slicer.qMRMLNodeComboBox() self.__vfSelector.nodeTypes = ['vtkMRMLScalarVolumeNode'] self.__vfSelector.setMRMLScene(slicer.mrmlScene) self.__vfSelector.connect('mrmlSceneChanged(vtkMRMLScene*)', self.onVFMRMLSceneChanged) self.__vfSelector.addEnabled = 1 self.__vfSelector.enabled = 0 # do not show "children" of vtkMRMLScalarVolumeNode self.__vfSelector.hideChildNodeTypes = ["vtkMRMLDiffusionWeightedVolumeNode", \ "vtkMRMLDiffusionTensorVolumeNode", "vtkMRMLVectorVolumeNode"] self.extractFrame = False self.extractButton = qt.QPushButton('Enable current frame copying') self.extractButton.checkable = True self.extractButton.connect('toggled(bool)', self.onExtractFrameToggled) ctrlFrameLayout.addWidget(label, 1, 0) ctrlFrameLayout.addWidget(self.__vfSelector, 1, 1, 1, 2) ctrlFrameLayout.addWidget(self.extractButton, 2, 0, 1, 3) # initialize slice observers (from DataProbe.py) # keep list of pairs: [observee,tag] so they can be removed easily self.styleObserverTags = [] # keep a map of interactor styles to sliceWidgets so we can easily get sliceLogic self.sliceWidgetsPerStyle = {} self.refreshObservers() # label map for probing label = qt.QLabel('Probed label volume') self.__fSelector = slicer.qMRMLNodeComboBox() self.__fSelector.nodeTypes = ['vtkMRMLScalarVolumeNode'] self.__fSelector.addAttribute('vtkMRMLScalarVolumeNode', 'LabelMap', '1') self.__fSelector.toolTip = 'Label map to be probed' self.__fSelector.setMRMLScene(slicer.mrmlScene) self.__fSelector.addEnabled = 0 self.__fSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onLabelVolumeChanged) self.__fSelector.connect('mrmlSceneChanged(vtkMRMLScene*)', self.onLVMRMLSceneChanged) plotFrameLayout.addWidget(label, 0, 0, 1, 1) plotFrameLayout.addWidget(self.__fSelector, 0, 1, 1, 2) self.iCharting = qt.QPushButton() self.iCharting.text = 'Enable interactive charting' self.iCharting.checkable = True plotFrameLayout.addWidget(self.iCharting, 1, 0, 1, 3) self.iCharting.setChecked(True) self.iCharting.connect('toggled(bool)', self.onInteractiveChartingChanged) label = qt.QLabel("Use intensity range to fix axis extent") label.toolTip = "If checked, the extent of the vertical axis of the plot will be fixed to the range of the intensities in the input MultiVolume" self.__fixedAxesCheckbox = qt.QCheckBox() self.__fixedAxesCheckbox.toolTip = "If checked, the extent of the vertical axis of the plot will be fixed to the range of the intensities in the input MultiVolume" self.__fixedAxesCheckbox.checked = False plotFrameLayout.addWidget(label, 2, 0) plotFrameLayout.addWidget(self.__fixedAxesCheckbox, 2, 1, 1, 2) # add chart container widget self.__chartView = ctk.ctkVTKChartView(w) plotFrameLayout.addWidget(self.__chartView, 3, 0, 1, 3) self.__chart = self.__chartView.chart() self.__chartTable = vtk.vtkTable() self.__xArray = vtk.vtkFloatArray() self.__yArray = vtk.vtkFloatArray() # will crash if there is no name self.__xArray.SetName('') self.__yArray.SetName('signal intensity') self.__chartTable.AddColumn(self.__xArray) self.__chartTable.AddColumn(self.__yArray)
def createChart(self, sliceWidget, xy, ignoreCurrentBackground=False): if not sliceWidget and not xy: return sliceLogic = sliceWidget.sliceLogic() bgLayer = sliceLogic.GetBackgroundLayer() doIJKToRASTransformation = False bgVolumeNode = bgLayer.GetVolumeNode() if not bgVolumeNode or bgVolumeNode.GetID() != self.__bgMultiVolumeNode.GetID() or \ bgVolumeNode != self.__bgMultiVolumeNode: if not ignoreCurrentBackground: return else: doIJKToRASTransformation = True xyz = sliceWidget.sliceView().convertDeviceToXYZ(xy) xyToIJK = bgLayer.GetXYToIJKTransform() ijkFloat = xyToIJK.TransformDoublePoint(xyz) if doIJKToRASTransformation: RAStoIJK = vtk.vtkMatrix4x4() self.__bgMultiVolumeNode.GetRASToIJKMatrix(RAStoIJK) ras = self.xyToRAS(sliceLogic, xy) ijkFloat = RAStoIJK.MultiplyPoint([ras[0], ras[1], ras[2], 1])[:3] bgijk = self.getIJKIntFromIJKFloat(ijkFloat) bgImage = self.__bgMultiVolumeNode.GetImageData() if not self.arePixelsWithinImageExtent(bgImage, bgijk): self.clearPlots() return nComponents = self.__bgMultiVolumeNode.GetNumberOfFrames() useFg = False fgImage = None fgijk = None if self.__fgMultiVolumeNode: fgijkFloat = xyToIJK.TransformDoublePoint(xyz) fgijk = self.getIJKIntFromIJKFloat(fgijkFloat) fgImage = self.__fgMultiVolumeNode.GetImageData() if self.__fgChartTableNode: slicer.mrmlScene.RemoveNode(self.__fgChartTableNode) self.__fgChartTableNode = slicer.mrmlScene.AddNewNodeByClass( "vtkMRMLTableNode", "fgChartTable") fgChartTable = self.__fgChartTableNode.GetTable() if fgijk[0] == bgijk[0] and fgijk[1] == bgijk[1] and fgijk[2] == bgijk[2] and \ fgImage.GetNumberOfScalarComponents() == bgImage.GetNumberOfScalarComponents(): useFg = True fgxArray = vtk.vtkFloatArray() self.refreshArray(fgxArray, nComponents, 'fg') fgyArray = vtk.vtkFloatArray() self.refreshArray(fgyArray, nComponents, '2nd multivolume') # will crash if there is no name fgChartTable.AddColumn(fgxArray) fgChartTable.AddColumn(fgyArray) fgChartTable.SetNumberOfRows(nComponents) # get the vector of values at IJK for c in range(nComponents): val = bgImage.GetScalarComponentAsDouble(bgijk[0], bgijk[1], bgijk[2], c) if math.isnan(val): val = 0 self.__chartTable.SetValue(c, 0, self.__mvLabels[c]) self.__chartTable.SetValue(c, 1, val) if useFg: fgValue = fgImage.GetScalarComponentAsDouble( bgijk[0], bgijk[1], bgijk[2], c) if math.isnan(fgValue): fgValue = 0 fgChartTable.SetValue(c, 0, self.__mvLabels[c]) fgChartTable.SetValue(c, 1, fgValue) self.baselineAverageSignal = 0 if self.__chartMode == self.PERCENTAGE_CHANGE_MODE: self.computePercentageChangeWithRespectToBaseline( self.__bgMultiVolumeNode, self.__chartTable, bgijk) if useFg: self.computePercentageChangeWithRespectToBaseline( self.__fgMultiVolumeNode, fgChartTable, fgijk) self.clearPlots() self.setAxesTitle() self.__bgPlot = slicer.mrmlScene.AddNewNodeByClass( "vtkMRMLPlotSeriesNode", "1st multivolume") self.__bgPlot.SetAndObserveTableNodeID(self.__chartTableNode.GetID()) self.__bgPlot.SetXColumnName('x') self.__bgPlot.SetYColumnName('1st multivolume') self.__bgPlot.SetPlotType(slicer.vtkMRMLPlotSeriesNode.PlotTypeScatter) if useFg: self.__bgPlot.SetLineStyle( slicer.vtkMRMLPlotSeriesNode.LineStyleNone) else: self.__bgPlot.SetMarkerStyle( slicer.vtkMRMLPlotSeriesNode.MarkerStyleNone) self.__chart.AddAndObservePlotSeriesNodeID(self.__bgPlot.GetID()) # bgPlot.SetLabel("Primary multivolume ") if useFg: self.__fgPlot = slicer.mrmlScene.AddNewNodeByClass( "vtkMRMLPlotSeriesNode", "2nd multivolume") self.__fgPlot.SetAndObserveTableNodeID( self.__fgChartTableNode.GetID()) self.__fgPlot.SetXColumnName('fg') self.__fgPlot.SetYColumnName('2nd multivolume') self.__fgPlot.SetPlotType( slicer.vtkMRMLPlotSeriesNode.PlotTypeScatter) self.__fgPlot.SetColor(1, 0, 0) self.__fgPlot.SetMarkerStyle( slicer.vtkMRMLPlotSeriesNode.MarkerStyleNone) self.__chart.AddAndObservePlotSeriesNodeID(self.__fgPlot.GetID())
def processEvent(self, observee, event): if not self.iCharting.checked: return if self.__mvNode == None: return mvImage = self.__mvNode.GetImageData() nComponents = self.__mvNode.GetNumberOfFrames() # TODO: use a timer to delay calculation and compress events if event == 'LeaveEvent': # reset all the readouts # TODO: reset the label text return if not self.sliceWidgetsPerStyle.has_key(observee): return sliceWidget = self.sliceWidgetsPerStyle[observee] sliceLogic = sliceWidget.sliceLogic() interactor = observee.GetInteractor() xy = interactor.GetEventPosition() xyz = sliceWidget.sliceView().convertDeviceToXYZ(xy) ras = sliceWidget.sliceView().convertXYZToRAS(xyz) bgLayer = sliceLogic.GetBackgroundLayer() fgLayer = sliceLogic.GetForegroundLayer() volumeNode = bgLayer.GetVolumeNode() fgVolumeNode = self.fgSelector.currentNode() if not volumeNode or volumeNode.GetID() != self.__mvNode.GetID(): return if volumeNode != self.__mvNode: return nameLabel = volumeNode.GetName() xyToIJK = bgLayer.GetXYToIJKTransform() ijkFloat = xyToIJK.TransformDoublePoint(xyz) ijk = [] for element in ijkFloat: try: index = int(round(element)) except ValueError: index = 0 ijk.append(index) extent = mvImage.GetExtent() if not (ijk[0]>=extent[0] and ijk[0]<=extent[1] and \ ijk[1]>=extent[2] and ijk[1]<=extent[3] and \ ijk[2]>=extent[4] and ijk[2]<=extent[5]): # pixel outside the valid extent return useFg = False if fgVolumeNode: fgxyToIJK = fgLayer.GetXYToIJKTransform() fgijkFloat = xyToIJK.TransformDoublePoint(xyz) fgijk = [] for element in fgijkFloat: try: index = int(round(element)) except ValueError: index = 0 fgijk.append(index) fgImage = fgVolumeNode.GetImageData() fgChartTable = vtk.vtkTable() if fgijk[0] == ijk[0] and fgijk[1] == ijk[1] and fgijk[2] == ijk[2] and \ fgImage.GetNumberOfScalarComponents() == mvImage.GetNumberOfScalarComponents(): useFg = True fgxArray = vtk.vtkFloatArray() fgxArray.SetNumberOfTuples(nComponents) fgxArray.SetNumberOfComponents(1) fgxArray.Allocate(nComponents) fgxArray.SetName('frame') fgyArray = vtk.vtkFloatArray() fgyArray.SetNumberOfTuples(nComponents) fgyArray.SetNumberOfComponents(1) fgyArray.Allocate(nComponents) fgyArray.SetName('signal intensity') # will crash if there is no name fgChartTable.AddColumn(fgxArray) fgChartTable.AddColumn(fgyArray) fgChartTable.SetNumberOfRows(nComponents) # get the vector of values at IJK for c in range(nComponents): val = mvImage.GetScalarComponentAsDouble(ijk[0], ijk[1], ijk[2], c) self.__chartTable.SetValue(c, 0, self.__mvLabels[c]) self.__chartTable.SetValue(c, 1, val) if useFg: fgValue = fgImage.GetScalarComponentAsDouble( ijk[0], ijk[1], ijk[2], c) fgChartTable.SetValue(c, 0, self.__mvLabels[c]) fgChartTable.SetValue(c, 1, fgValue) baselineAverageSignal = 0 if self.iChartingPercent.checked: # check if percent plotting was requested and recalculate nBaselines = min(self.baselineFrames.value, nComponents) for c in range(nBaselines): baselineAverageSignal += mvImage.GetScalarComponentAsDouble( ijk[0], ijk[1], ijk[2], c) baselineAverageSignal /= nBaselines if baselineAverageSignal != 0: for c in range(nComponents): intensity = mvImage.GetScalarComponentAsDouble( ijk[0], ijk[1], ijk[2], c) self.__chartTable.SetValue( c, 1, (intensity / baselineAverageSignal - 1) * 100.) self.__chart.RemovePlot(0) self.__chart.RemovePlot(0) if self.iChartingPercent.checked and baselineAverageSignal != 0: self.__chart.GetAxis(0).SetTitle('change relative to baseline, %') else: self.__chart.GetAxis(0).SetTitle('signal intensity') tag = str( self.__mvNode.GetAttribute( 'MultiVolume.FrameIdentifyingDICOMTagName')) units = str( self.__mvNode.GetAttribute( 'MultiVolume.FrameIdentifyingDICOMTagUnits')) xTitle = tag + ', ' + units self.__chart.GetAxis(1).SetTitle(xTitle) if self.iChartingIntensityFixedAxes.checked == True: self.__chart.GetAxis(0).SetBehavior(vtk.vtkAxis.FIXED) self.__chart.GetAxis(0).SetRange(self.__mvRange[0], self.__mvRange[1]) else: self.__chart.GetAxis(0).SetBehavior(vtk.vtkAxis.AUTO) if useFg: plot = self.__chart.AddPlot(vtk.vtkChart.POINTS) plot.SetInput(self.__chartTable, 0, 1) fgplot = self.__chart.AddPlot(vtk.vtkChart.LINE) fgplot.SetInput(fgChartTable, 0, 1) else: plot = self.__chart.AddPlot(vtk.vtkChart.LINE) plot.SetInput(self.__chartTable, 0, 1) if self.xLogScaleCheckBox.checkState() == 2: title = self.__chart.GetAxis(1).GetTitle() self.__chart.GetAxis(1).SetTitle('log of ' + title) if self.yLogScaleCheckBox.checkState() == 2: title = self.__chart.GetAxis(0).GetTitle() self.__chart.GetAxis(0).SetTitle('log of ' + title)
def setup(self, wName, parent): if self.ctrlWidget: return self.LinkViewers() self.numFrames = len(self.nodeImgList[0][0]) if parent: self.ctrlWidget = parent else: # Create seperate window self.ctrlWidget = slicer.qMRMLWidget() self.ctrlWidget.setMRMLScene(slicer.mrmlScene) self.ctrlWidget.setLayout(qt.QFormLayout()) self.ctrlWidget.setWindowTitle(wName) ctrlLayout = self.ctrlWidget.layout() # Create Slider Panel self.sliderPanel = qt.QWidget() self.sliderPanel.setLayout(qt.QGridLayout()) ctrlLayout.addWidget(self.sliderPanel) sliderLayout = self.sliderPanel.layout() if self.numFrames > 1: self.ctrlFrameLabel = qt.QLabel('Frame') self.ctrlFrameSlider = ctk.ctkSliderWidget() self.ctrlFrameSlider.connect('valueChanged(double)', self.onSliderFrameChanged) sliderLayout.addWidget(self.ctrlFrameLabel, 0, 0) sliderLayout.addWidget(self.ctrlFrameSlider, 0, 1) self.ctrlLevelLabel = qt.QLabel('Level') self.ctrlLevelSlider = ctk.ctkSliderWidget() self.ctrlLevelSlider.connect('valueChanged(double)', self.onSliderLevelChanged) sliderLayout.addWidget(self.ctrlLevelLabel, 1, 0) sliderLayout.addWidget(self.ctrlLevelSlider, 1, 1) self.ctrlWindowLabel = qt.QLabel('Window') self.ctrlWindowSlider = ctk.ctkSliderWidget() self.ctrlWindowSlider.connect('valueChanged(double)', self.onSliderWindowChanged) sliderLayout.addWidget(self.ctrlWindowLabel, 2, 0) sliderLayout.addWidget(self.ctrlWindowSlider, 2, 1) self.setSliderRangesAndValues() if self.sliceNodeList: self.orientPanel = qt.QWidget() self.orientPanel.setLayout(qt.QGridLayout()) ctrlLayout.addWidget(self.orientPanel) self.orientationButtons = {} index = 0 for orientation in self.orientations: self.orientationButtons[orientation] = qt.QRadioButton() self.orientationButtons[orientation].text = orientation # self.orientationBox.layout().addWidget(self.orientationButtons[orientation]) self.orientPanel.layout().addWidget( self.orientationButtons[orientation], 0, index) self.orientationButtons[orientation].connect( "clicked()", lambda o=orientation: self.setOrientation(o)) index += 1 self.setOrientation(self.selectedOrientation) if False: #self.plotFrame = ctk.ctkCollapsibleButton() #self.plotFrame.text = "Plotting" #self.plotFrame.collapsed = 0 self.plotFrame = qt.QWidget() plotFrameLayout = qt.QGridLayout(self.plotFrame) ctrlLayout.addWidget(self.plotFrame) self.plotSettingsFrame = ctk.ctkCollapsibleButton() self.plotSettingsFrame.text = "Settings" self.plotSettingsFrame.collapsed = 1 plotSettingsFrameLayout = qt.QGridLayout(self.plotSettingsFrame) #plotFrameLayout.addWidget(self.plotSettingsFrame,0,1) self.xLogScaleCheckBox = qt.QCheckBox() self.xLogScaleCheckBox.setChecked(0) self.yLogScaleCheckBox = qt.QCheckBox() self.yLogScaleCheckBox.setChecked(0) # taken from https://github.com/fedorov/MultiVolumeExplorer self.__chartView = ctk.ctkVTKChartView(self.ctrlWidget) # self.plotFrame) # self.ctrlWidget plotFrameLayout.addWidget(self.__chartView, 0, 0) self.__chart = self.__chartView.chart() self.__chartTable = vtk.vtkTable() self.__xArray = vtk.vtkFloatArray() self.__yArray = vtk.vtkFloatArray() # will crash if there is no name self.__xArray.SetName('') self.__yArray.SetName('signal intensity') self.__chartTable.AddColumn(self.__xArray) self.__chartTable.AddColumn(self.__yArray) self.onInputChanged() self.refreshObservers() self.buttonPanel = qt.QWidget() self.buttonPanel.setLayout(qt.QGridLayout()) ctrlLayout.addWidget(self.buttonPanel) self.exitButton = qt.QPushButton("Exit") self.exitButton.toolTip = "Close down slicer." self.exitButton.name = "sviewer exit" self.buttonPanel.layout().addWidget(self.exitButton, 0, 0) self.exitButton.connect('clicked()', exit) # do not do ctrlWin.show() here - for some reason window does not pop up then return self.ctrlWidget
def createChart(self, sliceWidget, xy, ignoreCurrentBackground=False): if not sliceWidget and not xy: return sliceLogic = sliceWidget.sliceLogic() bgLayer = sliceLogic.GetBackgroundLayer() doIJKToRASTransformation = False bgVolumeNode = bgLayer.GetVolumeNode() if not bgVolumeNode or bgVolumeNode.GetID() != self.__bgMultiVolumeNode.GetID() or \ bgVolumeNode != self.__bgMultiVolumeNode: if not ignoreCurrentBackground: return else: doIJKToRASTransformation = True xyz = sliceWidget.sliceView().convertDeviceToXYZ(xy) xyToIJK = bgLayer.GetXYToIJKTransform() ijkFloat = xyToIJK.TransformDoublePoint(xyz) if doIJKToRASTransformation: RAStoIJK = vtk.vtkMatrix4x4() self.__bgMultiVolumeNode.GetRASToIJKMatrix(RAStoIJK) ras = self.xyToRAS(sliceLogic, xy) ijkFloat = RAStoIJK.MultiplyPoint([ras[0], ras[1], ras[2], 1])[:3] bgijk = self.getIJKIntFromIJKFloat(ijkFloat) bgImage = self.__bgMultiVolumeNode.GetImageData() if not self.arePixelsWithinImageExtent(bgImage, bgijk): self.clearPlots() return nComponents = self.__bgMultiVolumeNode.GetNumberOfFrames() useFg = False fgImage = None fgijk = None if self.__fgMultiVolumeNode: fgijkFloat = xyToIJK.TransformDoublePoint(xyz) fgijk = self.getIJKIntFromIJKFloat(fgijkFloat) fgImage = self.__fgMultiVolumeNode.GetImageData() fgChartTable = vtk.vtkTable() if fgijk[0] == bgijk[0] and fgijk[1] == bgijk[1] and fgijk[2] == bgijk[2] and \ fgImage.GetNumberOfScalarComponents() == bgImage.GetNumberOfScalarComponents(): useFg = True fgxArray = vtk.vtkFloatArray() self.refreshArray(fgxArray, nComponents, '') fgyArray = vtk.vtkFloatArray() self.refreshArray(fgyArray, nComponents, '2nd multivolume') # will crash if there is no name fgChartTable.AddColumn(fgxArray) fgChartTable.AddColumn(fgyArray) fgChartTable.SetNumberOfRows(nComponents) # get the vector of values at IJK for c in range(nComponents): val = bgImage.GetScalarComponentAsDouble(bgijk[0],bgijk[1],bgijk[2],c) if math.isnan(val): val = 0 self.__chartTable.SetValue(c, 0, self.__mvLabels[c]) self.__chartTable.SetValue(c, 1, val) if useFg: fgValue = fgImage.GetScalarComponentAsDouble(bgijk[0],bgijk[1],bgijk[2],c) if math.isnan(fgValue): fgValue = 0 fgChartTable.SetValue(c,0,self.__mvLabels[c]) fgChartTable.SetValue(c,1,fgValue) self.baselineAverageSignal = 0 if self.__chartMode == self.PERCENTAGE_CHANGE_MODE: self.computePercentageChangeWithRespectToBaseline(self.__bgMultiVolumeNode, self.__chartTable, bgijk) if useFg: self.computePercentageChangeWithRespectToBaseline(self.__fgMultiVolumeNode, fgChartTable, fgijk) self.clearPlots() self.setAxesTitle() bgPlot = self.chart.AddPlot(vtk.vtkChart.POINTS if useFg else vtk.vtkChart.LINE) # bgPlot.SetLabel("Primary multivolume ") self.setPlotInputTable(bgPlot, self.__chartTable) if useFg: fgPlot = self.chart.AddPlot(vtk.vtkChart.LINE) # bgPlot.SetLabel("Primary multivolume ") self.setPlotInputTable(fgPlot, fgChartTable)
def setup(self): self.parent.connect('mrmlSceneChanged(vtkMRMLScene*)', self.onVCMRMLSceneChanged) w = qt.QWidget() layout = qt.QGridLayout() w.setLayout(layout) self.layout.addWidget(w) w.show() self.layout = layout # create frames self.inputFrame = ctk.ctkCollapsibleButton() self.inputFrame.text = "Input" self.inputFrame.collapsed = 0 inputFrameLayout = qt.QFormLayout(self.inputFrame) self.layout.addWidget(self.inputFrame) self.ctrlFrame = ctk.ctkCollapsibleButton() self.ctrlFrame.text = "Frame control" self.ctrlFrame.collapsed = 0 ctrlFrameLayout = qt.QGridLayout(self.ctrlFrame) self.layout.addWidget(self.ctrlFrame) self.plotFrame = ctk.ctkCollapsibleButton() self.plotFrame.text = "Plotting" self.plotFrame.collapsed = 0 plotFrameLayout = qt.QGridLayout(self.plotFrame) self.layout.addWidget(self.plotFrame) self.plotSettingsFrame = ctk.ctkCollapsibleButton() self.plotSettingsFrame.text = "Settings" self.plotSettingsFrame.collapsed = 1 plotSettingsFrameLayout = qt.QGridLayout(self.plotSettingsFrame) plotFrameLayout.addWidget(self.plotSettingsFrame, 0, 1) label = qt.QLabel('Input multivolume') self.__mvSelector = slicer.qMRMLNodeComboBox() self.__mvSelector.nodeTypes = ['vtkMRMLMultiVolumeNode'] self.__mvSelector.setMRMLScene(slicer.mrmlScene) self.__mvSelector.connect('mrmlSceneChanged(vtkMRMLScene*)', self.onVCMRMLSceneChanged) self.__mvSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onInputChanged) self.__mvSelector.addEnabled = 0 inputFrameLayout.addRow(label, self.__mvSelector) label = qt.QLabel('Input secondary multivolume') self.fgSelector = slicer.qMRMLNodeComboBox() self.fgSelector.nodeTypes = ['vtkMRMLMultiVolumeNode'] self.fgSelector.setMRMLScene(slicer.mrmlScene) self.fgSelector.addEnabled = 0 self.fgSelector.noneEnabled = 1 self.fgSelector.toolTip = "Secondary multivolume will be used for the secondary \ plot in interactive charting. As an example, this can be used to overlay the \ curve obtained by fitting a model to the data" inputFrameLayout.addRow(label, self.fgSelector) # TODO: initialize the slider based on the contents of the labels array # slider to scroll over metadata stored in the vector container being explored self.__mdSlider = ctk.ctkSliderWidget() label = qt.QLabel('Current frame number') # "play" control self.playButton = qt.QPushButton('Play') self.playButton.toolTip = 'Iterate over multivolume frames' self.playButton.checkable = True ctrlFrameLayout.addWidget(label, 0, 0) ctrlFrameLayout.addWidget(self.__mdSlider, 0, 1) ctrlFrameLayout.addWidget(self.playButton, 0, 2) self.playButton.connect('toggled(bool)', self.onPlayButtonToggled) self.__mdSlider.connect('valueChanged(double)', self.onSliderChanged) label = qt.QLabel('Current frame copy') self.__vfSelector = slicer.qMRMLNodeComboBox() self.__vfSelector.nodeTypes = ['vtkMRMLScalarVolumeNode'] self.__vfSelector.setMRMLScene(slicer.mrmlScene) self.__vfSelector.connect('mrmlSceneChanged(vtkMRMLScene*)', self.onVFMRMLSceneChanged) self.__vfSelector.addEnabled = 1 self.__vfSelector.enabled = 0 # do not show "children" of vtkMRMLScalarVolumeNode self.__vfSelector.hideChildNodeTypes = ["vtkMRMLDiffusionWeightedVolumeNode", \ "vtkMRMLDiffusionTensorVolumeNode", "vtkMRMLVectorVolumeNode"] self.extractFrame = False self.extractButton = qt.QPushButton('Enable current frame copying') self.extractButton.checkable = True self.extractButton.connect('toggled(bool)', self.onExtractFrameToggled) ctrlFrameLayout.addWidget(label, 1, 0) ctrlFrameLayout.addWidget(self.__vfSelector, 1, 1, 1, 2) ctrlFrameLayout.addWidget(self.extractButton, 2, 0, 1, 3) # initialize slice observers (from DataProbe.py) # keep list of pairs: [observee,tag] so they can be removed easily self.styleObserverTags = [] # keep a map of interactor styles to sliceWidgets so we can easily get sliceLogic self.sliceWidgetsPerStyle = {} self.refreshObservers() # label map for probing label = qt.QLabel('Probed label volume') self.__fSelector = slicer.qMRMLNodeComboBox() self.__fSelector.nodeTypes = ['vtkMRMLScalarVolumeNode'] self.__fSelector.addAttribute('vtkMRMLScalarVolumeNode', 'LabelMap', '1') self.__fSelector.toolTip = 'Label map to be probed' self.__fSelector.setMRMLScene(slicer.mrmlScene) self.__fSelector.addEnabled = 0 self.chartButton = qt.QPushButton('Chart') self.chartButton.checkable = False self.chartButton.connect('clicked()', self.onChartRequested) plotSettingsFrameLayout.addWidget(label, 0, 0) plotSettingsFrameLayout.addWidget(self.__fSelector, 0, 1) plotSettingsFrameLayout.addWidget(self.chartButton, 0, 2) self.iCharting = qt.QPushButton() self.iCharting.text = 'Enable interactive charting' self.iCharting.checkable = True plotSettingsFrameLayout.addWidget(self.iCharting, 1, 0, 1, 3) self.iCharting.setChecked(True) self.iCharting.connect('toggled(bool)', self.onInteractiveChartingChanged) groupLabel = qt.QLabel('Interactive plotting mode:') self.iChartingMode = qt.QButtonGroup() self.iChartingIntensity = qt.QRadioButton('Signal intensity') #self.iChartingIntensity.tooltip = 'Plot range adjusted dynamically to the range over the time course for the selected pixel' self.iChartingIntensityFixedAxes = qt.QRadioButton( 'Fixed range intensity') #self.iChartingIntensityFixedAxes.tooltip = "If checked, the extent of the vertical axis of the plot will be fixed to the range of the intensities in the input MultiVolume" self.iChartingPercent = qt.QRadioButton('Percent change') #self.iChartingPercent.tooltip = 'Percent change relative to the average of the first N frames (parameter set below)' self.iChartingIntensity.setChecked(1) self.groupWidget = qt.QWidget() self.groupLayout = qt.QFormLayout(self.groupWidget) self.groupLayout.addRow(groupLabel) self.groupLayout.addRow(self.iChartingIntensity) self.groupLayout.addRow(self.iChartingIntensityFixedAxes) self.groupLayout.addRow(self.iChartingPercent) self.baselineFrames = qt.QSpinBox() self.baselineFrames.minimum = 1 label = qt.QLabel('Number of frames for baseline calculation') self.groupLayout.addRow(label, self.baselineFrames) self.xLogScaleCheckBox = qt.QCheckBox() self.xLogScaleCheckBox.setChecked(0) label = qt.QLabel('Use log scale for X axis') self.groupLayout.addRow(self.xLogScaleCheckBox, label) self.xLogScaleCheckBox.connect('stateChanged(int)', self.onXLogScaleRequested) self.yLogScaleCheckBox = qt.QCheckBox() self.yLogScaleCheckBox.setChecked(0) label = qt.QLabel('Use log scale for Y axis') self.groupLayout.addRow(self.yLogScaleCheckBox, label) self.yLogScaleCheckBox.connect('stateChanged(int)', self.onYLogScaleRequested) plotSettingsFrameLayout.addWidget(self.groupWidget, 2, 0) # add chart container widget self.__chartView = ctk.ctkVTKChartView(w) plotFrameLayout.addWidget(self.__chartView, 3, 0, 1, 3) self.__chart = self.__chartView.chart() self.__chartTable = vtk.vtkTable() self.__xArray = vtk.vtkFloatArray() self.__yArray = vtk.vtkFloatArray() # will crash if there is no name self.__xArray.SetName('') self.__yArray.SetName('signal intensity') self.__chartTable.AddColumn(self.__xArray) self.__chartTable.AddColumn(self.__yArray)
def __init__(self,param): super(LesionFormWidget,self).__init__() # parameters node keeps all that is needed to render # the form and to store the scores self.param = param self.widget = qt.QWidget() self.layout = qt.QHBoxLayout(self.widget) lesionNameWidget = qt.QWidget() scoreSheetWidget = qt.QWidget() plotWidget = qt.QWidget() lnLayout = qt.QVBoxLayout(lesionNameWidget) ssLayout = qt.QVBoxLayout(scoreSheetWidget) pLayout = qt.QVBoxLayout(plotWidget) lesionName = qt.QLabel(self.param.lesionName) lnLayout.addWidget(lesionName) w = qt.QWidget() wl = qt.QHBoxLayout(w) for i in range(0,6): if i: label = qt.QLabel(str(i)) else: label = qt.QLabel('') wl.addWidget(label) ssLayout.addWidget(w) w = qt.QWidget() wl = qt.QHBoxLayout(w) t2label = qt.QLabel('T2W') wl.addWidget(t2label) t2radios = [] self.t2group = qt.QButtonGroup() for i in range(1,6): t2radios.append(qt.QRadioButton()) self.t2group.addButton(t2radios[-1],i) wl.addWidget(t2radios[-1]) self.t2group.connect('buttonClicked(int)', self.onT2scoreUpdated) ssLayout.addWidget(w) w = qt.QWidget() wl = qt.QHBoxLayout(w) dwilabel = qt.QLabel('DWI') wl.addWidget(dwilabel) dwiradios = [] self.dwigroup = qt.QButtonGroup() for i in range(1,6): dwiradios.append(qt.QRadioButton()) self.dwigroup.addButton(dwiradios[-1],i) wl.addWidget(dwiradios[-1]) self.dwigroup.connect('buttonClicked(int)', self.onDWIscoreUpdated) ssLayout.addWidget(w) w = qt.QWidget() wl = qt.QHBoxLayout(w) dcelabel = qt.QLabel('DCE') wl.addWidget(dcelabel) dceradios = [] self.dcegroup = qt.QButtonGroup() for i in range(1,6): dceradios.append(qt.QRadioButton()) self.dcegroup.addButton(dceradios[-1],i) wl.addWidget(dceradios[-1]) self.dcegroup.connect('buttonClicked(int)', self.onDCEscoreUpdated) ssLayout.addWidget(w) chartView = ctk.ctkVTKChartView(plotWidget) chart = chartView.chart() table = vtk.vtkTable() x = vtk.vtkFloatArray() y = vtk.vtkFloatArray() x.SetName('time point') y.SetName('signal intensity') table.AddColumn(x) table.AddColumn(y) table.SetNumberOfRows(100) for c in range(len(self.param.x)): table.SetValue(c,0,self.param.x[c]) table.SetValue(c,1,self.param.y[c]) plot = chart.AddPlot(0) plot.SetInput(table,0,1) chart.AddPlot(0) cw = qt.QWidget() cwl = qt.QVBoxLayout(cw) cwl.addWidget(chartView) pLayout.addWidget(cw) self.layout.addWidget(lesionNameWidget) self.layout.addWidget(scoreSheetWidget) self.layout.addWidget(plotWidget)
def chartContact(self, screwCount): # Show this chart in the plot view plotWidget = slicer.app.layoutManager().plotWidget(0) plotViewNode = plotWidget.mrmlPlotViewNode() # Retrieve/Create plot chart plotChartNode = plotViewNode.GetPlotChartNode() if not plotChartNode: plotChartNode = slicer.mrmlScene.AddNewNodeByClass( "vtkMRMLPlotChartNode", "Screw - Bone Contact chart") plotViewNode.SetPlotChartNodeID(plotChartNode.GetID()) plotChartNode.SetTitle("Screw - Bone Contact") plotChartNode.SetXAxisTitle('Screw Percentile (Head - Tip)') plotChartNode.SetYAxisTitle('Average HU Contact') # Retrieve/Create plot table firstPlotSeries = plotChartNode.GetNthPlotSeriesNode(0) plotTableNode = firstPlotSeries.GetTableNode( ) if firstPlotSeries else None if not plotTableNode: plotTableNode = slicer.mrmlScene.AddNewNodeByClass( "vtkMRMLTableNode", "Screw - Bone Contact table") # Set x, cortical bone, and cancellous bone columns plotTableNode.RemoveAllColumns() arrX = vtk.vtkFloatArray() arrX.SetName("Screw Percentile") plotTableNode.AddColumn(arrX) arrCortical = vtk.vtkFloatArray() arrCortical.SetName("Cortical Bone") plotTableNode.AddColumn(arrCortical) arrCancellous = vtk.vtkFloatArray() arrCancellous.SetName("Cancellous Bone") plotTableNode.AddColumn(arrCancellous) numPoints = 10 plotTable = plotTableNode.GetTable() plotTable.SetNumberOfRows(numPoints) for i in range(numPoints): plotTable.SetValue(i, 0, i * 10) plotTable.SetValue(i, 1, 250) plotTable.SetValue(i, 2, 130) arrays = [arrCortical, arrCancellous] for i in range(screwCount): # Create an Array Node and add some data arrScrew = vtk.vtkFloatArray() arrScrew.SetName('Screw %s' % i) arrScrew.SetNumberOfValues(numPoints) screwValues = self.screwContact[i] for j in range(numPoints): arrScrew.SetValue(j, screwValues[j]) plotTableNode.AddColumn(arrScrew) arrays.append(arrScrew) # Update/Create plot series for arrIndex, arr in enumerate(arrays): plotSeriesNode = plotChartNode.GetNthPlotSeriesNode(arrIndex) if not plotSeriesNode: plotSeriesNode = slicer.mrmlScene.AddNewNodeByClass( "vtkMRMLPlotSeriesNode") plotChartNode.AddAndObservePlotSeriesNodeID( plotSeriesNode.GetID()) plotSeriesNode.SetName("{0}".format(arr.GetName())) plotSeriesNode.SetAndObserveTableNodeID(plotTableNode.GetID()) plotSeriesNode.SetXColumnName(arrX.GetName()) plotSeriesNode.SetYColumnName(arr.GetName()) plotSeriesNode.SetPlotType( slicer.vtkMRMLPlotSeriesNode.PlotTypeScatter) if arrIndex < 2: # two constant lines plotSeriesNode.SetLineStyle( slicer.vtkMRMLPlotSeriesNode.LineStyleDash) else: plotSeriesNode.SetLineStyle( slicer.vtkMRMLPlotSeriesNode.LineStyleSolid) plotSeriesNode.SetMarkerStyle( slicer.vtkMRMLPlotSeriesNode.MarkerStyleNone) plotSeriesNode.SetUniqueColor() # Remove extra series nodes for i in range(plotChartNode.GetNumberOfPlotSeriesNodes() - len(arrays)): plotChartNode.RemoveNthPlotSeriesNodeID( plotChartNode.GetNumberOfPlotSeriesNodes() - 1)
def processEvent(self, observee, event): #if not self.iCharting.checked: # return fgImages = self.nodeImgList[0] mvImage = fgImages[0] fgNodes = self.nodeList[0] nComponents = self.numFrames # TODO: use a timer to delay calculation and compress events if event == 'LeaveEvent': # reset all the readouts # TODO: reset the label text return if not self.sliceWidgetsPerStyle.has_key(observee): return sliceWidget = self.sliceWidgetsPerStyle[observee] sliceLogic = sliceWidget.sliceLogic() interactor = observee.GetInteractor() xy = interactor.GetEventPosition() coordinates = [] # we need a 4 element point to be able to multiply further down coordinates.append(xy[0]) coordinates.append(xy[1]) coordinates.append(0) coordinates.append(1) xyToRas = sliceLogic.GetSliceNode().GetXYToRAS() rasPos = xyToRas.MultiplyPoint(coordinates) # VTK_CREATE(vtkMatrix4x4, rasToijk); rasToijk = vtk.vtkMatrix4x4() fgNodes[0].GetRASToIJKMatrix(rasToijk) ijkFloat = rasToijk.MultiplyPoint(rasPos) ijk = [] for element in ijkFloat: try: index = int(round(element)) except ValueError: index = 0 ijk.append(index) extent = mvImage[0].GetExtent() if not (ijk[0]>=extent[0] and ijk[0]<=extent[1] and \ ijk[1]>=extent[2] and ijk[1]<=extent[3] and \ ijk[2]>=extent[4] and ijk[2]<=extent[5]): return nComponents = self.numFrames # for testing # nComponents=1 if True: fgxArray = vtk.vtkFloatArray() fgxArray.SetNumberOfTuples(nComponents) fgxArray.SetNumberOfComponents(1) fgxArray.Allocate(nComponents) fgxArray.SetName('frame') fgyArray = vtk.vtkFloatArray() fgyArray.SetNumberOfTuples(nComponents) fgyArray.SetNumberOfComponents(1) fgyArray.Allocate(nComponents) fgyArray.SetName('signal intensity') # will crash if there is no name fgChartTable = vtk.vtkTable() fgChartTable.AddColumn(fgxArray) fgChartTable.AddColumn(fgyArray) fgChartTable.SetNumberOfRows(nComponents) # get the vector of values at IJK if (self.ctrlLevelSlider.maximum - self.ctrlLevelSlider.minimum) > 20: intFlag = True else: intFlag = False disVal = [] if self.ctrlFrameSlider: cInd = int(self.ctrlFrameSlider.value) else: cInd = 0 for c in range(nComponents): for img in fgImages: # for c in range(1): iLen = len(img) if c < iLen: val = img[c].GetScalarComponentAsDouble( ijk[0], ijk[1], ijk[2], 0) else: val = img[iLen - 1].GetScalarComponentAsDouble( ijk[0], ijk[1], ijk[2], 0) if intFlag: val = int(val) else: val = round(val * 100) / 100.0 # Kilian: will only show last image - change later self.__chartTable.SetValue(c, 0, self.__mvLabels[c]) self.__chartTable.SetValue(c, 1, val) if cInd == c: disVal.append(val) #if useFg: # fgValue = fgImage.GetScalarComponentAsDouble(ijk[0],ijk[1],ijk[2],0) # fgChartTable.SetValue(c,0,self.__mvLabels[c]) # fgChartTable.SetValue(c,1,fgValue) self.valueFrameValues.setText(disVal) # To disable plot uncomment # return baselineAverageSignal = 0 # if self.iChartingPercent.checked: # # check if percent plotting was requested and recalculate # nBaselines = min(self.baselineFrames.value,nComponents) # for c in range(nBaselines): # baselineAverageSignal += mvImage[0].GetScalarComponentAsDouble(ijk[0],ijk[1],ijk[2],c) # baselineAverageSignal /= nBaselines # if baselineAverageSignal != 0: # for c in range(nComponents): # intensity = mvImage[0].GetScalarComponentAsDouble(ijk[0],ijk[1],ijk[2],c) # self.__chartTable.SetValue(c,1,(intensity/baselineAverageSignal-1)*100.) self.__chart.RemovePlot(0) self.__chart.RemovePlot(0) #if self.iChartingPercent.checked and baselineAverageSignal != 0: # self.__chart.GetAxis(0).SetTitle('change relative to baseline, %') #else: self.__chart.GetAxis(0).SetTitle('signal intensity') #tag = str(self.__mvNode.GetAttribute('MultiVolume.FrameIdentifyingDICOMTagName')) #units = str(self.__mvNode.GetAttribute('MultiVolume.FrameIdentifyingDICOMTagUnits')) #xTitle = tag+', '+units self.__chart.GetAxis(1).SetTitle("Time") #if self.iChartingIntensityFixedAxes.checked == True: # self.__chart.GetAxis(0).SetBehavior(vtk.vtkAxis.FIXED) # self.__chart.GetAxis(0).SetRange(self.__mvRange[0],self.__mvRange[1]) # self.__chart.GetAxis(0).SetRange(2000,6000) # self.__chart.GetAxis(1).SetBehavior(vtk.vtkAxis.FIXED) # self.__chart.GetAxis(1).SetRange(2000,6000) #else: # self.__chart.GetAxis(0).SetBehavior(vtk.vtkAxis.AUTO) # if useFg: useFg = False if useFg: plot = self.__chart.AddPlot(vtk.vtkChart.POINTS) if vtk.VTK_MAJOR_VERSION <= 5: plot.SetInput(self.__chartTable, 0, 1) else: plot.SetInputData(self.__chartTable, 0, 1) fgplot = self.__chart.AddPlot(vtk.vtkChart.LINE) if vtk.VTK_MAJOR_VERSION <= 5: fgplot.SetInput(fgChartTable, 0, 1) else: fgplot.SetInputData(fgChartTable, 0, 1) else: plot = self.__chart.AddPlot(vtk.vtkChart.LINE) if vtk.VTK_MAJOR_VERSION <= 5: plot.SetInput(self.__chartTable, 0, 1) else: plot.SetInputData(self.__chartTable, 0, 1) if self.xLogScaleCheckBox.checkState() == 2: title = self.__chart.GetAxis(1).GetTitle() self.__chart.GetAxis(1).SetTitle('log of ' + title) if self.yLogScaleCheckBox.checkState() == 2: title = self.__chart.GetAxis(0).GetTitle() self.__chart.GetAxis(0).SetTitle('log of ' + title)
def setup( self ): self.parent.connect('mrmlSceneChanged(vtkMRMLScene*)', self.onVCMRMLSceneChanged) w = qt.QWidget() layout = qt.QGridLayout() w.setLayout(layout) self.layout.addWidget(w) w.show() self.layout = layout # create frames self.inputFrame = ctk.ctkCollapsibleButton() self.inputFrame.text = "Input" self.inputFrame.collapsed = 0 inputFrameLayout = qt.QFormLayout(self.inputFrame) self.layout.addWidget(self.inputFrame) self.ctrlFrame = ctk.ctkCollapsibleButton() self.ctrlFrame.text = "Frame control" self.ctrlFrame.collapsed = 0 ctrlFrameLayout = qt.QGridLayout(self.ctrlFrame) self.layout.addWidget(self.ctrlFrame) self.plotFrame = ctk.ctkCollapsibleButton() self.plotFrame.text = "Plotting" self.plotFrame.collapsed = 0 plotFrameLayout = qt.QGridLayout(self.plotFrame) self.layout.addWidget(self.plotFrame) label = qt.QLabel('Input multivolume') self.__mvSelector = slicer.qMRMLNodeComboBox() self.__mvSelector.nodeTypes = ['vtkMRMLMultiVolumeNode'] self.__mvSelector.setMRMLScene(slicer.mrmlScene) self.__mvSelector.connect('mrmlSceneChanged(vtkMRMLScene*)', self.onVCMRMLSceneChanged) self.__mvSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onInputChanged) self.__mvSelector.addEnabled = 0 inputFrameLayout.addRow(label, self.__mvSelector) ##self.layout.addWidget(label) ##self.layout.addWidget(self.__mvSelector) # TODO: initialize the slider based on the contents of the labels array # slider to scroll over metadata stored in the vector container being explored self.__mdSlider = ctk.ctkSliderWidget() #self.__mdSlider.setRange(0,10) #self.__mdSlider.setValue(5) label = qt.QLabel('Current frame number') ##self.layout.addWidget(label) ##self.layout.addWidget(self.__mdSlider) # "play" control self.playButton = qt.QPushButton('Play') self.playButton.toolTip = 'Iterate over multivolume frames' self.playButton.checkable = True ctrlFrameLayout.addWidget(label, 0, 0) ctrlFrameLayout.addWidget(self.__mdSlider, 0, 1) ctrlFrameLayout.addWidget(self.playButton, 0, 2) self.playButton.connect('toggled(bool)', self.onPlayButtonToggled) self.__mdSlider.connect('valueChanged(double)', self.onSliderChanged) label = qt.QLabel('Current frame copy') self.__vfSelector = slicer.qMRMLNodeComboBox() self.__vfSelector.nodeTypes = ['vtkMRMLScalarVolumeNode'] self.__vfSelector.setMRMLScene(slicer.mrmlScene) self.__vfSelector.connect('mrmlSceneChanged(vtkMRMLScene*)', self.onVFMRMLSceneChanged) self.__vfSelector.addEnabled = 1 self.__vfSelector.enabled = 0 # do not show "children" of vtkMRMLScalarVolumeNode self.__vfSelector.hideChildNodeTypes = ["vtkMRMLDiffusionWeightedVolumeNode", \ "vtkMRMLDiffusionTensorVolumeNode", "vtkMRMLVectorVolumeNode"] self.extractFrame = False self.extractButton = qt.QPushButton('Enable current frame copying') self.extractButton.checkable = True self.extractButton.connect('toggled(bool)', self.onExtractFrameToggled) ctrlFrameLayout.addWidget(label, 1, 0) ctrlFrameLayout.addWidget(self.__vfSelector,1,1,1,2) ctrlFrameLayout.addWidget(self.extractButton,2,0,1,3) # initialize slice observers (from DataProbe.py) # keep list of pairs: [observee,tag] so they can be removed easily self.styleObserverTags = [] # keep a map of interactor styles to sliceWidgets so we can easily get sliceLogic self.sliceWidgetsPerStyle = {} self.refreshObservers() # label map for probing label = qt.QLabel('Probed label volume') self.__fSelector = slicer.qMRMLNodeComboBox() self.__fSelector.nodeTypes = ['vtkMRMLScalarVolumeNode'] self.__fSelector.addAttribute('vtkMRMLScalarVolumeNode','LabelMap','1') self.__fSelector.toolTip = 'Label map to be probed' self.__fSelector.setMRMLScene(slicer.mrmlScene) self.__fSelector.addEnabled = 0 self.__fSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onLabelVolumeChanged) self.__fSelector.connect('mrmlSceneChanged(vtkMRMLScene*)', self.onLVMRMLSceneChanged) plotFrameLayout.addWidget(label,0,0,1,1) plotFrameLayout.addWidget(self.__fSelector,0,1,1,2) self.iCharting = qt.QPushButton() self.iCharting.text = 'Enable interactive charting' self.iCharting.checkable = True plotFrameLayout.addWidget(self.iCharting,1,0,1,3) self.iCharting.setChecked(True) self.iCharting.connect('toggled(bool)', self.onInteractiveChartingChanged) label = qt.QLabel("Use intensity range to fix axis extent") label.toolTip = "If checked, the extent of the vertical axis of the plot will be fixed to the range of the intensities in the input MultiVolume" self.__fixedAxesCheckbox = qt.QCheckBox() self.__fixedAxesCheckbox.toolTip = "If checked, the extent of the vertical axis of the plot will be fixed to the range of the intensities in the input MultiVolume" self.__fixedAxesCheckbox.checked = False plotFrameLayout.addWidget(label, 2, 0) plotFrameLayout.addWidget(self.__fixedAxesCheckbox, 2,1,1,2) # add chart container widget self.__chartView = ctk.ctkVTKChartView(w) plotFrameLayout.addWidget(self.__chartView,3,0,1,3) self.__chart = self.__chartView.chart() self.__chartTable = vtk.vtkTable() self.__xArray = vtk.vtkFloatArray() self.__yArray = vtk.vtkFloatArray() # will crash if there is no name self.__xArray.SetName('') self.__yArray.SetName('signal intensity') self.__chartTable.AddColumn(self.__xArray) self.__chartTable.AddColumn(self.__yArray)
def onApplyThreshold(self): min,max = self.getDistanceBound() newPoints = vtk.vtkPoints() newLines = vtk.vtkCellArray() newTensors = vtk.vtkFloatArray() newTensors.SetNumberOfComponents(9) newScalars = vtk.vtkFloatArray() points = self.inputPolyData.GetPoints() lines = self.inputPolyData.GetLines() tensors = self.inputPolyData.GetPointData().GetTensors() lines.InitTraversal() newId = 0 for length in self.distanceTable: if length<=self.thresholdMax.value and length>=self.thresholdMin.value: ids = vtk.vtkIdList() lines.GetNextCell(ids) newLine = vtk.vtkPolyLine() #print(ids.GetNumberOfIds()) newLine.GetPointIds().SetNumberOfIds(ids.GetNumberOfIds()) #print(((length-min)/(max-min))*100) for i in range(ids.GetNumberOfIds()): newPoints.InsertNextPoint(points.GetPoint(ids.GetId(i))) newLine.GetPointIds().SetId(i,newId) newScalars.InsertNextValue(((length-min)/(max-min))) newId += 1 tensorValue = [0]*9 if(tensors != None): for j in range(9): tensorValue[j] = tensors.GetComponent(ids.GetId(i),j) newTensors.InsertNextTuple(tensorValue) newLines.InsertNextCell(newLine) self.outputPolyData = vtk.vtkPolyData() self.outputPolyData.SetPoints(newPoints) self.outputPolyData.SetLines(newLines) self.outputPolyData.GetPointData().SetTensors(newTensors) newScalars.SetName("Length") self.outputPolyData.GetPointData().AddArray(newScalars) self.outputNode.SetAndObservePolyData(self.outputPolyData) chartViewNodes = slicer.mrmlScene.GetNodesByClass('vtkMRMLChartViewNode') chartViewNodes.InitTraversal() chartViewNode = chartViewNodes.GetNextItemAsObject() arrayNode = slicer.mrmlScene.AddNode(slicer.vtkMRMLDoubleArrayNode()) array = arrayNode.GetArray() array.SetNumberOfTuples(10) step = (max-min)/10 interMin = min interMax = min+step for i in range(10): numberOfFibers = 0 for length in self.distanceTable: if length<=interMax and length>=interMin and length<=self.thresholdMax.value and length>=self.thresholdMin.value: numberOfFibers += 1 array.SetComponent(i,0,(interMin+interMax)/2) array.SetComponent(i,1,numberOfFibers) array.SetComponent(i,2,0) interMin += step interMax += step chartNode = slicer.mrmlScene.AddNode(slicer.vtkMRMLChartNode()) chartNode.AddArray("Fiber Length",arrayNode.GetID()) chartViewNode.SetChartNodeID(chartNode.GetID()) chartNode.SetProperty('default', 'title', 'Length Distribution') chartNode.SetProperty('default', 'xAxisLabel', 'Length') chartNode.SetProperty('default', 'yAxisLabel', 'Distribution') chartNode.SetProperty('default', 'type', 'Bar')