Example #1
0
 def tempDirectory(self,key='__SlicerTestTemp__',tempDir=None,includeDateTime=False):
   """Come up with a unique directory name in the temp dir and make it and return it
   # TODO: switch to QTemporaryDir in Qt5.
   Note: this directory is not automatically cleaned up
   """
   if not tempDir:
     tempDir = qt.QDir(slicer.app.temporaryPath)
   tempDirName = key
   if includeDateTime:
     key += qt.QDateTime().currentDateTime().toString("yyyy-MM-dd_hh+mm+ss.zzz")
   fileInfo = qt.QFileInfo(qt.QDir(tempDir), tempDirName)
   dirPath = fileInfo.absoluteFilePath()
   qt.QDir().mkpath(dirPath)
   return dirPath
Example #2
0
 def promptForDatabaseDirectory(self):
     """Ask the user to pick a database directory.
 But, if the application is in testing mode, just pick
 a temp directory
 """
     commandOptions = slicer.app.commandOptions()
     if commandOptions.testingEnabled:
         databaseDirectory = slicer.app.temporaryPath + '/tempDICOMDatbase'
         qt.QDir().mkpath(databaseDirectory)
         self.onDatabaseDirectoryChanged(databaseDirectory)
     else:
         settings = qt.QSettings()
         databaseDirectory = settings.value('DatabaseDirectory')
         if databaseDirectory:
             self.onDatabaseDirectoryChanged(databaseDirectory)
         else:
             fileDialog = ctk.ctkFileDialog(slicer.util.mainWindow())
             fileDialog.setWindowModality(1)
             fileDialog.setWindowTitle("Select DICOM Database Directory")
             fileDialog.setFileMode(2)  # prompt for directory
             fileDialog.connect('fileSelected(QString)',
                                self.onDatabaseDirectoryChanged)
             label = qt.QLabel(
                 "<p><p>The Slicer DICOM module stores a local database with an index to all datasets that are <br>pushed to slicer, retrieved from remote dicom servers, or imported.<p>Please select a location for this database where you can store the amounts of data you require.<p>Be sure you have write access to the selected directory.",
                 fileDialog)
             fileDialog.setBottomWidget(label)
             fileDialog.exec_()
Example #3
0
 def promptForDatabaseDirectory(self):
     """Ask the user to pick a database directory.
 But, if the application is in testing mode, just pick
 a temp directory
 """
     commandOptions = slicer.app.commandOptions()
     if commandOptions.testingEnabled:
         databaseDirectory = slicer.app.temporaryPath + '/tempDICOMDatbase'
         qt.QDir().mkpath(databaseDirectory)
         self.onDatabaseDirectoryChanged(databaseDirectory)
     else:
         settings = qt.QSettings()
         databaseDirectory = settings.value('DatabaseDirectory')
         if databaseDirectory:
             self.onDatabaseDirectoryChanged(databaseDirectory)
         else:
             # pick the user's Documents by default
             documentsLocation = qt.QDesktopServices.DocumentsLocation
             documents = qt.QDesktopServices.storageLocation(
                 documentsLocation)
             databaseDirectory = documents + "/SlicerDICOMDatabase"
             message = "DICOM Database will be stored in\n\n"
             message += databaseDirectory
             message += "\n\nUse the Local Database button in the DICOM Browser "
             message += "to pick a different location."
             qt.QMessageBox.information(slicer.util.mainWindow(), 'DICOM',
                                        message, qt.QMessageBox.Ok)
             if not os.path.exists(databaseDirectory):
                 os.mkdir(databaseDirectory)
             self.onDatabaseDirectoryChanged(databaseDirectory)
    def addModule(self, fileName, permanent):
        """
        Loads a module in the Slicer factory while Slicer is running
        """
        logging.info('Module addition process started')
        # Determine which modules in above are not already loaded
        factory = slicer.app.moduleManager().factoryManager()
        myModule = type('moduleType', (), {})
        myModule.dirPath = os.path.dirname(fileName)
        myModule.baseName = os.path.basename(fileName)
        myModule.key, myModule.fileExtension = os.path.splitext(
            myModule.baseName)
        if factory.isLoaded(myModule.key):
            raise Exception("Abort: Module already loaded")
        if permanent:
            # Add module(s) to permanent search paths, if requested
            settings = slicer.app.revisionUserSettings()
            rawSearchPaths = list(
                self._settingsList(settings, "Modules/AdditionalPaths"))
            searchPaths = [qt.QDir(path) for path in rawSearchPaths]

            modified = False
            rawPath = myModule.dirPath
            path = qt.QDir(rawPath)
            if path not in searchPaths:
                searchPaths.append(path)
                rawSearchPaths.append(rawPath)
                modified = True

            if modified:
                settings.setValue("Modules/AdditionalPaths", rawSearchPaths)

        # Register requested module(s)
        factory.registerModule(qt.QFileInfo(fileName))
        if not factory.isRegistered(myModule.key):
            raise Exception("Abort: Failed to register module %s",
                            myModule.key)

        # Instantiate and load requested module(s)
        if not factory.loadModules([myModule.key]):
            raise Exception(
                "Abort: The module factory manager reported an error. \
                     One or more of the requested module(s) and/or \
                     dependencies thereof may not have been loaded.")
        logging.info('Module addition process completed')
        return True
Example #5
0
  def export(self,exportables):
    for exportable in exportables:
      # Get node to export
      node = slicer.mrmlScene.GetNodeByID(exportable.nodeID)
      if node.GetAssociatedNode() == None or not node.GetAssociatedNode().IsA('vtkMRMLScalarVolumeNode'):
        error = "Series '" + node.GetNameWithoutPostfix() + "' cannot be exported!"
        print(error)
        return error

      # Get output directory and create a subdirectory. This is necessary
      # to avoid overwriting the files in case of multiple exportables, as
      # naming of the DICOM files is static
      directoryDir = qt.QDir(exportable.directory)
      directoryDir.mkdir(exportable.nodeID)
      directoryDir.cd(exportable.nodeID)
      directory = directoryDir.absolutePath()
      print("Export scalar volume '" + node.GetAssociatedNode().GetName() + "' to directory " + directory)

      # Get study and patient nodes
      studyNode = node.GetParentNode()
      if studyNode == None:
        error = "Unable to get study node for series '" + node.GetAssociatedNode().GetName() + "'"
        print(error)
        return error
      patientNode = studyNode.GetParentNode()
      if patientNode == None:
        error = "Unable to get patient node for series '" + node.GetAssociatedNode().GetName() + "'"
        print(error)
        return error

      # Assemble tags dictionary for volume export
      from vtkSlicerSubjectHierarchyModuleMRMLPython import vtkMRMLSubjectHierarchyConstants
      tags = {}
      tags['Patient Name'] = exportable.tag(vtkMRMLSubjectHierarchyConstants.GetDICOMPatientNameTagName())
      tags['Patient ID'] = exportable.tag(vtkMRMLSubjectHierarchyConstants.GetDICOMPatientIDTagName())
      tags['Patient Comments'] = exportable.tag(vtkMRMLSubjectHierarchyConstants.GetDICOMPatientCommentsTagName())
      tags['Study ID'] = self.defaultStudyID
      tags['Study Date'] = exportable.tag(vtkMRMLSubjectHierarchyConstants.GetDICOMStudyDateTagName())
      tags['Study Description'] = exportable.tag(vtkMRMLSubjectHierarchyConstants.GetDICOMStudyDescriptionTagName())
      tags['Modality'] = exportable.tag('Modality')
      tags['Manufacturer'] = exportable.tag('Manufacturer')
      tags['Model'] = exportable.tag('Model')
      tags['Series Description'] = exportable.tag('SeriesDescription')
      tags['Series Number'] = exportable.tag('SeriesNumber')

      # Validate tags
      if tags['Modality'] == "":
        error = "Empty modality for series '" + node.GetAssociatedNode().GetName() + "'"
        print(error)
        return error
      #TODO: more tag checks

      # Perform export
      exporter = DICOMLib.DICOMExportScalarVolume(tags['Study ID'], node.GetAssociatedNode(), tags, directory)
      exporter.export()

    # Success
    return ""
    def setup(self):
        # Instantiate and connect widgets ...

        #
        # Reload and Test area
        #
        reloadCollapsibleButton = ctk.ctkCollapsibleButton()
        reloadCollapsibleButton.text = "Reload && Test"
        self.layout.addWidget(reloadCollapsibleButton)
        reloadFormLayout = qt.QFormLayout(reloadCollapsibleButton)

        # reload button
        # (use this during development, but remove it when delivering
        #  your module to users)
        self.reloadButton = qt.QPushButton("Reload")
        self.reloadButton.toolTip = "Reload this module."
        self.reloadButton.name = "TCIABrowser Reload"
        reloadFormLayout.addWidget(self.reloadButton)
        self.reloadButton.connect('clicked()', self.onReload)

        # reload and test button
        # (use this during development, but remove it when delivering
        #  your module to users)
        self.reloadAndTestButton = qt.QPushButton("Reload and Test")
        self.reloadAndTestButton.toolTip = "Reload this module and then run the self tests."
        reloadFormLayout.addWidget(self.reloadAndTestButton)
        self.reloadAndTestButton.connect('clicked()', self.onReloadAndTest)

        #
        # Step 1: selection of the data directory
        #
        self.collectionSelector = qt.QComboBox()
        self.layout.addWidget(self.collectionSelector)
        self.collectionSelector.connect('currentIndexChanged(QString)',
                                        self.collectionSelected)

        self.studyTable = ItemTable(self.parent, headerName='Study Name')
        self.layout.addWidget(self.studyTable.widget)
        self.studyTable.widget.connect('cellClicked(int,int)',
                                       self.onStudyCellClicked)

        self.seriesTable = ItemTable(self.parent, headerName="Series Name")
        self.layout.addWidget(self.seriesTable.widget)

        self.loadButton = qt.QPushButton('Load series')
        self.layout.addWidget(self.loadButton)
        self.loadButton.connect('clicked()', self.onLoadButtonClicked)

        # Add vertical spacer
        self.layout.addStretch(1)

        # set up temporary directory
        self.tempDir = slicer.app.temporaryPath + '/TCIABrowser-tmp'
        print('Temporary directory location: ' + self.tempDir)
        qt.QDir().mkpath(self.tempDir)
