Skip to content

Instantly share code, notes, and snippets.

@fepegar
Last active October 27, 2019 20:55
Show Gist options
  • Save fepegar/1126520417de996c31354d15a89af9de to your computer and use it in GitHub Desktop.
Save fepegar/1126520417de996c31354d15a89af9de to your computer and use it in GitHub Desktop.
My .slicerrc.py file
from glob import glob
from time import gmtime, strftime
from os.path import expanduser, splitext, basename, join, isdir
import qt, vtk, ctk, slicer
import numpy as np
import SimpleITK as sitk
ONE_BY_THREE_LAYOUT_ID = 501
def loadModule(modulePath):
moduleFactory = slicer.app.moduleManager().factoryManager()
modulePath = expanduser(modulePath)
moduleFactory.registerModule(qt.QFileInfo(modulePath))
stem = splitext(basename(modulePath))[0]
moduleFactory.loadModules([stem])
def loadModules(modulesDir):
pyFiles = glob(join(modulesDir, '*.py'))
for modulePath in pyFiles:
loadModule(modulePath)
def printLoaded():
# Display current time
time = strftime("%d/%m/%Y %H:%M:%S", gmtime())
print('Slicer RC file loaded [{}]'.format(time))
def addHistogramWidget():
histogramVolumeSelector = slicer.qMRMLNodeComboBox()
histogramVolumeSelector.nodeTypes = ["vtkMRMLScalarVolumeNode"]
histogramVolumeSelector.selectNodeUponCreation = True
histogramVolumeSelector.addEnabled = False
histogramVolumeSelector.removeEnabled = False
histogramVolumeSelector.renameEnabled = False
histogramVolumeSelector.noneEnabled = True
histogramVolumeSelector.showHidden = False
histogramVolumeSelector.showChildNodeTypes = True
histogramVolumeSelector.setMRMLScene(slicer.mrmlScene)
histogramVolumeSelector.currentNodeChanged.connect(histogram)
w = slicer.modules.DataProbeInstance.infoWidget
w.frame.layout().addWidget(histogramVolumeSelector)
def histogram(volumeNode):
# https://www.slicer.org/wiki/Documentation/Nightly/ScriptRepository#Create_histogram_plot_of_a_volume
if volumeNode is None:
return
# Compute histogram values
import numpy as np
histogram = np.histogram(slicer.util.arrayFromVolume(volumeNode), bins=64)
count, _ = histogram
sortIndices = np.argsort(count)
secondMaxValue = count[sortIndices[-2]]
# Save results to a new table node
tableNode=slicer.mrmlScene.AddNewNodeByClass("vtkMRMLTableNode")
slicer.util.updateTableFromArray(tableNode, histogram)
tableNode.GetTable().GetColumn(0).SetName("Voxels")
tableNode.GetTable().GetColumn(1).SetName("Intensity")
# Create plot
plotSeriesNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLPlotSeriesNode", volumeNode.GetName() + ' histogram')
plotSeriesNode.SetAndObserveTableNodeID(tableNode.GetID())
plotSeriesNode.SetXColumnName("Intensity")
plotSeriesNode.SetYColumnName("Voxels")
plotSeriesNode.SetPlotType(plotSeriesNode.PlotTypeScatterBar)
plotSeriesNode.SetColor(0, 0.6, 1.0)
# Create chart and add plot
plotChartNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLPlotChartNode")
plotChartNode.AddAndObservePlotSeriesNodeID(plotSeriesNode.GetID())
plotChartNode.SetYAxisRangeAuto(False)
plotChartNode.SetYAxisRange(0, 2 * secondMaxValue)
# Show plot in layout
slicer.modules.plots.logic().ShowChartInLayout(plotChartNode)
mipSlider = ctk.ctkSliderWidget()
def createMipSlider():
mipSlider.decimals = 0
mipSlider.minimum = 0
mipSlider.maximum = 200
mipSlider.suffix = ' mm'
mipSlider.valueChanged.connect(updateMip)
w = slicer.modules.DataProbeInstance.infoWidget
w.frame.layout().addWidget(mipSlider)
def updateMip(mipLength):
# https://www.slicer.org/wiki/Documentation/Nightly/ScriptRepository#Thick_slab_reconstruction_and_maximum.2Fminimum_intensity_volume_projections
logics = getSlicesLogics()
nodes = getSlicesNodes()
for sliceNode, sliceLogic in zip(nodes, logics):
layers = getLayers(sliceLogic)
volumeNodes = getVolumeNodes(sliceLogic)
for volumeNode, layer in zip(volumeNodes, layers):
if volumeNode is None:
continue
volumeSpacing = getVolumeSpacingAcrossSlice(sliceNode, volumeNode)
mipSlices = int(round(mipLength / volumeSpacing))
if mipSlices < 1:
mipSlices = 1
reslice = layer.GetReslice()
reslice.SetSlabModeToMax()
reslice.SetSlabNumberOfSlices(mipSlices)
reslice.SetSlabSliceSpacingFraction(1)
sliceNode.Modified()
def getVolumeSpacingAcrossSlice(sliceNode, volumeNode):
orientations = {
'Sagittal': 0,
'Coronal': 1,
'Axial': 2,
}
axis = orientations[sliceNode.GetOrientation()]
return volumeNode.GetSpacing()[axis]
def getLayers(sliceLogic):
layers = [
sliceLogic.GetBackgroundLayer(),
sliceLogic.GetForegroundLayer(),
sliceLogic.GetLabelLayer(),
]
return layers
def getVolumeNodes(sliceLogic):
return [sliceLogic.GetLayerVolumeNode(n) for n in range(3)]
def getSlicesNodes():
return slicer.util.getNodesByClass('vtkMRMLSliceNode')
def getSlicesLogics():
return [sliceWidget.sliceLogic() for sliceWidget in getSliceWidgets()]
def getSliceWidgets():
lm = slicer.app.layoutManager()
return [lm.sliceWidget(name) for name in getSlicesNames()]
def getSlicesNames():
return [sliceNode.GetName() for sliceNode in getSlicesNodes()]
def setSlicesLinkedByDefault():
defaultSliceCompositeNode = slicer.vtkMRMLSliceCompositeNode()
defaultSliceCompositeNode.SetLinkedControl(1)
slicer.mrmlScene.AddDefaultNode(defaultSliceCompositeNode)
def setSlicesLinked():
for node in slicer.util.getNodesByClass('vtkMRMLSliceCompositeNode'):
node.SetLinkedControl(1)
def createMipModels():
from itertools import permutations
colors = 'Red', 'Yellow', 'Green'
modelMips = []
for source, target in permutations(colors, 2):
modelMip = SliceModelMip(
slicer.mrmlScene.AddNewNodeByClass('vtkMRMLModelNode'),
source, target)
modelMips.append(modelMip)
for node in getSlicesNodes():
node.Modified()
return modelMips
def addOneByThreeLayout():
customLayout = (
" <layout type=\"horizontal\">"
" <item>"
" <view class=\"vtkMRMLSliceNode\" singletontag=\"Red\">"
" <property name=\"orientation\" action=\"default\">Axial</property>"
" <property name=\"viewlabel\" action=\"default\">R</property>"
" <property name=\"viewcolor\" action=\"default\">#F34A33</property>"
" </view>"
" </item>"
" <item>"
" <view class=\"vtkMRMLSliceNode\" singletontag=\"Yellow\">"
" <property name=\"orientation\" action=\"default\">Sagittal</property>"
" <property name=\"viewlabel\" action=\"default\">Y</property>"
" <property name=\"viewcolor\" action=\"default\">#EDD54C</property>"
" </view>"
" </item>"
" <item>"
" <view class=\"vtkMRMLSliceNode\" singletontag=\"Green\">"
" <property name=\"orientation\" action=\"default\">Coronal</property>"
" <property name=\"viewlabel\" action=\"default\">G</property>"
" <property name=\"viewcolor\" action=\"default\">#6EB04B</property>"
" </view>"
" </item>"
" </layout>"
)
layoutManager = slicer.app.layoutManager()
layoutNode = layoutManager.layoutLogic().GetLayoutNode()
layoutNode.AddLayoutDescription(ONE_BY_THREE_LAYOUT_ID, customLayout)
def setOneByThreeLayout():
layoutManager = slicer.app.layoutManager()
layoutManager.setLayout(ONE_BY_THREE_LAYOUT_ID)
def disableDefaultInterpolation():
defaultDisplayNode = slicer.vtkMRMLScalarVolumeDisplayNode()
defaultDisplayNode.SetInterpolate(False)
slicer.mrmlScene.AddDefaultNode(defaultDisplayNode)
def toggleInterpolation():
nodes = slicer.util.getNodesByClass('vtkMRMLScalarVolumeDisplayNode')
for node in nodes:
status = node.GetInterpolate()
node.SetInterpolate(not status)
def setupKeyboardShortcuts():
shortcuts = [
('i', toggleInterpolation),
]
for (shortcutKey, callback) in shortcuts:
shortcut = qt.QShortcut(slicer.util.mainWindow())
shortcut.setKey(qt.QKeySequence(shortcutKey))
shortcut.activated.connect(callback)
def loadGIFColorTable():
possibleEpinavDir = expanduser('~/git/EpiNav')
if isdir(possibleEpinavDir):
tablePath = join(
possibleEpinavDir,
'MITK/Modules/Core/Resources/BrainAnatomyLabelsV3_0.txt'
)
slicer.util.loadColorTable(tablePath)
def showSliceIntersections():
slicer.modules.markups.logic().SetSliceIntersectionsVisibility(True)
def loadMRI():
slicer.util.loadVolume(expanduser('~/Dropbox/MRI/t1.nii.gz'))
class SliceModelMip:
def __init__(self, modelNode, color, target, alpha=0.2):
self.modelNode = modelNode
self.color = color
self.target = target
self.alpha = alpha
self.targetSliceNode = self.getTargetSliceNode()
self.setupModelNode()
self.setupDisplayNode()
self.addObserver()
def setupModelNode(self):
self.modelNode.CreateDefaultDisplayNodes()
self.modelNode.SetAndObservePolyData(self.getPolyData())
self.modelNode.SetName('{}On{}'.format(self.color, self.target))
def setupDisplayNode(self):
self.displayNode = self.modelNode.GetDisplayNode()
self.displayNode.SetSliceIntersectionVisibility(True)
self.displayNode.SetSliceIntersectionOpacity(self.alpha)
self.displayNode.SetColor(self.getSliceModelColor())
self.displayNode.RemoveAllViewNodeIDs()
self.displayNode.AddViewNodeID('vtkMRMLSliceNode{}'.format(self.target))
def addObserver(self):
self.targetSliceNode.AddObserver(
vtk.vtkCommand.ModifiedEvent,
self.updateThickness
)
def updateThickness(self, observer, event):
length = mipSlider.value
thickness = self.mmToPixels(length)
self.displayNode.SetSliceIntersectionThickness(thickness)
def mmToPixels(self, mm):
matrix = self.targetSliceNode.GetXYToRAS()
row = 1 if self.target == 'Yellow' else 0
mmToPixelsRatio = 1 / abs(matrix.GetElement(row, 0))
pixels = mmToPixelsRatio * mm
return int(round(pixels))
def getTargetSliceNode(self):
return slicer.mrmlScene.GetNodeByID(
'vtkMRMLSliceNode{}'.format(self.target))
def getPolyData(self):
return self.getSliceModelNode().GetPolyData()
def getSliceModelNode(self):
node = slicer.util.getFirstNodeByClassByName(
'vtkMRMLModelNode', '{} Volume Slice'.format(self.color))
return node
def getSliceModelColor(self):
return self.getSliceModelNode().GetDisplayNode().GetColor()
def main():
printLoaded()
createMipSlider()
setSlicesLinkedByDefault()
addOneByThreeLayout()
addHistogramWidget()
setupKeyboardShortcuts()
loadGIFColorTable()
showSliceIntersections()
modulesDirs = (
expanduser('~/git/slicer-blockmatching'),
expanduser('~/git/episurg/slicer'),
expanduser('~/git/EpilepsySemiology/SemiologyVisualization'),
)
for modulesDir in modulesDirs:
loadModules(modulesDir)
slicer.util.setModulePanelTitleVisible(False)
slicer.util.setApplicationLogoVisible(False)
slicer.util.setModuleHelpSectionVisible(False)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment