Browse Source

Initial import

Andrej Studen 7 years ago
commit
c40d238590

+ 25 - 0
CMakeLists.txt

@@ -0,0 +1,25 @@
+cmake_minimum_required(VERSION 2.8.9)
+
+project(MyFirstSlicerExtension)
+
+#-----------------------------------------------------------------------------
+# Extension meta-information
+set(EXTENSION_HOMEPAGE "http://www-f9.ijs.si/~studen")
+set(EXTENSION_CATEGORY "Learning")
+set(EXTENSION_CONTRIBUTORS "AS")
+set(EXTENSION_DESCRIPTION "dummy extension")
+set(EXTENSION_ICONURL "http://www-beta1.labkey.com/wp-content/uploads/2016/03/LK-wTAG-COLOR.png")
+set(EXTENSION_SCREENSHOTURLS "http://www-beta1.labkey.com/wp-content/uploads/2016/03/LK-wTAG-COLOR.png")
+
+#-----------------------------------------------------------------------------
+# Extension dependencies
+find_package(Slicer REQUIRED)
+include(${Slicer_USE_FILE})
+
+#-----------------------------------------------------------------------------
+# Extension modules
+add_subdirectory(labkeySlicerPythonExtension)
+## NEXT_MODULE
+
+#-----------------------------------------------------------------------------
+include(${Slicer_EXTENSION_CPACK})

BIN
Labkey.png


+ 30 - 0
labkeySlicerPythonExtension/CMakeLists.txt

@@ -0,0 +1,30 @@
+#-----------------------------------------------------------------------------
+set(MODULE_NAME labkeySlicerPythonExtension)
+
+#-----------------------------------------------------------------------------
+set(MODULE_PYTHON_SCRIPTS
+  ${MODULE_NAME}.py
+  )
+
+set(MODULE_PYTHON_RESOURCES
+  Resources/Icons/${MODULE_NAME}.png
+  )
+
+#-----------------------------------------------------------------------------
+slicerMacroBuildScriptedModule(
+  NAME ${MODULE_NAME}
+  SCRIPTS ${MODULE_PYTHON_SCRIPTS}
+  RESOURCES ${MODULE_PYTHON_RESOURCES}
+  WITH_GENERIC_TESTS
+  )
+
+#-----------------------------------------------------------------------------
+if(BUILD_TESTING)
+
+  # Register the unittest subclass in the main script as a ctest.
+  # Note that the test will also be available at runtime.
+  slicer_add_python_unittest(SCRIPT ${MODULE_NAME}.py)
+
+  # Additional build-time testing
+  add_subdirectory(Testing)
+endif()

BIN
labkeySlicerPythonExtension/Resources/Icons/labkeySlicerPythonExtension.png


+ 1 - 0
labkeySlicerPythonExtension/Testing/CMakeLists.txt

@@ -0,0 +1 @@
+add_subdirectory(Python)

+ 2 - 0
labkeySlicerPythonExtension/Testing/Python/CMakeLists.txt

@@ -0,0 +1,2 @@
+
+#slicer_add_python_unittest(SCRIPT ${MODULE_NAME}ModuleTest.py)

+ 267 - 0
labkeySlicerPythonExtension/labkeySlicerPythonExtension.py