Example #7
0
    def test_TextureModel1(self):
        """ Ideally you should have several levels of tests.  At the lowest level
    tests should 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")

        # Download
        import urllib
        url = 'https://artec3d-production.s3-eu-west-1.amazonaws.com/3Dmodels/human_eye_obj.zip'
        zipFilePath = slicer.app.temporaryPath + '/' + 'Human_Eye_obj.zip'
        extractPath = slicer.app.temporaryPath + '/' + 'Human_Eye_obj'
        if not os.path.exists(zipFilePath) or os.stat(
                zipFilePath).st_size == 0:
            logging.info('Requesting download from %s...\n' % url)
            urllib.urlretrieve(url, zipFilePath)
            self.delayDisplay('Finished with download\n')

        # Unzip
        self.delayDisplay("Unzipping to %s" % (extractPath))
        qt.QDir().mkpath(extractPath)
        applicationLogic = slicer.app.applicationLogic()
        applicationLogic.Unzip(zipFilePath, extractPath)

        # Load
        slicer.util.loadModel(extractPath + "/Human_Eye_obj.obj")
        slicer.util.loadVolume(extractPath + "/Human_Eye_obj_0.jpg")

        self.delayDisplay('Finished with download and loading')

        # Test
        modelNode = slicer.util.getNode("Human_Eye_obj")
        textureNode = slicer.util.getNode("Human_Eye_obj_0")
        logic = TextureModelLogic()
        logic.applyTexture(modelNode, textureNode)
        self.delayDisplay('Test passed!')
Example #8
0
  def populateParameters( self ):
    parameterDir = qt.QDir(PARAM_FILES_DIR)
    for path in parameterDir.entryList(parameterDir.Files):
      fileInfo = qt.QFileInfo(path)
      name = fileInfo.baseName().replace("_", " ")
      self.get('ParameterFileComboBox').addItem(name, fileInfo.absolutePath() + '/' + path)

    # Add load from file
    self.get('ParameterFileComboBox').insertSeparator(
      self.get('ParameterFileComboBox').count)
    self.get('ParameterFileComboBox').addItem('Load from file...', None)

    comboBox = self.get('LayoutComboBox')
    comboBox.addItem('Quad View', slicer.vtkMRMLLayoutNode.SlicerLayoutFourUpView)
    comboBox.addItem('Red Slice', slicer.vtkMRMLLayoutNode.SlicerLayoutOneUpRedSliceView)
    comboBox.addItem('Yellow Slice', slicer.vtkMRMLLayoutNode.SlicerLayoutOneUpYellowSliceView)
    comboBox.addItem('Green Slice', slicer.vtkMRMLLayoutNode.SlicerLayoutOneUpGreenSliceView)
    comboBox.addItem('3D View', slicer.vtkMRMLLayoutNode.SlicerLayoutOneUp3DView)
    comboBox.addItem('MIP', slicer.vtkMRMLLayoutNode.SlicerLayoutOneUpRedSliceView)
Example #9
0
    def test_TextureModel1(self):
        """ Ideally you should have several levels of tests.  At the lowest level
    tests should 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")

        # Download
        import urllib
        url = 'https://github.com/Slicer/SlicerTestingData/releases/download/SHA256/752ce9afe8b708fcd4f8448612170f8e730670d845f65177860edc0e08004ecf'
        zipFilePath = slicer.app.temporaryPath + '/' + 'FemurHeadSurfaceScan.zip'
        extractPath = slicer.app.temporaryPath + '/' + 'FemurHeadSurfaceScan'
        if not os.path.exists(zipFilePath) or os.stat(
                zipFilePath).st_size == 0:
            logging.info('Requesting download from %s...\n' % url)
            urllib.urlretrieve(url, zipFilePath)
            self.delayDisplay('Finished with download\n')

        # Unzip
        self.delayDisplay("Unzipping to %s" % (extractPath))
        qt.QDir().mkpath(extractPath)
        applicationLogic = slicer.app.applicationLogic()
        applicationLogic.Unzip(zipFilePath, extractPath)

        # Load
        slicer.util.loadModel(extractPath + "/head_obj.obj")
        slicer.util.loadVolume(extractPath + "/head_obj_0.png")

        self.delayDisplay('Finished with download and loading')

        # Test
        modelNode = slicer.util.getNode("head_obj")
        textureNode = slicer.util.getNode("head_obj_0")
        logic = TextureModelLogic()
        logic.applyTexture(modelNode, textureNode)
        self.delayDisplay('Test passed!')
Example #10
0
  def onPresetSelected( self ):
    clickedButton = self.getSelectedButton()
    if clickedButton is None:
      self.validate()
      return

    path = clickedButton.property('Path')
    presetFiles = qt.QDir(path)

    self.Presets = {}
    self.WorkflowConfigData = {}
    for filename in presetFiles.entryList(['*'], presetFiles.Files):
      absolutePath = '%s/%s' % (presetFiles.absolutePath(), filename)
      if filename.endswith('.json'):
        self.Presets[filename[:-len('.json')]] = absolutePath
      elif filename.endswith('.dict'):
        file = open(absolutePath)
        self.WorkflowConfigData[filename[:-len('.dict')]] = eval(file.read())

    self.Workflow.updateConfiguration()
    self.validate()
Example #11
0
    def __init__(self, KEV80=False, KEV120=False, inputVolumeName=None):
        self.lowerThresholdValue = None
        self.upperThresholdValue = 5000
        self.editUtil = EditorLib.EditUtil.EditUtil()
        self.KEV80 = KEV80
        self.KEV120 = KEV120
        self.inputVolumeName = inputVolumeName
        self.calciumLabelNode = None
        self.CardiacAgatstonMeasuresLUTNode = None

        # imports custom Slicer lookup color table file
        self.CardiacAgatstonMeasuresLUTNode = slicer.util.getNode(
            pattern='CardiacAgatstonMeasuresLUT')
        if not self.CardiacAgatstonMeasuresLUTNode:
            import urllib
            downloads = ((
                'http://www.na-mic.org/Wiki/images/4/4e/CardiacAgatstonMeasures_TutorialContestSummer2014.zip',
                'CardiacAgatstonMeasures_TutorialContestSummer2014.zip'), )

            for url, name in downloads:
                filePath = os.path.join(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)

            zipFilePath = os.path.join(
                slicer.app.temporaryPath,
                'CardiacAgatstonMeasures_TutorialContestSummer2014.zip')
            extractPath = os.path.join(
                slicer.app.temporaryPath,
                'CardiacAgatstonMeasures_TutorialContestSummer2014')
            qt.QDir().mkpath(extractPath)
            applicationLogic = slicer.app.applicationLogic()
            applicationLogic.Unzip(zipFilePath, extractPath)

            lutPath = os.path.join(extractPath,
                                   'CardiacAgatstonMeasuresLUT.ctbl')
            slicer.util.loadColorTable(lutPath)
Example #12
0
  def setupUi( self ):
    self.loadUi('InitialStep.ui')

    moduleName = 'Workflow'
    scriptedModulesPath = eval('slicer.modules.%s.path' % moduleName.lower())
    scriptedModulesPath = os.path.dirname(scriptedModulesPath)
    iconsPath = os.path.join(scriptedModulesPath, 'Widgets', 'Resources', 'Icons')

    buttonGroup = qt.QButtonGroup(self.get('InitialCollapsibleGroupBox'))

    logic = slicer.modules.workflow.logic()
    resourceDir = qt.QDir(logic.GetModuleShareDirectory() + '/Resources')
    for dir in resourceDir.entryList(resourceDir.Dirs | resourceDir.NoDotAndDotDot):
      pushButton = qt.QPushButton(self.get('InitialCollapsibleGroupBox'))
      buttonGroup.addButton(pushButton)
      pushButton.text = dir.replace('_', ' ')
      pushButton.setProperty('Path', resourceDir.absolutePath() + '/' + dir)
      pushButton.checkable = True
      pushButton.connect('clicked()', self.onPresetSelected)
      pushButton.setIcon(qt.QIcon(os.path.join(iconsPath, dir)))
      pushButton.setIconSize(qt.QSize(75, 75))

      self.PresetButtons.append(pushButton)
      self.get('InitialCollapsibleGroupBox').layout().addWidget(pushButton)
