Last active
October 27, 2019 20:55
-
-
Save fepegar/1126520417de996c31354d15a89af9de to your computer and use it in GitHub Desktop.
My .slicerrc.py file
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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