@@ -0,0 +1,267 @@
+import os
+import unittest
+from __main__ import vtk, qt, ctk, slicer
+from slicer.ScriptedLoadableModule import *
+
+#
+# LineIntensityProfile
+#
+
+class LineIntensityProfile(ScriptedLoadableModule):
+  """Uses ScriptedLoadableModule base class, available at:
+  https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
+  """
+
+  def __init__(self, parent):
+    ScriptedLoadableModule.__init__(self, parent)
+    self.parent.title = "LineIntensityProfile" # TODO make this more human readable by adding spaces
+    self.parent.categories = ["Examples"]
+    self.parent.dependencies = []
+    self.parent.contributors = ["John Doe (AnyWare Corp.)"] # replace with "Firstname Lastname (Organization)"
+    self.parent.helpText = """
+    This is an example of scripted loadable module bundled in an extension.
+    """
+    self.parent.acknowledgementText = """
+    This file was originally developed by Jean-Christophe Fillion-Robin, Kitware Inc.
+    and Steve Pieper, Isomics, Inc. and was partially funded by NIH grant 3P41RR013218-12S1.
+""" # replace with organization, grant and thanks.
+
+#
+# LineIntensityProfileWidget
+#
+
+class LineIntensityProfileWidget(ScriptedLoadableModuleWidget):
+  """Uses ScriptedLoadableModuleWidget base class, available at:
+  https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
+  """
+
+  def setup(self):
+    ScriptedLoadableModuleWidget.setup(self)
+    # Instantiate and connect widgets ...
+
+    #
+    # Parameters Area
+    #
+    parametersCollapsibleButton = ctk.ctkCollapsibleButton()
+    parametersCollapsibleButton.text = "Parameters"
+    self.layout.addWidget(parametersCollapsibleButton)
+
+    # Layout within the dummy collapsible button
+    parametersFormLayout = qt.QFormLayout(parametersCollapsibleButton)
+
+    #
+    # input volume selector
+    #
+    self.inputSelector = slicer.qMRMLNodeComboBox()
+    self.inputSelector.nodeTypes = ( ("vtkMRMLScalarVolumeNode"), "" )
+    self.inputSelector.addAttribute( "vtkMRMLScalarVolumeNode", "LabelMap", 0 )
+    self.inputSelector.selectNodeUponCreation = True
+    self.inputSelector.addEnabled = False
+    self.inputSelector.removeEnabled = False
+    self.inputSelector.noneEnabled = False
+    self.inputSelector.showHidden = False
+    self.inputSelector.showChildNodeTypes = False
+    self.inputSelector.setMRMLScene( slicer.mrmlScene )
+    self.inputSelector.setToolTip( "Pick the input to the algorithm." )
+    parametersFormLayout.addRow("Input Volume: ", self.inputSelector)
+
+    #
+    # output volume selector
+    #
+    self.outputSelector = slicer.qMRMLNodeComboBox()
+    self.outputSelector.nodeTypes = ( ("vtkMRMLScalarVolumeNode"), "" )
+    self.outputSelector.addAttribute( "vtkMRMLScalarVolumeNode", "LabelMap", 0 )
+    self.outputSelector.selectNodeUponCreation = False
+    self.outputSelector.addEnabled = True
+    self.outputSelector.removeEnabled = True
+    self.outputSelector.noneEnabled = False
+    self.outputSelector.showHidden = False
+    self.outputSelector.showChildNodeTypes = False
+    self.outputSelector.setMRMLScene( slicer.mrmlScene )
+    self.outputSelector.setToolTip( "Pick the output to the algorithm." )
+    parametersFormLayout.addRow("Output Volume: ", self.outputSelector)
+
+    #
+    # check box to trigger taking screen shots for later use in tutorials
+    #
+    self.enableScreenshotsFlagCheckBox = qt.QCheckBox()
+    self.enableScreenshotsFlagCheckBox.checked = 0
+    self.enableScreenshotsFlagCheckBox.setToolTip("If checked, take screen shots for tutorials. Use Save Data to write them to disk.")
+    parametersFormLayout.addRow("Enable Screenshots", self.enableScreenshotsFlagCheckBox)
+
+    #
+    # scale factor for screen shots
+    #
+    self.screenshotScaleFactorSliderWidget = ctk.ctkSliderWidget()
+    self.screenshotScaleFactorSliderWidget.singleStep = 1.0
+    self.screenshotScaleFactorSliderWidget.minimum = 1.0
+    self.screenshotScaleFactorSliderWidget.maximum = 50.0
+    self.screenshotScaleFactorSliderWidget.value = 1.0
+    self.screenshotScaleFactorSliderWidget.setToolTip("Set scale factor for the screen shots.")
+    parametersFormLayout.addRow("Screenshot scale factor", self.screenshotScaleFactorSliderWidget)
+
+    #
+    # Apply Button
+    #
+    self.applyButton = qt.QPushButton("Apply")
+    self.applyButton.toolTip = "Run the algorithm."
+    self.applyButton.enabled = False
+    parametersFormLayout.addRow(self.applyButton)
+
+    # connections
+    self.applyButton.connect('clicked(bool)', self.onApplyButton)
+    self.inputSelector.connect("currentNodeChanged(vtkMRMLNode*)", self.onSelect)
+    self.outputSelector.connect("currentNodeChanged(vtkMRMLNode*)", self.onSelect)
+
+    # Add vertical spacer
+    self.layout.addStretch(1)
+
+  def cleanup(self):
+    pass
+
+  def onSelect(self):
+    self.applyButton.enabled = self.inputSelector.currentNode() and self.outputSelector.currentNode()
+
+  def onApplyButton(self):
+    logic = LineIntensityProfileLogic()
+    enableScreenshotsFlag = self.enableScreenshotsFlagCheckBox.checked
+    screenshotScaleFactor = int(self.screenshotScaleFactorSliderWidget.value)
+    print("Run the algorithm")
+    logic.run(self.inputSelector.currentNode(), self.outputSelector.currentNode(), enableScreenshotsFlag,screenshotScaleFactor)
+
+
+#
+# LineIntensityProfileLogic
+#
+
+class LineIntensityProfileLogic(ScriptedLoadableModuleLogic):
+  """This class should implement all the actual
+  computation done by your module.  The interface
+  should be such that other python code can import
+  this class and make use of the functionality without
+  requiring an instance of the Widget.
+  Uses ScriptedLoadableModuleLogic base class, available at:
+  https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
+  """
+
+  def hasImageData(self,volumeNode):
+    """This is a dummy logic method that
+    returns true if the passed in volume
+    node has valid image data
+    """
+    if not volumeNode:
+      print('no volume node')
+      return False
+    if volumeNode.GetImageData() == None:
+      print('no image data')
+      return False
+    return True
+
+  def takeScreenshot(self,name,description,type=-1):
+    # show the message even if not taking a screen shot
+    self.delayDisplay(description)
+
+    if self.enableScreenshots == 0:
+      return
+
+    lm = slicer.app.layoutManager()
+    # switch on the type to get the requested window
+    widget = 0
+    if type == slicer.qMRMLScreenShotDialog.FullLayout:
+      # full layout
+      widget = lm.viewport()
+    elif type == slicer.qMRMLScreenShotDialog.ThreeD:
+      # just the 3D window
+      widget = lm.threeDWidget(0).threeDView()
+    elif type == slicer.qMRMLScreenShotDialog.Red:
+      # red slice window
+      widget = lm.sliceWidget("Red")
+    elif type == slicer.qMRMLScreenShotDialog.Yellow:
+      # yellow slice window
+      widget = lm.sliceWidget("Yellow")
+    elif type == slicer.qMRMLScreenShotDialog.Green:
+      # green slice window
+      widget = lm.sliceWidget("Green")
+    else:
+      # default to using the full window
+      widget = slicer.util.mainWindow()
+      # reset the type so that the node is set correctly
+      type = slicer.qMRMLScreenShotDialog.FullLayout
+
+    # grab and convert to vtk image data
+    qpixMap = qt.QPixmap().grabWidget(widget)
+    qimage = qpixMap.toImage()
+    imageData = vtk.vtkImageData()
+    slicer.qMRMLUtils().qImageToVtkImageData(qimage,imageData)
+
+    annotationLogic = slicer.modules.annotations.logic()
+    annotationLogic.CreateSnapShot(name, description, type, self.screenshotScaleFactor, imageData)
+
+  def run(self,inputVolume,outputVolume,enableScreenshots=0,screenshotScaleFactor=1):
+    """
+    Run the actual algorithm
+    """
+
+    self.delayDisplay('Running the aglorithm')
+
+    self.enableScreenshots = enableScreenshots
+    self.screenshotScaleFactor = screenshotScaleFactor
+
+    self.takeScreenshot('LineIntensityProfile-Start','Start',-1)
+
+    return True
+
+
+class LineIntensityProfileTest(ScriptedLoadableModuleTest):
+  """
+  This is the test case for your scripted module.
+  Uses ScriptedLoadableModuleTest base class, available at:
+  https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
+  """
+
+  def setUp(self):
+    """ Do whatever is needed to reset the state - typically a scene clear will be enough.
+    """
+    slicer.mrmlScene.Clear(0)
+
+  def runTest(self):
+    """Run as few or as many tests as needed here.
+    """
+    self.setUp()
+    self.test_LineIntensityProfile1()
+
+  def test_LineIntensityProfile1(self):
+    """ Ideally you should have several levels of tests.  At the lowest level
+    tests sould exercise the functionality of the logic with different inputs
+    (both valid and invalid).  At higher levels your tests should emulate the
+    way the user would interact with your code and confirm that it still works
+    the way you intended.
+    One of the most important features of the tests is that it should alert other
+    developers when their changes will have an impact on the behavior of your
+    module.  For example, if a developer removes a feature that you depend on,
+    your test should break so they know that the feature is needed.
+    """
+
+    self.delayDisplay("Starting the test")
+    #
+    # first, get some data
+    #
+    import urllib
+    downloads = (
+        ('http://slicer.kitware.com/midas3/download?items=5767', 'FA.nrrd', slicer.util.loadVolume),
+        )
+
+    for url,name,loader in downloads:
+      filePath = slicer.app.temporaryPath + '/' + name
+      if not os.path.exists(filePath) or os.stat(filePath).st_size == 0:
+        print('Requesting download %s from %s...\n' % (name, url))
+        urllib.urlretrieve(url, filePath)
+      if loader:
+        print('Loading %s...\n' % (name,))
+        loader(filePath)
+    self.delayDisplay('Finished with download and loading\n')
+
+    volumeNode = slicer.util.getNode(pattern="FA")
+    logic = LineIntensityProfileLogic()
+    self.assertTrue( logic.hasImageData(volumeNode) )
+    self.delayDisplay('Test passed!')