Example #13
0
    def section_LoadDicomData(self):
        try:
            # Download and unzip test CT DICOM data
            import urllib
            downloads = ((
                'http://slicer.kitware.com/midas3/download/item/137843/TestDicomCT.zip',
                self.dicomZipFilePath), )

            downloaded = 0
            for url, filePath in downloads:
                if not os.path.exists(filePath) or os.stat(
                        filePath).st_size == 0:
                    if downloaded == 0:
                        self.delayDisplay(
                            'Downloading input data to folder\n' +
                            self.dicomZipFilePath +
                            '.\n\n  It may take a few minutes...',
                            self.delayMs)
                    print('Requesting download from %s...' % (url))
                    urllib.urlretrieve(url, filePath)
                    downloaded += 1
                else:
                    self.delayDisplay(
                        'Input data has been found in folder ' +
                        self.dicomZipFilePath, self.delayMs)
            if downloaded > 0:
                self.delayDisplay('Downloading input data finished',
                                  self.delayMs)

            numOfFilesInDicomDataDir = len([
                name for name in os.listdir(self.dicomDataDir)
                if os.path.isfile(self.dicomDataDir + '/' + name)
            ])
            if (numOfFilesInDicomDataDir !=
                    self.expectedNumOfFilesInDicomDataDir):
                slicer.app.applicationLogic().Unzip(self.dicomZipFilePath,
                                                    self.dicomDataDir)
                self.delayDisplay("Unzipping done", self.delayMs)

            numOfFilesInDicomDataDirTest = len([
                name for name in os.listdir(self.dicomDataDir)
                if os.path.isfile(self.dicomDataDir + '/' + name)
            ])
            self.assertTrue(numOfFilesInDicomDataDirTest ==
                            self.expectedNumOfFilesInDicomDataDir)

            # Open test database and empty it
            qt.QDir().mkpath(self.dicomDatabaseDir)

            if slicer.dicomDatabase:
                self.originalDatabaseDirectory = os.path.split(
                    slicer.dicomDatabase.databaseFilename)[0]
            else:
                self.originalDatabaseDirectory = None
                settings = qt.QSettings()
                settings.setValue('DatabaseDirectory', self.dicomDatabaseDir)

            dicomWidget = slicer.modules.dicom.widgetRepresentation().self()
            dicomWidget.onDatabaseDirectoryChanged(self.dicomDatabaseDir)
            self.assertTrue(slicer.dicomDatabase.isOpen)

            # Import test data in database
            indexer = ctk.ctkDICOMIndexer()
            self.assertTrue(indexer)

            indexer.addDirectory(slicer.dicomDatabase, self.dicomDataDir)

            self.assertTrue(len(slicer.dicomDatabase.patients()) == 1)
            self.assertTrue(slicer.dicomDatabase.patients()[0])

            # Load test data
            numOfScalarVolumeNodesBeforeLoad = len(
                slicer.util.getNodes('vtkMRMLScalarVolumeNode*'))
            numOfSubjectHierarchyNodesBeforeLoad = len(
                slicer.util.getNodes('vtkMRMLSubjectHierarchyNode*'))

            patient = slicer.dicomDatabase.patients()[0]
            studies = slicer.dicomDatabase.studiesForPatient(patient)
            series = [
                slicer.dicomDatabase.seriesForStudy(study) for study in studies
            ]
            seriesUIDs = [uid for uidList in series for uid in uidList]
            dicomWidget.detailsPopup.offerLoadables(seriesUIDs,
                                                    'SeriesUIDList')
            dicomWidget.detailsPopup.loadCheckedLoadables()

            self.assertTrue(
                len(slicer.util.getNodes('vtkMRMLScalarVolumeNode*')) ==
                numOfScalarVolumeNodesBeforeLoad + 1)
            self.assertTrue(
                len(slicer.util.getNodes('vtkMRMLSubjectHierarchyNode*')) ==
                numOfSubjectHierarchyNodesBeforeLoad + 3)

        except Exception, e:
            import traceback
            traceback.print_exc()
            self.delayDisplay('Test caused exception!\n' + str(e),
                              self.delayMs * 2)
Example #14
0
    def test_LabelToDICOMSEGConverterRoundTrip(self):
        print("CTEST_FULL_OUTPUT")

        dir(slicer.modules)
        """ Load the data using DICOM module
    """

        import os
        self.delayDisplay("Starting the DICOM test")
        #
        # first, get the data - a zip file of dicom data
        #
        import urllib
        downloads = (('http://slicer.kitware.com/midas3/download?items=10881',
                      'JANCT-CT.zip'), )

        self.delayDisplay("Downloading")
        for url, name in downloads:
            filePath = slicer.app.temporaryPath + '/' + name
            if not os.path.exists(filePath) or os.stat(filePath).st_size == 0:
                self.delayDisplay('Requesting download %s from %s...\n' %
                                  (name, url))
                urllib.urlretrieve(url, filePath)
        self.delayDisplay('Finished with download\n')

        reportingTempDir = slicer.app.temporaryPath + '/LabelToDICOMSEGConverter'
        qt.QDir().mkpath(reportingTempDir)
        dicomFilesDirectory = reportingTempDir + '/dicomFiles'
        self.cleanupDir(dicomFilesDirectory)
        qt.QDir().mkpath(dicomFilesDirectory)
        slicer.app.applicationLogic().Unzip(filePath, dicomFilesDirectory)

        try:
            self.delayDisplay("Switching to temp database directory")
            tempDatabaseDirectory = reportingTempDir + '/tempDICOMDatbase'
            qt.QDir().mkpath(tempDatabaseDirectory)
            self.cleanupDir(tempDatabaseDirectory)
            if slicer.dicomDatabase:
                self.originalDatabaseDirectory = os.path.split(
                    slicer.dicomDatabase.databaseFilename)[0]
            else:
                self.originalDatabaseDirectory = None
                settings = qt.QSettings()
                settings.setValue('DatabaseDirectory', tempDatabaseDirectory)
            dicomWidget = slicer.modules.dicom.widgetRepresentation().self()
            dicomWidget.onDatabaseDirectoryChanged(tempDatabaseDirectory)

            self.delayDisplay('Importing DICOM')
            mainWindow = slicer.util.mainWindow()
            mainWindow.moduleSelector().selectModule('DICOM')

            self.importDICOM(slicer.dicomDatabase, dicomFilesDirectory)

            patient = slicer.dicomDatabase.patients()[0]
            studies = slicer.dicomDatabase.studiesForPatient(patient)
            series = [
                slicer.dicomDatabase.seriesForStudy(study) for study in studies
            ]
            seriesUIDs = [uid for uidList in series for uid in uidList]
            dicomWidget.detailsPopup.offerLoadables(seriesUIDs,
                                                    'SeriesUIDList')
            dicomWidget.detailsPopup.examineForLoading()

            loadablesByPlugin = dicomWidget.detailsPopup.loadablesByPlugin

            self.delayDisplay('Loading Selection')
            dicomWidget.detailsPopup.loadCheckedLoadables()

            # initialize the module with the report and volume

            volumes = slicer.util.getNodes('vtkMRMLScalarVolumeNode*')
            self.assertTrue(len(volumes) == 1)

            (name, volume) = volumes.items()[0]
            self.delayDisplay('Loaded volume name %s' % volume.GetName())

            self.delayDisplay('Configure Module')
            mainWindow = slicer.util.mainWindow()
            mainWindow.moduleSelector().selectModule(
                'LabelToDICOMSEGConverter')

            module = slicer.modules.labeltodicomsegconverter.widgetRepresentation(
            ).self()

            # add label node
            volumesLogic = slicer.modules.volumes.logic()
            labelNode = volumesLogic.CreateAndAddLabelVolume(
                slicer.mrmlScene, volume, "Segmentation")
            labelNode.SetAttribute('AssociatedNodeID', volume.GetID())
            labelDisplayNode = labelNode.GetDisplayNode()
            labelDisplayNode.SetAndObserveColorNodeID(
                'vtkMRMLColorTableNodeFileGenericAnatomyColors.txt')
            image = volume.GetImageData()
            thresh = vtk.vtkImageThreshold()
            if vtk.vtkVersion().GetVTKMajorVersion() < 6:
                thresh.SetInput(image)
            else:
                thresh.SetInputData(image)
            thresh.ThresholdBetween(10, 400)
            thresh.SetInValue(10)
            thresh.SetOutValue(0)
            thresh.Update()
            labelNode.SetAndObserveImageData(thresh.GetOutput())
            module.segmentationSelector.setCurrentNode(labelNode)
            module.volumeSelector.setCurrentNode(volume)

            self.delayDisplay('Input label initialized')

            module.outputDir = reportingTempDir + '/Output'

            # Save the report

            exportDir = reportingTempDir + '/Output'
            qt.QDir().mkpath(exportDir)
            self.cleanupDir(exportDir)
            module.onLabelExport()

            self.delayDisplay('Report saved')

            self.importDICOM(slicer.dicomDatabase, exportDir)

            slicer.mrmlScene.Clear(0)

            patient = slicer.dicomDatabase.patients()[0]
            studies = slicer.dicomDatabase.studiesForPatient(patient)
            series = [
                slicer.dicomDatabase.seriesForStudy(study) for study in studies
            ]
            seriesUIDs = [uid for uidList in series for uid in uidList]
            dicomWidget.detailsPopup.offerLoadables(seriesUIDs,
                                                    'SeriesUIDList')
            dicomWidget.detailsPopup.examineForLoading()

            loadablesByPlugin = dicomWidget.detailsPopup.loadablesByPlugin

            self.delayDisplay('Wait', 10000)

            dicomWidget.detailsPopup.loadCheckedLoadables()
            volumes = slicer.util.getNodes('vtkMRMLLabelMapVolumeNode*')
            for n, v in volumes.items():
                print('Label volume found: ' + v.GetID())
            self.assertTrue(len(volumes) == 1)

            for name, volume in volumes.items():
                image = volume.GetImageData()
                previousImage = thresh.GetOutput()
                diff = vtk.vtkImageDifference()
                if vtk.vtkVersion().GetVTKMajorVersion() < 6:
                    diff.SetInput(thresh.GetOutput())
                else:
                    diff.SetInputData(thresh.GetOutput())
                diff.SetImage(image)
                diff.Update()
                if diff.GetThresholdedError() > 1:
                    self.delayDisplay('Reloaded image does not match')
                    self.assertTrue(False)

            self.delayDisplay('Test passed')

            self.delayDisplay("Restoring original database directory")
            if self.originalDatabaseDirectory:
                dicomWidget.onDatabaseDirectoryChanged(
                    self.originalDatabaseDirectory)

        except Exception, e:
            if self.originalDatabaseDirectory:
                dicomWidget.onDatabaseDirectoryChanged(
                    self.originalDatabaseDirectory)
            import traceback
            traceback.print_exc()
            self.delayDisplay('Test caused exception!\n' + str(e))
            self.assertTrue(False)
Example #15
0
    def test_CardiacAgatstonMeasures1(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 Test Part 1 - Importing heart scan")

        try:
            #
            # first, get some data
            #
            m = slicer.util.mainWindow()
            m.moduleSelector().selectModule('CardiacAgatstonMeasures')

            import urllib
            downloads = ((
                'http://www.na-mic.org/Wiki/images/4/4e/CardiacAgatstonMeasures_TutorialContestSummer2014.zip',
                'CardiacAgatstonMeasures_TutorialContestSummer2014.zip'), )

            self.delayDisplay("Downloading")

            for url, name in downloads:
                filePath = os.path.join(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)
            self.delayDisplay('Finished with download\n')

            self.delayDisplay("Unzipping to  %s" % (slicer.app.temporaryPath))
            zipFilePath = os.path.join(
                slicer.app.temporaryPath,
                'CardiacAgatstonMeasures_TutorialContestSummer2014.zip')
            extractPath = os.path.join(
                slicer.app.temporaryPath,
                'CardiacAgatstonMeasures_TutorialContestSummer2014')
            qt.QDir().mkpath(extractPath)
            self.delayDisplay("Using extract path  %s" % (extractPath))
            applicationLogic = slicer.app.applicationLogic()
            applicationLogic.Unzip(zipFilePath, extractPath)

            self.delayDisplay(
                "Loading CardiacAgatstonMeasuresTestInput.nii.gz")
            inputImagePath = os.path.join(
                extractPath, 'CardiacAgatstonMeasuresTestInput.nii.gz')
            slicer.util.loadVolume(inputImagePath)
            volumeNode = slicer.util.getNode(
                pattern="CardiacAgatstonMeasuresTestInput")
            logic = CardiacAgatstonMeasuresLogic()
            self.assertTrue(logic.hasImageData(volumeNode))
            self.delayDisplay(
                'Finished with downloading and loading CardiacAgatstonMeasuresTestInput.nii.gz'
            )

            CardiacAgatstonMeasuresLUTNode = slicer.util.getNode(
                pattern='CardiacAgatstonMeasuresLUT')
            if not CardiacAgatstonMeasuresLUTNode:
                self.delayDisplay("Loading CardiacAgatstonMeasuresLUT.ctbl")
                lutPath = os.path.join(extractPath,
                                       'CardiacAgatstonMeasuresLUT.ctbl')
                slicer.util.loadColorTable(lutPath)
                CardiacAgatstonMeasuresLUTNode = slicer.util.getNode(
                    pattern="CardiacAgatstonMeasuresLUT")
            logic = CardiacAgatstonMeasuresLogic()
            self.assertTrue(
                logic.hasCorrectLUTData(CardiacAgatstonMeasuresLUTNode))
            self.delayDisplay(
                'Finished with downloading and loading CardiacAgatstonMeasuresLUT.ctbl'
            )

            self.delayDisplay('Test Part 1 passed!\n')
        except Exception, e:
            import traceback
            traceback.print_exc()
            self.delayDisplay('Test caused exception!\n' + str(e))
Example #16
0
    def test_Part1DICOM(self,
                        enableScreenshotsFlag=0,
                        screenshotScaleFactor=1):
        """ Test the DICOM part of the test using the head atlas
    """

        self.enableScreenshots = enableScreenshotsFlag
        self.screenshotScaleFactor = screenshotScaleFactor

        import os
        self.delayDisplay("Starting the DICOM test")
        #
        # first, get the data - a zip file of dicom data
        #
        import urllib
        downloads = (('http://slicer.kitware.com/midas3/download?items=124183',
                      'dataset1_Thorax_Abdomen.zip'), )

        self.delayDisplay("Downloading")
        for url, name in downloads:
            filePath = slicer.app.temporaryPath + '/' + name
            if not os.path.exists(filePath) or os.stat(filePath).st_size == 0:
                self.delayDisplay('Requesting download %s from %s...\n' %
                                  (name, url))
                urllib.urlretrieve(url, filePath)
        self.delayDisplay('Finished with download\n')

        self.delayDisplay("Unzipping")
        dicomFilesDirectory = slicer.app.temporaryPath + '/dicomFiles'
        qt.QDir().mkpath(dicomFilesDirectory)
        slicer.app.applicationLogic().Unzip(filePath, dicomFilesDirectory)

        try:
            self.delayDisplay("Switching to temp database directory")
            tempDatabaseDirectory = slicer.app.temporaryPath + '/tempDICOMDatabase'
            qt.QDir().mkpath(tempDatabaseDirectory)
            if slicer.dicomDatabase:
                originalDatabaseDirectory = os.path.split(
                    slicer.dicomDatabase.databaseFilename)[0]
            else:
                originalDatabaseDirectory = None
                settings = qt.QSettings()
                settings.setValue('DatabaseDirectory', tempDatabaseDirectory)
            dicomWidget = slicer.modules.dicom.widgetRepresentation().self()
            dicomWidget.onDatabaseDirectoryChanged(tempDatabaseDirectory)

            self.delayDisplay('Importing DICOM')
            mainWindow = slicer.util.mainWindow()
            mainWindow.moduleSelector().selectModule('DICOM')

            indexer = ctk.ctkDICOMIndexer()
            indexer.addDirectory(slicer.dicomDatabase, dicomFilesDirectory,
                                 None)
            indexer.waitForImportFinished()

            dicomWidget.detailsPopup.open()

            # load the data by series UID
            dicomWidget.detailsPopup.offerLoadables(
                '1.3.12.2.1107.5.1.4.50025.30000005060811542834300000776',
                'Series')
            dicomWidget.detailsPopup.examineForLoading()

            self.delayDisplay('Loading Selection')
            dicomWidget.detailsPopup.loadCheckedLoadables()

            self.takeScreenshot('LoadingADICOMVolume-Loaded',
                                'Loaded DICOM Volume', -1)

            layoutManager = slicer.app.layoutManager()
            redWidget = layoutManager.sliceWidget('Red')
            self.clickAndDrag(redWidget, start=(10, 10), end=(10, 40))
            self.clickAndDrag(redWidget, start=(10, 10), end=(40, 10))

            self.takeScreenshot('LoadingADICOMVolume-WL',
                                'Changed level and window', -1)

            redWidget.sliceController().setSliceLink(True)
            redWidget.sliceController().setSliceVisible(True)
            self.takeScreenshot('LoadingADICOMVolume-LinkView',
                                'Linked and visible', -1)

            self.clickAndDrag(redWidget,
                              button='Right',
                              start=(10, 10),
                              end=(10, 40))
            self.takeScreenshot('LoadingADICOMVolume-Zoom', 'Zoom', -1)

            threeDView = layoutManager.threeDWidget(0).threeDView()
            self.clickAndDrag(threeDView)
            self.takeScreenshot('LoadingADICOMVolume-Rotate', 'Rotate', -1)

            threeDView.resetFocalPoint()
            self.takeScreenshot('LoadingADICOMVolume-Center',
                                'Center the view', -1)

            layoutManager.setLayout(slicer.vtkMRMLLayoutNode.
                                    SlicerLayoutConventionalWidescreenView)
            self.takeScreenshot('LoadingADICOMVolume-ConventionalWidescreen',
                                'Conventional Widescreen Layout', -1)

            slicer.util.mainWindow().moduleSelector().selectModule(
                'VolumeRendering')
            self.takeScreenshot('VolumeRendering-Module', 'Volume Rendering',
                                -1)

            volumeRenderingWidgetRep = slicer.modules.volumerendering.widgetRepresentation(
            )
            abdomenVolume = slicer.mrmlScene.GetFirstNodeByName(
                '6: CT_Thorax_Abdomen')
            volumeRenderingWidgetRep.setMRMLVolumeNode(abdomenVolume)
            self.takeScreenshot('VolumeRendering-SelectVolume',
                                'Select the volume 6: CT_Thorax_Abdomen', -1)

            presetsScene = slicer.modules.volumerendering.logic(
            ).GetPresetsScene()
            ctCardiac3 = presetsScene.GetFirstNodeByName('CT-Cardiac3')
            volumeRenderingWidgetRep.applyPreset(ctCardiac3)
            self.takeScreenshot('VolumeRendering-SelectPreset',
                                'Select the Preset CT-Cardiac-3')

            self.delayDisplay('Skipping: Select VTK CPU Ray Casting')

            volumeRenderingNode = slicer.mrmlScene.GetFirstNodeByName(
                'VolumeRendering')
            volumeRenderingNode.SetVisibility(1)
            self.takeScreenshot('VolumeRendering-ViewRendering',
                                'View Volume Rendering', -1)

            self.delayDisplay('Skipping Move the Shift slider')

            redWidget.sliceController().setSliceVisible(False)
            self.takeScreenshot('VolumeRendering-SlicesOff',
                                'Turn off visibility of slices in 3D', -1)

            threeDView = layoutManager.threeDWidget(0).threeDView()
            self.clickAndDrag(threeDView)
            self.takeScreenshot('VolumeRendering-RotateVolumeRendering',
                                'Rotate volume rendered image', -1)

            volumeRenderingNode.SetVisibility(0)
            self.takeScreenshot('VolumeRendering-TurnOffVolumeRendering',
                                'Turn off volume rendered image', -1)

            volumeRenderingNode.SetCroppingEnabled(1)
            annotationROI = slicer.mrmlScene.GetFirstNodeByName(
                'AnnotationROI')
            annotationROI.SetDisplayVisibility(1)
            self.takeScreenshot('VolumeRendering-DisplayROI',
                                'Enable cropping and display ROI', -1)

            redWidget.sliceController().setSliceVisible(True)
            self.takeScreenshot('VolumeRendering-SlicesOn',
                                'Turn on visibility of slices in 3D', -1)

            annotationROI.SetXYZ(-79.61, 154.16, -232.591)
            annotationROI.SetRadiusXYZ(43.4, 65.19, 70.5)
            self.takeScreenshot('VolumeRendering-SizedROI',
                                'Position the ROI over a kidney', -1)

            volumeRenderingNode.SetVisibility(1)
            self.takeScreenshot('VolumeRendering-ROIRendering',
                                'ROI volume rendered', -1)

            annotationROI.SetXYZ(15, 146, -186)
            annotationROI.SetRadiusXYZ(138, 57, 61)
            self.takeScreenshot('VolumeRendering-BothKidneys',
                                'Rendered both kidneys', -1)

            self.delayDisplay('Test passed!')
        except Exception, e:
            import traceback
            traceback.print_exc()
            self.delayDisplay('Test caused exception!\n' + str(e))
Example #17
0
    def export(self, exportables):
        for exportable in exportables:
            # Get volume node to export
            shNode = slicer.vtkMRMLSubjectHierarchyNode.GetSubjectHierarchyNode(
                slicer.mrmlScene)
            if shNode is None:
                error = "Invalid subject hierarchy"
                logging.error(error)
                return error
            volumeNode = shNode.GetItemDataNode(
                exportable.subjectHierarchyItemID)
            if volumeNode is None or not volumeNode.IsA(
                    'vtkMRMLScalarVolumeNode'):
                error = "Series '" + shNode.GetItemName(
                    exportable.subjectHierarchyItemID
                ) + "' cannot be exported  as volume sequence"
                logging.error(error)
                return error

            sequenceBrowserNode = self.getSequenceBrowserNodeForMasterOutputNode(
                volumeNode)
            if not sequenceBrowserNode:
                error = "Series '" + shNode.GetItemName(
                    exportable.subjectHierarchyItemID
                ) + "' cannot be exported as volume sequence"
                logging.error(error)
                return error

            volumeSequenceNode = sequenceBrowserNode.GetSequenceNode(
                volumeNode)
            if not volumeSequenceNode:
                error = "Series '" + shNode.GetItemName(
                    exportable.subjectHierarchyItemID
                ) + "' cannot be exported as volume sequence"
                logging.error(error)
                return error

            # Get study and patient items
            studyItemID = shNode.GetItemParent(
                exportable.subjectHierarchyItemID)
            if not studyItemID:
                error = "Unable to get study for series '" + volumeNode.GetName(
                ) + "'"
                logging.error(error)
                return error
            patientItemID = shNode.GetItemParent(studyItemID)
            if not patientItemID:
                error = "Unable to get patient for series '" + volumeNode.GetName(
                ) + "'"
                logging.error(error)
                return error

            # Assemble tags dictionary for volume export

            tags = {}
            tags['Patient Name'] = exportable.tag(
                slicer.vtkMRMLSubjectHierarchyConstants.
                GetDICOMPatientNameTagName())
            tags['Patient ID'] = exportable.tag(
                slicer.vtkMRMLSubjectHierarchyConstants.
                GetDICOMPatientIDTagName())
            tags['Patient Comments'] = exportable.tag(
                slicer.vtkMRMLSubjectHierarchyConstants.
                GetDICOMPatientCommentsTagName())
            if slicer.app.majorVersion >= 5 or (slicer.app.majorVersion == 4
                                                and
                                                slicer.app.minorVersion >= 11):
                tags['Study Instance UID'] = pydicom.uid.generate_uid()
            else:
                tags['Study Instance UID'] = dicom.UID.generate_uid()
            tags['Study ID'] = exportable.tag(
                slicer.vtkMRMLSubjectHierarchyConstants.GetDICOMStudyIDTagName(
                ))
            tags['Study Date'] = exportable.tag(
                slicer.vtkMRMLSubjectHierarchyConstants.
                GetDICOMStudyDateTagName())
            tags['Study Time'] = exportable.tag(
                slicer.vtkMRMLSubjectHierarchyConstants.
                GetDICOMStudyTimeTagName())
            tags['Study Description'] = exportable.tag(
                slicer.vtkMRMLSubjectHierarchyConstants.
                GetDICOMStudyDescriptionTagName())
            tags['Modality'] = exportable.tag('Modality')
            tags['Manufacturer'] = exportable.tag('Manufacturer')
            tags['Model'] = exportable.tag('Model')
            tags['Series Description'] = exportable.tag('SeriesDescription')
            tags['Series Number'] = exportable.tag('SeriesNumber')
            tags['Series Date'] = exportable.tag("SeriesDate")
            tags['Series Time'] = exportable.tag("SeriesTime")
            if slicer.app.majorVersion >= 5 or (slicer.app.majorVersion == 4
                                                and
                                                slicer.app.minorVersion >= 11):
                tags['Series Instance UID'] = pydicom.uid.generate_uid()
                tags[
                    'Frame of Reference Instance UID'] = pydicom.uid.generate_uid(
                    )
            else:
                tags['Series Instance UID'] = dicom.UID.generate_uid()
                tags[
                    'Frame of Reference Instance UID'] = dicom.UID.generate_uid(
                    )

            # Validate tags
            if tags['Modality'] == "":
                error = "Empty modality for series '" + volumeNode.GetName(
                ) + "'"
                logging.error(error)
                return error
            #TODO: more tag checks

            sequenceItemCount = sequenceBrowserNode.GetMasterSequenceNode(
            ).GetNumberOfDataNodes()
            originalSelectedSequenceItemNumber = sequenceBrowserNode.GetSelectedItemNumber(
            )
            masterVolumeNode = sequenceBrowserNode.GetMasterSequenceNode()

            # initialize content datetime from series datetime
            contentStartDate = exportable.tag("SeriesDate")
            contentStartTime = exportable.tag("SeriesTime")
            import datetime
            datetimeNow = datetime.datetime.now()
            if not contentStartDate:
                contentStartDate = datetimeNow.strftime("%Y%m%d")
            if not contentStartTime:
                contentStartTime = datetimeNow.strftime("%H%M%S.%f")
            contentStartDatetime = self.datetimeFromDicom(
                contentStartDate, contentStartTime)

            # Get output directory and create a subdirectory. This is necessary
            # to avoid overwriting the files in case of multiple exportables, as
            # naming of the DICOM files is static
            directoryName = 'VolumeSequence_' + str(
                exportable.subjectHierarchyItemID)
            directoryDir = qt.QDir(exportable.directory)
            directoryDir.mkdir(directoryName)
            directoryDir.cd(directoryName)
            directory = directoryDir.absolutePath()
            logging.info("Export scalar volume '" + volumeNode.GetName() +
                         "' to directory " + directory)

            for sequenceItemIndex in range(sequenceItemCount):

                # Switch to next item in the series
                sequenceBrowserNode.SetSelectedItemNumber(sequenceItemIndex)
                slicer.app.processEvents()
                # Compute content date&time
                # TODO: verify that unit in sequence node is "second" (and convert to seconds if not)
                timeOffsetSec = float(
                    masterVolumeNode.GetNthIndexValue(sequenceItemIndex)
                ) - float(masterVolumeNode.GetNthIndexValue(0))
                contentDatetime = contentStartDatetime + datetime.timedelta(
                    seconds=timeOffsetSec)
                tags['Content Date'] = contentDatetime.strftime("%Y%m%d")
                tags['Content Time'] = contentDatetime.strftime("%H%M%S.%f")
                # Perform export
                filenamePrefix = f"IMG_{sequenceItemIndex:04d}_"
                exporter = DICOMExportScalarVolume(tags['Study ID'],
                                                   volumeNode, tags, directory,
                                                   filenamePrefix)
                exporter.export()

        # Success
        return ""
Example #18
0
    def test_Part1DICOM(self):
        """ Test the DICOM part of the test using the head atlas
    """

        import os
        self.delayDisplay("Starting the DICOM test")
        #
        # first, get the data - a zip file of dicom data
        #
        import urllib
        downloads = (('http://slicer.kitware.com/midas3/download?items=18822',
                      'Dcmtk-db.zip'), )

        self.delayDisplay("Downloading")
        for url, name in downloads:
            filePath = slicer.app.temporaryPath + '/' + name
            if not os.path.exists(filePath) or os.stat(filePath).st_size == 0:
                self.delayDisplay('Requesting download %s from %s...\n' %
                                  (name, url))
                urllib.urlretrieve(url, filePath)
        self.delayDisplay('Finished with download\n')

        self.delayDisplay("Unzipping")
        dicomFilesDirectory = slicer.app.temporaryPath + '/dicomFiles'
        qt.QDir().mkpath(dicomFilesDirectory)
        slicer.app.applicationLogic().Unzip(filePath, dicomFilesDirectory)

        try:
            self.delayDisplay("Switching to temp database directory")
            tempDatabaseDirectory = slicer.app.temporaryPath + '/tempDICOMDatbase'
            qt.QDir().mkpath(tempDatabaseDirectory)
            if slicer.dicomDatabase:
                originalDatabaseDirectory = os.path.split(
                    slicer.dicomDatabase.databaseFilename)[0]
            else:
                originalDatabaseDirectory = None
                settings = qt.QSettings()
                settings.setValue('DatabaseDirectory', tempDatabaseDirectory)
            dicomWidget = slicer.modules.dicom.widgetRepresentation().self()
            dicomWidget.onDatabaseDirectoryChanged(tempDatabaseDirectory)

            self.delayDisplay('Start Local DICOM Q/R SCP')
            import subprocess
            import os
            configFilePath = dicomFilesDirectory + '/Dcmtk-db/dcmqrscp.cfg'
            processCurrentPath = dicomFilesDirectory + '/Dcmtk-db/'

            dcmqrscpExeOptions = (
                '/bin',
                '/../CTK-build/CMakeExternals/Install/bin',
                '/../DCMTK-install/bin',
                '/../DCMTK-build/bin',
            )

            dcmqrscpExePath = None
            dcmqrscpExeName = '/dcmqrscp'
            if slicer.app.os == 'win':
                dcmqrscpExeName = dcmqrscpExeName + '.exe'
            for path in dcmqrscpExeOptions:
                testPath = slicer.app.slicerHome + path + dcmqrscpExeName
                if os.path.exists(testPath):
                    dcmqrscpExePath = testPath
                    break
            if not dcmqrscpExePath:
                raise (UserWarning("Could not find dcmqrscp executable"))

            args = (dcmqrscpExePath, '-c', configFilePath)
            popen = subprocess.Popen(args,
                                     stdout=subprocess.PIPE,
                                     cwd=processCurrentPath)

            self.delayDisplay('Retrieve DICOM')
            mainWindow = slicer.util.mainWindow()
            mainWindow.moduleSelector().selectModule('DICOM')
            dicomWidget.dicomApp.suspendModel()
            dicomRetrieve = ctk.ctkDICOMRetrieve()
            dicomRetrieve.setKeepAssociationOpen(True)
            dicomRetrieve.setDatabase(slicer.dicomDatabase)
            dicomRetrieve.setCallingAETitle('SlicerAE')
            dicomRetrieve.setCalledAETitle('DCMTK')
            dicomRetrieve.setPort(12345)
            dicomRetrieve.setHost('localhost')
            dicomRetrieve.getStudy(
                '1.2.124.113932.1.170.223.162.178.20050502.160340.12640015')
            dicomWidget.dicomApp.resumeModel()
            popen.kill()
            dicomWidget.detailsPopup.open()
            # click on the first row of the tree
            index = dicomWidget.tree.indexAt(qt.QPoint(0, 0))
            dicomWidget.onTreeClicked(index)

            self.delayDisplay('Loading Selection')
            dicomWidget.detailsPopup.loadCheckedLoadables()

            self.delayDisplay('Change Level')
            layoutManager = slicer.app.layoutManager()
            redWidget = layoutManager.sliceWidget('Red')
            self.clickAndDrag(redWidget, start=(10, 10), end=(10, 40))

            self.delayDisplay('Change Window')
            self.clickAndDrag(redWidget, start=(10, 10), end=(40, 10))

            self.delayDisplay('Change Layout')
            layoutManager = slicer.app.layoutManager()
            layoutManager.setLayout(
                slicer.vtkMRMLLayoutNode.SlicerLayoutOneUpRedSliceView)

            self.delayDisplay('Zoom')
            self.clickAndDrag(redWidget,
                              button='Right',
                              start=(10, 10),
                              end=(10, 40))

            self.delayDisplay('Pan')
            self.clickAndDrag(redWidget,
                              button='Middle',
                              start=(10, 10),
                              end=(40, 40))

            self.delayDisplay('Center')
            redWidget.sliceController().fitSliceToBackground()

            self.delayDisplay('Lightbox')
            redWidget.sliceController().setLightboxTo6x6()

            self.delayDisplay('Conventional Layout')
            layoutManager.setLayout(
                slicer.vtkMRMLLayoutNode.SlicerLayoutConventionalView)

            self.delayDisplay('No Lightbox')
            redWidget.sliceController().setLightboxTo1x1()

            self.delayDisplay('Four Up Layout')
            layoutManager.setLayout(
                slicer.vtkMRMLLayoutNode.SlicerLayoutFourUpView)

            self.delayDisplay('Shift Mouse')
            self.clickAndDrag(redWidget,
                              button='None',
                              start=(100, 100),
                              end=(140, 140),
                              modifiers=['Shift'])

            self.delayDisplay('Conventional, Link, Slice Model')
            layoutManager.setLayout(
                slicer.vtkMRMLLayoutNode.SlicerLayoutConventionalView)
            redWidget.sliceController().setSliceLink(True)
            redWidget.sliceController().setSliceVisible(True)

            self.delayDisplay('Rotate')
            threeDView = layoutManager.threeDWidget(0).threeDView()
            self.clickAndDrag(threeDView)

            self.delayDisplay('Zoom')
            threeDView = layoutManager.threeDWidget(0).threeDView()
            self.clickAndDrag(threeDView, button='Right')

            self.delayDisplay('Test passed!')
        except Exception, e:
            import traceback
            traceback.print_exc()
            self.delayDisplay('Test caused exception!\n' + str(e))
Example #19
0
  def test_Part1DICOM(self):
    """ Test the DICOM part of the test using the head atlas
    """

    import os
    self.delayDisplay("Starting the DICOM test")
    #
    # first, get the data - a zip file of dicom data
    #
    import urllib
    downloads = (
        ('http://slicer.kitware.com/midas3/download?items=8610', 'dicom.zip'),
        )

    self.delayDisplay("Downloading")
    for url,name in downloads:
      filePath = slicer.app.temporaryPath + '/' + name
      if not os.path.exists(filePath) or os.stat(filePath).st_size == 0:
        self.delayDisplay('Requesting download %s from %s...\n' % (name, url))
        urllib.urlretrieve(url, filePath)
    self.delayDisplay('Finished with download\n')

    self.delayDisplay("Unzipping")
    dicomFilesDirectory = slicer.app.temporaryPath + '/dicomFiles'
    qt.QDir().mkpath(dicomFilesDirectory)
    slicer.app.applicationLogic().Unzip(filePath, dicomFilesDirectory)

    try:
      self.delayDisplay("Switching to temp database directory")
      tempDatabaseDirectory = slicer.app.temporaryPath + '/tempDICOMDatbase'
      qt.QDir().mkpath(tempDatabaseDirectory)
      if slicer.dicomDatabase:
        originalDatabaseDirectory = os.path.split(slicer.dicomDatabase.databaseFilename)[0]
      else:
        originalDatabaseDirectory = None
        settings = qt.QSettings()
        settings.setValue('DatabaseDirectory', tempDatabaseDirectory)
      dicomWidget = slicer.modules.dicom.widgetRepresentation().self()
      dicomWidget.onDatabaseDirectoryChanged(tempDatabaseDirectory)

      self.delayDisplay('Importing DICOM')
      mainWindow = slicer.util.mainWindow()
      mainWindow.moduleSelector().selectModule('DICOM')
      dicomWidget.dicomApp.suspendModel()
      indexer = ctk.ctkDICOMIndexer()
      indexer.addDirectory(slicer.dicomDatabase, dicomFilesDirectory, None)
      indexer.waitForImportFinished()
      dicomWidget.dicomApp.resumeModel()
      dicomWidget.detailsPopup.open()
      # click on the first row of the tree
      index = dicomWidget.tree.indexAt(qt.QPoint(0,0))
      dicomWidget.onTreeClicked(index)

      self.delayDisplay('Loading Selection')
      dicomWidget.detailsPopup.loadCheckedLoadables()

      self.delayDisplay('Change Level')
      layoutManager = slicer.app.layoutManager()
      redWidget = layoutManager.sliceWidget('Red')
      self.clickAndDrag(redWidget,start=(10,10),end=(10,40))

      self.delayDisplay('Change Window')
      self.clickAndDrag(redWidget,start=(10,10),end=(40,10))

      self.delayDisplay('Change Layout')
      layoutManager = slicer.app.layoutManager()
      layoutManager.setLayout(slicer.vtkMRMLLayoutNode.SlicerLayoutOneUpRedSliceView)

      self.delayDisplay('Zoom')
      self.clickAndDrag(redWidget,button='Right',start=(10,10),end=(10,40))

      self.delayDisplay('Pan')
      self.clickAndDrag(redWidget,button='Middle',start=(10,10),end=(40,40))

      self.delayDisplay('Center')
      redWidget.sliceController().fitSliceToBackground()

      self.delayDisplay('Lightbox')
      redWidget.sliceController().setLightboxTo6x6()

      self.delayDisplay('Conventional Layout')
      layoutManager.setLayout(slicer.vtkMRMLLayoutNode.SlicerLayoutConventionalView)

      self.delayDisplay('No Lightbox')
      redWidget.sliceController().setLightboxTo1x1()

      self.delayDisplay('Four Up Layout')
      layoutManager.setLayout(slicer.vtkMRMLLayoutNode.SlicerLayoutFourUpView)

      self.delayDisplay('Shift Mouse')
      self.clickAndDrag(redWidget,button='None',start=(100,100),end=(140,140),modifiers=['Shift'])

      self.delayDisplay('Conventional, Link, Slice Model')
      layoutManager.setLayout(slicer.vtkMRMLLayoutNode.SlicerLayoutConventionalView)
      redWidget.sliceController().setSliceLink(True)
      redWidget.sliceController().setSliceVisible(True);

      self.delayDisplay('Rotate')
      threeDView = layoutManager.threeDWidget(0).threeDView()
      self.clickAndDrag(threeDView)

      self.delayDisplay('Zoom')
      threeDView = layoutManager.threeDWidget(0).threeDView()
      self.clickAndDrag(threeDView,button='Right')

      self.delayDisplay('Test passed!')
    except Exception, e:
      import traceback
      traceback.print_exc()
      self.delayDisplay('Test caused exception!\n' + str(e))
Example #20
0
    def onStartStopDicomPeer(self, flag):
        if flag:
            import os
            self.startStopDicomPeerButton.setEnabled(False)
            dicomFilesDirectory = slicer.app.temporaryPath
            configFilePath = dicomFilesDirectory + '/Dcmtk-db/dcmqrscp.cfg'
            processCurrentPath = dicomFilesDirectory + '/Dcmtk-db/'

            msgBox = qt.QMessageBox()
            msgBox.setText(
                'Do you want to choose local DCMTK database folder?')
            msgBox.setStandardButtons(qt.QMessageBox.Yes | qt.QMessageBox.No)
            val = msgBox.exec_()
            if (val == qt.QMessageBox.Yes):
                print 'Yes'
                dicomFilesDirectory = qt.QFileDialog.getExistingDirectory(
                    None, 'Select DCMTK database folder')
                configFilePath = dicomFilesDirectory + '/dcmqrscp.cfg'
                processCurrentPath = dicomFilesDirectory
            else:
                downloads = (
                    ('http://slicer.kitware.com/midas3/download?items=18822',
                     'Dcmtk-db.zip'), )
                print 'Downloading'

                import urllib
                for url, name 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)
                print 'Finished with download'

                print 'Unzipping'
                qt.QDir().mkpath(dicomFilesDirectory)
                slicer.app.applicationLogic().Unzip(filePath,
                                                    dicomFilesDirectory)

            import subprocess
            dcmqrscpExeOptions = (
                '/bin',
                '/../CTK-build/CMakeExternals/Install/bin',
                '/../DCMTK-install/bin',
                '/../DCMTK-build/bin',
            )

            dcmqrscpExePath = None
            dcmqrscpExeName = '/dcmqrscp'
            if slicer.app.os == 'win':
                dcmqrscpExeName = dcmqrscpExeName + '.exe'
            for path in dcmqrscpExeOptions:
                testPath = slicer.app.slicerHome + path + dcmqrscpExeName
                if os.path.exists(testPath):
                    dcmqrscpExePath = testPath
                    break
            if not dcmqrscpExePath:
                raise (UserWarning("Could not find dcmqrscp executable"))

            args = (dcmqrscpExePath, '-c', configFilePath)
            print 'Start DICOM peer'
            self.popen = subprocess.Popen(args,
                                          stdout=subprocess.PIPE,
                                          cwd=processCurrentPath)
            self.startStopDicomPeerButton.setEnabled(True)
        else:
            print 'Stop DICOM peer'
            self.popen.kill()
Example #21
0
  def test_Part2PETCT(self):
    """ Test using the PETCT module
    """
    self.delayDisplay("Starting the test")
    #
    # first, get some data
    #
    import urllib
    downloads = (
        ('http://slicer.kitware.com/midas3/download?items=9185', 'RSNA2011_PETCT.zip', slicer.util.loadScene),
        )

    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')

    zipFilePath = slicer.app.temporaryPath + '/' + 'RSNA2011_PETCT.zip'
    extractPath = slicer.app.temporaryPath + '/' + 'RSNA2011_PETCT'
    qt.QDir().mkpath(extractPath)
    applicationLogic = slicer.app.applicationLogic()
    applicationLogic.Unzip(zipFilePath, extractPath)

    try:
      logic = RSNA2012QuantLogic()
      mainWindow = slicer.util.mainWindow()
      layoutManager = slicer.app.layoutManager()
      threeDView = layoutManager.threeDWidget(0).threeDView()
      redWidget = layoutManager.sliceWidget('Red')
      redController = redWidget.sliceController()
      greenWidget = layoutManager.sliceWidget('Green')
      greenController = greenWidget.sliceController()
      yellowWidget = layoutManager.sliceWidget('Yellow')
      yellowController = yellowWidget.sliceController()
      viewNode = threeDView.mrmlViewNode()
      cameras = slicer.util.getNodes('vtkMRMLCameraNode*')
      for cameraNode in cameras.values():
        if cameraNode.GetActiveTag() == viewNode.GetID():
          break

      self.delayDisplay('Configure View')
      threeDView.resetFocalPoint()
      self.clickAndDrag(threeDView,button='Right')
      redWidget.sliceController().setSliceVisible(True);
      yellowWidget.sliceController().setSliceVisible(True);

      self.delayDisplay('Show Volumes')
      mainWindow.moduleSelector().selectModule('Volumes')
      compositNode = redWidget.mrmlSliceCompositeNode()
      compositNode.SetForegroundOpacity(0.6)
      volumeSelector = slicer.util.findChildren(name='ActiveVolumeNodeSelector')[0]
      scalarWidget = slicer.util.findChildren(name='qSlicerScalarVolumeDisplayWidget')[0]
      colorSelector = slicer.util.findChildren(scalarWidget, name='ColorTableComboBox')[0]
      PET1 = slicer.util.getNode('PET1')
      volumeSelector.setCurrentNode(PET1)
      PETHeat = slicer.util.getNode('PET-Heat')
      colorSelector.setCurrentNode(PETHeat)

      self.delayDisplay('Scroll Slices')
      for offset in xrange(-1000,-700,20):
        redController.setSliceOffsetValue(offset)
      for offset in xrange(-20,20,2):
        greenController.setSliceOffsetValue(offset)
      for offset in xrange(-20,20,2):
        yellowController.setSliceOffsetValue(offset)

      self.delayDisplay('SUV Computation')

      slicer.util.selectModule('PETStandardUptakeValueComputation')

      parameters = {
          "PETDICOMPath": extractPath + '/' + 'PET1',
          "PETVolume": slicer.util.getNode('PET1'),
          "VOIVolume": slicer.util.getNode('PET1-label'),
          }

      suvComputation = slicer.modules.petstandarduptakevaluecomputation
      self.CLINode1 = None
      self.CLINode1 = slicer.cli.run(suvComputation, self.CLINode1, parameters, delete_temporary_files=False)
      waitCount = 0
      while self.CLINode1.GetStatusString() != 'Completed' and waitCount < 100:
        self.delayDisplay( "Running SUV Computation... %d" % waitCount )
        waitCount += 1

      self.delayDisplay("Second time point")
      parameters = {
          "PETDICOMPath": extractPath + '/' + 'PET2',
          "PETVolume": slicer.util.getNode('PET2'),
          "VOIVolume": slicer.util.getNode('PET2-label'),
          }

      suvComputation = slicer.modules.petstandarduptakevaluecomputation
      self.CLINode2 = None
      self.CLINode2 = slicer.cli.run(suvComputation, self.CLINode2, parameters, delete_temporary_files=False)
      waitCount = 0
      while self.CLINode2.GetStatusString() != 'Completed' and waitCount < 100:
        self.delayDisplay( "Running SUV Computation... %d" % waitCount )
        waitCount += 1


      premax = float(self.CLINode1.GetParameterAsString('SUVMax').split()[0].strip(','))
      postmax = float(self.CLINode2.GetParameterAsString('SUVMax').split()[0].strip(','))
      self.delayDisplay("Check the numbers: is %g 16.6 greater than %g?" %
          (premax, postmax))

      percent = 100 * (postmax - premax) / premax
      if abs(percent - 16.61) > 1:
        raise "Oh no! the calculation is off"

      self.delayDisplay("Calculated percent change is %g" % percent)


      self.delayDisplay('Test passed!')
    except Exception, e:
      import traceback
      traceback.print_exc()
      self.delayDisplay('Test caused exception!\n' + str(e))
Example #22
0
    def loadModules(self, path, depth=1):
        # Get list of modules in specified path
        modules = ModuleInfo.findModules(path, depth)

        # Determine which modules in above are not already loaded
        factory = slicer.app.moduleManager().factoryManager()
        loadedModules = factory.instantiatedModuleNames()

        candidates = [m for m in modules if m.key not in loadedModules]

        # Prompt to load additional module(s)
        if len(candidates):
            dlg = LoadModulesDialog(self.parent.window())
            dlg.setModules(candidates)

            if dlg.exec_() == qt.QDialog.Accepted:
                modulesToLoad = dlg.selectedModules

                # Add module(s) to permanent search paths, if requested
                if dlg.addToSearchPaths:
                    settings = slicer.app.revisionUserSettings()
                    rawSearchPaths = list(
                        settings.value("Modules/AdditionalPaths"))
                    searchPaths = [qt.QDir(path) for path in rawSearchPaths]
                    modified = False

                    for module in modulesToLoad:
                        rawPath = os.path.dirname(module.path)
                        path = qt.QDir(rawPath)
                        if not path in searchPaths:
                            searchPaths.append(path)
                            rawSearchPaths.append(rawPath)
                            modified = True

                    if modified:
                        settings.setValue("Modules/AdditionalPaths",
                                          rawSearchPaths)

                # Register requested module(s)
                failed = []

                for module in modulesToLoad:
                    factory.registerModule(qt.QFileInfo(module.path))
                    if not factory.isRegistered(module.key):
                        failed.append(module)

                if len(failed):
                    md = qt.QMessageBox(self.parent.window())
                    md.icon = qt.QMessageBox.Critical
                    md.standardButtons = qt.QMessageBox.Close
                    md.windowTitle = "Module loading failed"

                    if len(failed) > 1:
                        md.text = "The following modules could not be registered:"

                    else:
                        md.text = "The '%s' module could not be registered:" % failed[
                            0].key

                    failedFormat = "<ul><li>%(key)s<br/>(%(path)s)</li></ul>"
                    md.informativeText = "".join(
                        [failedFormat % m.__dict__ for m in failed])

                    md.exec_()
                    return

                # Instantiate and load requested module(s)
                if not factory.loadModules(
                    [module.key for module in modulesToLoad]):
                    md = qt.QMessageBox(self.parent.window())
                    md.icon = qt.QMessageBox.Critical
                    md.standardButtons = qt.QMessageBox.Close
                    md.windowTitle = "Error loading module(s)"
                    md.text = (
                        "The module factory manager reported an error. "
                        "One or more of the requested module(s) and/or "
                        "dependencies thereof may not have been loaded.")
                    md.exec_()
Example #23
0
    def test_Part3PETCT(self,
                        enableScreenshotsFlag=0,
                        screenshotScaleFactor=1):
        """ Test using the PETCT module
    """

        self.enableScreenshots = enableScreenshotsFlag
        self.screenshotScaleFactor = screenshotScaleFactor

        self.delayDisplay("Starting the test")

        #
        # first, get some data
        #
        import urllib
        downloads = (('http://slicer.kitware.com/midas3/download?items=124185',
                      'dataset3_PETCT.zip'), )

        self.delayDisplay("Downloading")

        for url, name 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)
        self.delayDisplay('Finished with download\n')

        self.delayDisplay("Unzipping to  %s" % (slicer.app.temporaryPath))
        zipFilePath = slicer.app.temporaryPath + '/' + 'dataset3_PETCT.zip'
        extractPath = slicer.app.temporaryPath + '/' + 'dataset3_PETCT'
        qt.QDir().mkpath(extractPath)
        self.delayDisplay("Using extract path  %s" % (extractPath))
        applicationLogic = slicer.app.applicationLogic()
        applicationLogic.Unzip(zipFilePath, extractPath)

        self.delayDisplay("Loading PET_CT_pre-treatment.mrb")
        preTreatmentPath = extractPath + '/PET_CT_pre-treatment.mrb'
        slicer.util.loadScene(preTreatmentPath)
        self.takeScreenshot('PETCT-LoadedPre', 'Loaded pre-treatement scene',
                            -1)

        try:
            logic = RSNAQuantTutorialLogic()
            mainWindow = slicer.util.mainWindow()
            layoutManager = slicer.app.layoutManager()
            threeDView = layoutManager.threeDWidget(0).threeDView()
            redWidget = layoutManager.sliceWidget('Red')
            redController = redWidget.sliceController()
            greenWidget = layoutManager.sliceWidget('Green')
            greenController = greenWidget.sliceController()
            yellowWidget = layoutManager.sliceWidget('Yellow')
            yellowController = yellowWidget.sliceController()
            viewNode = threeDView.mrmlViewNode()
            cameras = slicer.util.getNodes('vtkMRMLCameraNode*')
            for cameraNode in cameras.values():
                if cameraNode.GetActiveTag() == viewNode.GetID():
                    break

            threeDView.resetFocalPoint()
            self.clickAndDrag(threeDView, button='Right')
            redWidget.sliceController().setSliceVisible(True)
            yellowWidget.sliceController().setSliceVisible(True)
            self.takeScreenshot('PETCT-ConfigureView', 'Configure View', -1)

            mainWindow.moduleSelector().selectModule('Volumes')
            compositNode = redWidget.mrmlSliceCompositeNode()
            compositNode.SetForegroundOpacity(0.2)
            self.takeScreenshot('PETCT-ShowVolumes',
                                'Show Volumes with lesion', -1)

            compositNode.SetForegroundOpacity(0.5)
            self.takeScreenshot('PETCT-CTOpacity', 'CT1 volume opacity to 0.5',
                                -1)

            yellowWidget.sliceController().setSliceVisible(False)
            greenWidget.sliceController().setSliceVisible(True)
            self.takeScreenshot('PETCT-ShowSlices',
                                'Show axial and sagittal slices', -1)

            self.delayDisplay('SUV Computation')
            if not hasattr(slicer.modules,
                           'petstandarduptakevaluecomputation'):
                self.delayDisplay(
                    "PET SUV Computation not available, skipping the test.")
                return

            slicer.util.selectModule('PETStandardUptakeValueComputation')

            parameters = {
                "PETDICOMPath": extractPath + '/' + 'PET1',
                "PETVolume": slicer.util.getNode('PET1'),
                "VOIVolume": slicer.util.getNode('PET1-label'),
            }

            suvComputation = slicer.modules.petstandarduptakevaluecomputation
            self.CLINode1 = None
            self.CLINode1 = slicer.cli.run(suvComputation,
                                           self.CLINode1,
                                           parameters,
                                           delete_temporary_files=False)
            waitCount = 0
            while self.CLINode1.GetStatusString(
            ) != 'Completed' and waitCount < 100:
                self.delayDisplay("Running SUV Computation... %d" % waitCount)
                waitCount += 1

            # close the scene
            slicer.mrmlScene.Clear(0)

            self.delayDisplay("Loading PET_CT_post-treatment.mrb")
            postTreatmentPath = extractPath + '/PET_CT_post-treatment.mrb'
            slicer.util.loadScene(postTreatmentPath)
            self.takeScreenshot('PETCT-LoadedPost',
                                'Loaded post-treatement scene', -1)

            compositNode.SetForegroundOpacity(0.5)
            self.takeScreenshot('PETCT-CT2Opacity',
                                'CT2 volume opacity to 0.5', -1)

            redController.setSliceOffsetValue(-165.01)
            self.takeScreenshot('PETCT-LarynxUptake',
                                'Mild uptake in the larynx and pharynx', -1)

            redController.setSliceOffsetValue(-106.15)
            self.takeScreenshot('PETCT-TumorUptake',
                                'No uptake in the area of the primary tumor',
                                -1)

            self.delayDisplay('Test passed!')
        except Exception, e:
            import traceback
            traceback.print_exc()
            self.delayDisplay('Test caused exception!\n' + str(e))
  def test_ReportingAIMRoundTrip(self):
    print("CTEST_FULL_OUTPUT")
    """ Load the data using DICOM module
    """
 
    import os
    self.delayDisplay("Starting the DICOM test")
    #
    # first, get the data - a zip file of dicom data
    #
    import urllib
    downloads = (
        ('http://slicer.kitware.com/midas3/download?items=10881', 'JANCT-CT.zip'),
        )

    self.delayDisplay("Downloading")
    for url,name in downloads:
      filePath = slicer.app.temporaryPath + '/' + name
      if not os.path.exists(filePath) or os.stat(filePath).st_size == 0:
        self.delayDisplay('Requesting download %s from %s...\n' % (name, url))
        urllib.urlretrieve(url, filePath)
    self.delayDisplay('Finished with download\n')

    reportingTempDir = slicer.app.temporaryPath+'/Reporting'
    print('Temporary directory location: '+reportingTempDir)
    qt.QDir().mkpath(reportingTempDir)
    dicomFilesDirectory = reportingTempDir + '/dicomFiles'
    self.cleanupDir(dicomFilesDirectory)
    qt.QDir().mkpath(dicomFilesDirectory)
    slicer.app.applicationLogic().Unzip(filePath, dicomFilesDirectory)

    try:
      self.delayDisplay("Switching to temp database directory")
      tempDatabaseDirectory = reportingTempDir + '/tempDICOMDatbase'
      qt.QDir().mkpath(tempDatabaseDirectory)
      self.cleanupDir(tempDatabaseDirectory)
      if slicer.dicomDatabase:
        self.originalDatabaseDirectory = os.path.split(slicer.dicomDatabase.databaseFilename)[0]
      else:
        self.originalDatabaseDirectory = None
        settings = qt.QSettings()
        settings.setValue('DatabaseDirectory', tempDatabaseDirectory)
      dicomWidget = slicer.modules.dicom.widgetRepresentation().self()
      dicomWidget.onDatabaseDirectoryChanged(tempDatabaseDirectory)

      self.delayDisplay('Importing DICOM')
      mainWindow = slicer.util.mainWindow()
      mainWindow.moduleSelector().selectModule('DICOM')
      #dicomWidget.dicomApp.suspendModel()
      indexer = ctk.ctkDICOMIndexer()
      indexer.addDirectory(slicer.dicomDatabase, dicomFilesDirectory, None)
      indexer.waitForImportFinished()

      patient = slicer.dicomDatabase.patients()[0]
      studies = slicer.dicomDatabase.studiesForPatient(patient)
      series = [slicer.dicomDatabase.seriesForStudy(study) for study in studies]
      seriesUIDs = [uid for uidList in series for uid in uidList]
      dicomWidget.detailsPopup.offerLoadables(seriesUIDs, 'SeriesUIDList')
      dicomWidget.detailsPopup.examineForLoading()

      loadablesByPlugin = dicomWidget.detailsPopup.loadablesByPlugin

      self.delayDisplay('Loading Selection')
      dicomWidget.detailsPopup.loadCheckedLoadables()

      # initialize the module with the report and volume
      
      volumes = slicer.util.getNodes('vtkMRMLScalarVolumeNode*')
      self.assertTrue(len(volumes) == 1)

      (name,volume) = volumes.items()[0]
      self.delayDisplay('Loaded volume name %s' % volume.GetName())

      self.delayDisplay('Configure Module')
      mainWindow = slicer.util.mainWindow()
      mainWindow.moduleSelector().selectModule('Reporting')
  
      reporting = slicer.modules.reporting.widgetRepresentation().self()

      report = slicer.mrmlScene.CreateNodeByClass('vtkMRMLReportingReportNode')
      report.SetReferenceCount(report.GetReferenceCount()-1)
      slicer.mrmlScene.AddNode(report)
      report.SetFindingLabel(7)
  
      reporting.reportSelector.setCurrentNode(report)
      self.delayDisplay('Setting volume to %s' % volume.GetName())
      reporting.volumeSelector.setCurrentNode(volume)
      slicer.app.processEvents()

      # place some markups and add a segmentation label

      # add fiducial
      fidNode = slicer.vtkMRMLAnnotationFiducialNode()
      fidName = "AIM Round Trip Test Fiducial"
      fidNode.SetName(fidName)
      fidNode.SetSelected(1)
      fidNode.SetDisplayVisibility(1)
      fidNode.SetLocked(0)
      # TODO: ask Nicole where this is assigned in the regular workflow
      fidNode.SetAttribute('AssociatedNodeID',volume.GetID())
      print("Calling set fid coords")
      startCoords = [15.8, 70.8, -126.7]    
      fidNode.SetFiducialCoordinates(startCoords[0],startCoords[1],startCoords[2])
      print("Starting fiducial coordinates: "+str(startCoords))
      slicer.mrmlScene.AddNode(fidNode)
  
      # add ruler
      rulerNode = slicer.vtkMRMLAnnotationRulerNode()
      rulerNode.SetName('Test Ruler')
      m = vtk.vtkMatrix4x4()
      volume.GetIJKToRASMatrix(m)
      ijk0 = [0,0,1,1]
      ijk1 = [50,50,1,1]
      ras0 = m.MultiplyPoint(ijk0)
      ras1 = m.MultiplyPoint(ijk1)
      rulerNode.SetPosition1(19.386751174926758, 68.528785705566406, -127.69000244140625)
      rulerNode.SetPosition2(132.72709655761719, -34.349384307861328, -127.69000244140625)
      rulerNode.SetAttribute('AssociatedNodeID',volume.GetID())
      slicer.mrmlScene.AddNode(rulerNode)
      slicer.app.processEvents()

      # add label node
      volumesLogic = slicer.modules.volumes.logic()
      labelNode = volumesLogic.CreateAndAddLabelVolume(slicer.mrmlScene, volume, "Segmentation")
      labelDisplayNode = labelNode.GetDisplayNode()
      labelDisplayNode.SetAndObserveColorNodeID('vtkMRMLColorTableNodeFileGenericAnatomyColors.txt')
      image = volume.GetImageData()
      thresh = vtk.vtkImageThreshold()
      if vtk.vtkVersion().GetVTKMajorVersion() < 6:
        thresh.SetInput(image)
      else:
        thresh.SetInputData(image)
      thresh.ThresholdBetween(10,400)
      thresh.SetInValue(report.GetFindingLabel())
      thresh.SetOutValue(0)
      thresh.Update()
      labelNode.SetAndObserveImageData(thresh.GetOutput())
      reporting.segmentationSelector.setCurrentNode(labelNode)

      # Save the report

      exportDir = reportingTempDir+'/Output'
      qt.QDir().mkpath(exportDir)
      self.cleanupDir(exportDir)
      report.SetStorageDirectoryName(exportDir)
      reportingLogic = slicer.modules.reporting.logic()
      print("Before saving report")
      reportingLogic.SaveReportToAIM(report)

      self.delayDisplay('Report saved')
      
      slicer.mrmlScene.Clear(0)


      # parse on patient level, find segmentation object, load and make sure
      # it matches the input
      # close the scene and load the report, check consistency

      # try to load back the saved AIM
      import glob
      print glob.glob(exportDir+'/*')      
      xmlFiles = glob.glob(exportDir+'/*xml')
      print xmlFiles

      self.assertTrue(len(xmlFiles) == 1)
      reporting.importAIMFile = xmlFiles[0]
      reporting.onReportImport()

      self.delayDisplay('Report loaded from AIM! Test passed.')
      
      self.delayDisplay("Restoring original database directory")
      if self.originalDatabaseDirectory:
        dicomWidget.onDatabaseDirectoryChanged(self.originalDatabaseDirectory)

    except Exception, e:
      if self.originalDatabaseDirectory:
        dicomWidget.onDatabaseDirectoryChanged(self.originalDatabaseDirectory)
      import traceback
      traceback.print_exc()
      self.delayDisplay('Test caused exception!\n' + str(e))
      self.assertTrue(False)