Exemple #1
0
    def __init__(self, parent, width=50, height=100):
        super(DICOMPluginSelector, self).__init__(parent)
        self.setMinimumHeight(height)
        self.setMinimumWidth(width)
        verticalBox = qt.QVBoxLayout()
        self.checkBoxByPlugin = {}

        for pluginClass in slicer.modules.dicomPlugins:
            self.checkBoxByPlugin[pluginClass] = qt.QCheckBox(pluginClass)
            verticalBox.addWidget(self.checkBoxByPlugin[pluginClass])

        # Pack vertical box with plugins into a scroll area widget
        verticalBoxWidget = qt.QWidget()
        scrollAreaBox = qt.QVBoxLayout()
        verticalBoxWidget.setLayout(verticalBox)
        scrollArea = qt.QScrollArea()
        scrollArea.setWidget(verticalBoxWidget)
        scrollAreaBox.addWidget(scrollArea)
        self.setLayout(scrollAreaBox)
        settings = qt.QSettings()

        if settings.contains('DICOM/disabledPlugins/size'):
            size = settings.beginReadArray('DICOM/disabledPlugins')
            disabledPlugins = []

            for i in range(size):
                settings.setArrayIndex(i)
                disabledPlugins.append(str(settings.allKeys()[0]))
            settings.endArray()

            for pluginClass in slicer.modules.dicomPlugins:
                if pluginClass in disabledPlugins:
                    self.checkBoxByPlugin[pluginClass].checked = False
                else:
                    # Activate plugins for the ones who are not in the disabled list
                    # and also plugins installed with extensions
                    self.checkBoxByPlugin[pluginClass].checked = True
        else:
            # All DICOM plugins would be enabled by default
            for pluginClass in slicer.modules.dicomPlugins:
                self.checkBoxByPlugin[pluginClass].checked = True
Exemple #2
0
    def __init__(self, dicomBrowser=None, parent="mainWindow"):
        VTKObservationMixin.__init__(self)
        qt.QWidget.__init__(
            self,
            slicer.util.mainWindow() if parent == "mainWindow" else parent)

        self.pluginInstances = {}
        self.fileLists = []
        self.extensionCheckPending = False

        self.settings = qt.QSettings()

        self.dicomBrowser = dicomBrowser if dicomBrowser is not None else slicer.app.createDICOMBrowserForMainDatabase(
        )

        self.browserPersistent = settingsValue('DICOM/BrowserPersistent',
                                               False,
                                               converter=toBool)
        self.advancedView = settingsValue('DICOM/advancedView',
                                          0,
                                          converter=int)
        self.horizontalTables = settingsValue('DICOM/horizontalTables',
                                              0,
                                              converter=int)

        self.setup()

        self.dicomBrowser.connect('directoryImported()',
                                  self.onDirectoryImported)
        self.dicomBrowser.connect('sendRequested(QStringList)', self.onSend)

        # Load when double-clicked on an item in the browser
        self.dicomBrowser.dicomTableManager().connect(
            'patientsDoubleClicked(QModelIndex)',
            self.patientStudySeriesDoubleClicked)
        self.dicomBrowser.dicomTableManager().connect(
            'studiesDoubleClicked(QModelIndex)',
            self.patientStudySeriesDoubleClicked)
        self.dicomBrowser.dicomTableManager().connect(
            'seriesDoubleClicked(QModelIndex)',
            self.patientStudySeriesDoubleClicked)
    def restoreDefaultValues(self):
        self.topLeftCheckBox.checked = True
        self.topLeft = 1
        self.topRightCheckBox.checked = True
        self.topRight = 1
        self.bottomLeftCheckBox.checked = True
        self.bottomLeft = 1
        self.fontSizeSpinBox.value = 14
        self.timesFontRadioButton.checked = True
        self.fontFamily = 'Times'
        self.backgroundDICOMAnnotationsPersistence = 0
        self.backgroundPersistenceCheckBox.checked = False
        self.scalarBarEnableCheckBox.checked = False
        self.scalarBarEnabled = 0
        self.rangeLabelFormat = '%G'
        self.rangeLabelFormatLineEdit.text = '%G'

        settings = qt.QSettings()
        settings.setValue('DataProbe/sliceViewAnnotations.enabled',
                          self.sliceViewAnnotationsEnabled)
        settings.setValue('DataProbe/sliceViewAnnotations.topLeft',
                          self.topLeft)
        settings.setValue('DataProbe/sliceViewAnnotations.topRight',
                          self.topRight)
        settings.setValue('DataProbe/sliceViewAnnotations.bottomLeft',
                          self.bottomLeft)
        settings.setValue('DataProbe/sliceViewAnnotations.fontFamily',
                          self.fontFamily)
        settings.setValue('DataProbe/sliceViewAnnotations.fontSize',
                          self.fontSize)
        settings.setValue(
            'DataProbe/sliceViewAnnotations.bgDICOMAnnotationsPersistence',
            self.backgroundDICOMAnnotationsPersistence)
        settings.setValue('DataProbe/sliceViewAnnotations.scalarBarEnabled',
                          self.scalarBarEnabled)
        settings.setValue(
            'DataProbe/sliceViewAnnotations.scalarBarSelectedLayer',
            self.scalarBarSelectedLayer)
        settings.setValue('DataProbe/sliceViewAnnotations.rangeLabelFormat',
                          self.rangeLabelFormat)
        self.updateSliceViewFromGUI()
Exemple #4
0
    def __init__(self, incomingDataDir, incomingPort=None):
        super(DICOMStoreSCPProcess, self).__init__()

        self.incomingDataDir = incomingDataDir
        if not os.path.exists(self.incomingDataDir):
            os.mkdir(self.incomingDataDir)

        if incomingPort:
            assert isinstance(incomingPort, int)
            self.port = str(incomingPort)
        else:
            settings = qt.QSettings()
            self.port = settings.value('StoragePort')
            if not self.port:
                settings.setValue('StoragePort', '11112')
                self.port = settings.value('StoragePort')

        self.storescpExecutable = os.path.join(
            self.exeDir, self.STORESCP_PROCESS_FILE_NAME + self.exeExtension)
        self.dcmdumpExecutable = os.path.join(self.exeDir,
                                              'dcmdump' + self.exeExtension)
Exemple #5
0
  def initializeDICOMDatabase(self):
    #  Create alias for convenience
    slicer.dicomDatabase = slicer.app.dicomDatabase()

    # Set the dicom pre-cache tags once all plugin classes have been initialized.
    # Pre-caching tags is very important for fast DICOM loading because tags that are
    # not pre-cached during DICOM import in bulk, will be cached during Examine step one-by-one
    # (which takes magnitudes more time).
    tagsToPrecache = list(slicer.dicomDatabase.tagsToPrecache)
    for pluginClass in slicer.modules.dicomPlugins:
      plugin = slicer.modules.dicomPlugins[pluginClass]()
      tagsToPrecache += list(plugin.tags.values())
    tagsToPrecache = sorted(set(tagsToPrecache))  # remove duplicates
    slicer.dicomDatabase.tagsToPrecache = tagsToPrecache

    # Try to initialize the database using the location stored in settings
    if slicer.app.commandOptions().testingEnabled:
      # For automatic tests (use a separate DICOM database for testing)
      slicer.dicomDatabaseDirectorySettingsKey = 'DatabaseDirectoryTest_'+ctk.ctkDICOMDatabase().schemaVersion()
      databaseDirectory = os.path.join(slicer.app.temporaryPath,
        'temp'+slicer.app.applicationName+'DICOMDatabase_'+ctk.ctkDICOMDatabase().schemaVersion())
    else:
      # For production
      slicer.dicomDatabaseDirectorySettingsKey = 'DatabaseDirectory_'+ctk.ctkDICOMDatabase().schemaVersion()
      settings = qt.QSettings()
      databaseDirectory = settings.value(slicer.dicomDatabaseDirectorySettingsKey)
      if not databaseDirectory:
        documentsLocation = qt.QStandardPaths.DocumentsLocation
        documents = qt.QStandardPaths.writableLocation(documentsLocation)
        databaseDirectory = os.path.join(documents, slicer.app.applicationName+"DICOMDatabase")
        settings.setValue(slicer.dicomDatabaseDirectorySettingsKey, databaseDirectory)

    # Attempt to open the database. If it fails then user will have to configure it using DICOM module.
    databaseFileName = databaseDirectory + "/ctkDICOM.sql"
    slicer.dicomDatabase.openDatabase(databaseFileName)
    if slicer.dicomDatabase.isOpen:
      # There is an existing database at the current location
      if slicer.dicomDatabase.schemaVersionLoaded() != slicer.dicomDatabase.schemaVersion():
        # Schema does not match, do not use it
        slicer.dicomDatabase.closeDatabase()
Exemple #6
0
  def __init__(self,parent, width=50,height=100):
    self.widget = qt.QWidget(parent)
    self.widget.setMinimumHeight(height)
    self.widget.setMinimumWidth(width)
    self.width = width
    self.height = height
    self.layout = qt.QVBoxLayout()
    self.widget.setLayout(self.layout)
    self.checkBoxByPlugin = {}
    settings = qt.QSettings()

    slicerPlugins = slicer.modules.dicomPlugins

    for pluginClass in slicer.modules.dicomPlugins:
      self.checkBoxByPlugin[pluginClass] = qt.QCheckBox(pluginClass)
      self.layout.addWidget(self.checkBoxByPlugin[pluginClass])

    if settings.contains('DICOM/disabledPlugins/size'):
      size = settings.beginReadArray('DICOM/disabledPlugins')
      disabledPlugins = []

      for i in xrange(size):
        settings.setArrayIndex(i)
        disabledPlugins.append(str(settings.allKeys()[0]))
      settings.endArray()

      for pluginClass in slicer.modules.dicomPlugins:
        if pluginClass in disabledPlugins:
          self.checkBoxByPlugin[pluginClass].checked = False
        else:
          # Activate plugins for the ones who are not in the disabled list
          # and also plugins installed with extensions
          self.checkBoxByPlugin[pluginClass].checked = True

    else:

      # All DICOM plugins would be enabled by default
      for pluginClass in slicer.modules.dicomPlugins:
        self.checkBoxByPlugin[pluginClass].checked = True
  def __init__(self,database,fileToBeAddedCallback=None,fileAddedCallback=None):
    super(DICOMListener,self).__init__()
    self.dicomDatabase = database
    self.indexer = ctk.ctkDICOMIndexer()
    self.fileToBeAddedCallback = fileToBeAddedCallback
    self.fileAddedCallback = fileAddedCallback
    self.lastFileAdded = None
    settings = qt.QSettings()

    dir = settings.value('DatabaseDirectory')
    if not dir:
      raise( UserWarning('Database directory not set: cannot start DICOMListener') )
    if not os.path.exists(dir):
      os.mkdir(dir)
    self.incomingDir = dir + "/incoming"
    if not os.path.exists(self.incomingDir):
      os.mkdir(self.incomingDir)

    self.port = settings.value('StoragePort')
    if not self.port:
      settings.setValue('StoragePort', '11112')
      self.port = settings.value('StoragePort')
Exemple #8
0
 def loadParametersFromSettings(self):
     settings = qt.QSettings()
     self.ui.pixelTypeComboBox.currentText = settings.value(
         'RawImageGuess/pixelType')
     self.ui.endiannessComboBox.currentText = settings.value(
         'RawImageGuess/endianness')
     self.ui.imageSkipSliderWidget.value = toLong(
         settings.value('RawImageGuess/headerSize', 0))
     self.ui.imageSizeXSliderWidget.value = toLong(
         settings.value('RawImageGuess/sizeX', 200))
     self.ui.imageSizeYSliderWidget.value = toLong(
         settings.value('RawImageGuess/sizeY', 200))
     self.ui.imageSizeZSliderWidget.value = toLong(
         settings.value('RawImageGuess/sizeZ', 1))
     self.ui.skipSlicesSliderWidget.value = toLong(
         settings.value('RawImageGuess/skipSlices', 0))
     self.ui.imageSpacingXSliderWidget.value = float(
         settings.value('RawImageGuess/spacingX', 1.0))
     self.ui.imageSpacingYSliderWidget.value = float(
         settings.value('RawImageGuess/spacingY', 1.0))
     self.ui.imageSpacingZSliderWidget.value = float(
         settings.value('RawImageGuess/spacingZ', 1.0))
Exemple #9
0
 def saveParametersToSettings(self):
     settings = qt.QSettings()
     settings.setValue('RawImageGuess/pixelType',
                       self.ui.pixelTypeComboBox.currentText)
     settings.setValue('RawImageGuess/endianness',
                       self.ui.endiannessComboBox.currentText)
     settings.setValue('RawImageGuess/headerSize',
                       self.ui.imageSkipSliderWidget.value)
     settings.setValue('RawImageGuess/sizeX',
                       self.ui.imageSizeXSliderWidget.value)
     settings.setValue('RawImageGuess/sizeY',
                       self.ui.imageSizeYSliderWidget.value)
     settings.setValue('RawImageGuess/sizeZ',
                       self.ui.imageSizeZSliderWidget.value)
     settings.setValue('RawImageGuess/skipSlices',
                       self.ui.skipSlicesSliderWidget.value)
     settings.setValue('RawImageGuess/spacingX',
                       self.ui.imageSpacingXSliderWidget.value)
     settings.setValue('RawImageGuess/spacingY',
                       self.ui.imageSpacingXSliderWidget.value)
     settings.setValue('RawImageGuess/spacingZ',
                       self.ui.imageSpacingXSliderWidget.value)
Exemple #10
0
def closeTemporaryDatabase(originalDatabaseDir, cleanup=True):
    """ Close temporary DICOM database and remove its directory if requested
    """
    if slicer.dicomDatabase.isOpen:
        if cleanup:
            slicer.dicomDatabase.initializeDatabase()
            # TODO: The database files cannot be deleted even if the database is closed.
            #       Not critical, as it will be empty, so will not take measurable disk space.
            # import shutil
            # databaseDir = os.path.split(slicer.dicomDatabase.databaseFilename)[0]
            # shutil.rmtree(databaseDir)
            # if os.access(databaseDir, os.F_OK):
            #     logging.error('Failed to delete DICOM database ' + databaseDir)
        slicer.dicomDatabase.closeDatabase()
    else:
        logging.error('Unable to close DICOM database ' +
                      slicer.dicomDatabase.databaseFilename)

    if originalDatabaseDir is None:
        # Only log debug if there was no original database, as it is a valid use case,
        # see openTemporaryDatabase
        logging.debug('No original database directory was specified')
        return True

    settings = qt.QSettings()
    settings.setValue(slicer.dicomDatabaseDirectorySettingsKey,
                      originalDatabaseDir)

    # Attempt to re-open original database only if it exists
    if os.access(originalDatabaseDir, os.F_OK):
        success = openDatabase(originalDatabaseDir)
        if not success:
            logging.error('Unable to open DICOM database ' +
                          originalDatabaseDir)
            return False

    return True
Exemple #11
0
    def performPostModuleDiscoveryTasks(self):
        """Since dicom plugins are discovered while the application
    is initialized, they may be found after the DICOM module
    itself if initialized.  This method is tied to a singleShot
    that will be called once the event loop is read to start.
    """

        if slicer.mrmlScene.GetTagByClassName(
                "vtkMRMLScriptedModuleNode") != 'ScriptedModule':
            slicer.mrmlScene.RegisterNodeClass(vtkMRMLScriptedModuleNode())

        # initialize the dicom infrastructure
        slicer.dicomDatabase = None
        settings = qt.QSettings()
        # the dicom database is a global object for slicer
        if settings.contains('DatabaseDirectory'):
            databaseDirectory = settings.value('DatabaseDirectory')
            if databaseDirectory:
                slicer.dicomDatabase = ctk.ctkDICOMDatabase()
                slicer.dicomDatabase.openDatabase(
                    databaseDirectory + "/ctkDICOM.sql", "SLICER")
                if not slicer.dicomDatabase.isOpen:
                    # can't open the database, so prompt the user later if they enter module
                    slicer.dicomDatabase = None
                else:
                    self.startListener()
                if slicer.dicomDatabase:
                    slicer.app.setDICOMDatabase(slicer.dicomDatabase)
        # set the dicom pre-cache tags once all plugin classes have been initialized
        DICOMLib.setDatabasePrecacheTags()

        if not slicer.app.commandOptions().noMainWindow:
            # add to the main app file menu
            self.addMenu()
            # add the settings options
            self.settingsPanel = DICOMSettingsPanel()
            slicer.app.settingsDialog().addPanel("DICOM", self.settingsPanel)
Exemple #12
0
    def __init__(self, parent=None):
        ScriptedLoadableModuleWidget.__init__(self, parent)
        settings = qt.QSettings()
        self.developerMode = settings.value('Developer/DeveloperMode').lower() == 'true'
        if not parent:
            self.parent = slicer.qMRMLWidget()
            self.parent.setLayout(qt.QVBoxLayout())
            self.parent.setMRMLScene(slicer.mrmlScene)
        else:
            self.parent = parent
        self.layout = self.parent.layout()
        if not parent:
            self.setup()
            self.parent.show()

        self.priority = 2
        self.calcinationType = 0
        self.ThresholdMin = 130.0
        self.ThresholdMax = 2000.0
        self.MinimumLesionSize = 1
        self.MaximumLesionSize = 2000
        self.croppedVolumeNode = slicer.vtkMRMLScalarVolumeNode()
        self.threshImage = vtk.vtkImageData()
        self.marchingCubes = vtk.vtkDiscreteMarchingCubes()
        self.transformPolyData = vtk.vtkTransformPolyDataFilter()

        self.selectedLableList = []
        self.labelScores = []
        self.selectedLables = {}
        self.modelNodes = []
        self.voxelVolume = 1
        self.selectedRGB = [1,0,0]
        self.observerTags = []
        self.xy = []

        self.totalScore = 0
  def validate(self):
    moduleCount = len(self.selectedModules)

    if moduleCount == 0:
      self.ui.buttonBox.button(qt.QDialogButtonBox.Yes).enabled = False
      self.ui.addToSearchPaths.enabled = False

      moduleCount = len(self._moduleItems)

    else:
      self.ui.buttonBox.button(qt.QDialogButtonBox.Yes).enabled = True
      self.ui.addToSearchPaths.enabled = True

    if moduleCount == 1:
      self.ui.addToSearchPaths.text = "Add selected module to search paths"
    else:
      self.ui.addToSearchPaths.text = "Add selected modules to search paths"

    # If developer mode is already enabled then don't even show the option
    settings = qt.QSettings()
    developerModeAlreadyEnabled = slicer.util.settingsValue('Developer/DeveloperMode', False, lambda v: v.lower()=='true')
    if developerModeAlreadyEnabled:
      self.ui.enableDeveloperMode.visible = False
      self.ui.enableDeveloperMode.checked = False
Exemple #14
0
    def __init__(self, epsilon=0.01):
        # Get the location and initialize the DICOM DB used by Reporting logic
        reportingLogic = slicer.modules.reporting.logic()
        settings = qt.QSettings()
        dbFileName = settings.value("DatabaseDirectory", "")
        if dbFileName == "":
            print(
                "DICOMSegmentationPlugin failed to initialize DICOM db location from settings"
            )
        else:
            dbFileName = dbFileName + "/ctkDICOM.sql"
            if reportingLogic.InitializeDICOMDatabase(dbFileName):
                print("DICOMSegmentationPlugin initialized DICOM db OK")
            else:
                print('Failed to initialize DICOM database at ' + dbFileName)

        super(DICOMSegmentationPluginClass, self).__init__()
        self.loadType = "DICOMSegmentation"

        self.tags['seriesInstanceUID'] = "0020,000E"
        self.tags['seriesDescription'] = "0008,103E"
        self.tags['seriesNumber'] = "0020,0011"
        self.tags['modality'] = "0008,0060"
        self.tags['instanceUID'] = "0008,0018"
    def saveServerUrl(self):
        self.updateMRMLFromGUI()

        # Save selected server URL
        settings = qt.QSettings()
        serverUrl = self.ui.serverComboBox.currentText
        settings.setValue("NVIDIA-AIAA/serverUrl", serverUrl)

        # Save current server URL to the top of history
        serverUrlHistory = settings.value("NVIDIA-AIAA/serverUrlHistory")
        if serverUrlHistory:
            serverUrlHistory = serverUrlHistory.split(";")
        else:
            serverUrlHistory = []
        try:
            serverUrlHistory.remove(serverUrl)
        except ValueError:
            pass

        serverUrlHistory.insert(0, serverUrl)
        serverUrlHistory = serverUrlHistory[:10]  # keep up to first 10 elements
        settings.setValue("NVIDIA-AIAA/serverUrlHistory", ";".join(serverUrlHistory))

        self.updateServerUrlGUIFromSettings()
Exemple #16
0
    def addCatheterNameToConfig(self, cathName):

        nameList = self.getCatheterNameListFromConfig()

        if cathName == None or cathName == '':
            return 0

        if (type(nameList) == list) and (cathName in nameList):
            # The name already exists in the config
            return 0

        settings = qt.QSettings()

        setting = settings.value(self.moduleName + '/' + 'CathList')

        if type(setting) == tuple:
            setting = list(setting)
            setting.append(cathName)
        else:
            setting = [cathName]

        settings.setValue(self.moduleName + '/' + 'CathList', setting)

        return 1
Exemple #17
0
    def savePathsInApplicationSettings(self, beamNode):
        if beamNode is None:
            return

        ctcreateExecFilePath = self.scriptedEngine.parameter(
            beamNode, "CtcreateExecFilePath")
        if ctcreateExecFilePath != self.ctcreateExecFilePathDefault:
            qt.QSettings().setValue(
                'OrthovoltageDoseEngine/CtcreateExecFilePath',
                ctcreateExecFilePath)

        ctcreateOutputPath = self.scriptedEngine.parameter(
            beamNode, "CtcreateOutputPath")
        if ctcreateOutputPath != self.ctcreateOutputPathDefault:
            qt.QSettings().setValue(
                'OrthovoltageDoseEngine/CtcreateOutputPath',
                ctcreateOutputPath)

        phaseSpaceFilePath = self.scriptedEngine.parameter(
            beamNode, "PhaseSpaceFilePath")
        if phaseSpaceFilePath != self.phaseSpaceFilePathDefault:
            qt.QSettings().setValue(
                'OrthovoltageDoseEngine/PhaseSpaceFilePath',
                phaseSpaceFilePath)

        dosxyznrcFolderPath = self.scriptedEngine.parameter(
            beamNode, "DosxyznrcFolderPath")
        if dosxyznrcFolderPath != self.dosxyznrcFolderPathDefault:
            qt.QSettings().setValue(
                'OrthovoltageDoseEngine/DosxyznrcFolderPath',
                dosxyznrcFolderPath)

        dosxyznrcExecFilePath = self.scriptedEngine.parameter(
            beamNode, "DosxyznrcExecFilePath")
        if dosxyznrcExecFilePath != self.dosxyznrcExecFilePathDefault:
            qt.QSettings().setValue(
                'OrthovoltageDoseEngine/DosxyznrcExecFilePath',
                dosxyznrcExecFilePath)

        pegsFilePath = self.scriptedEngine.parameter(beamNode, "PegsFilePath")
        if pegsFilePath != self.pegsFilePathDefault:
            qt.QSettings().setValue('OrthovoltageDoseEngine/PegsFilePath',
                                    pegsFilePath)
Exemple #18
0
 def onCondaDirectorySelected(self):
     self.condaDirectoryPath = self.condaDirectoryPathSelector.directory
     self.logic.setPathToCondaExecutable(self.condaDirectoryPath)
     settings = qt.QSettings()
     settings.setValue("AIGT/Anaconda", self.condaDirectoryPath)
Exemple #19
0
 def onFontSizeSpinBox(self):
   self.fontSize = self.fontSizeSpinBox.value
   settings = qt.QSettings()
   settings.setValue('DataProbe/sliceViewAnnotations.fontSize',
       self.fontSize)
   self.updateSliceViewFromGUI()
Exemple #20
0
    def examine(self, fileLists):
        """ Returns a list of DICOMLoadable instances
    corresponding to ways of interpreting the
    fileLists parameter.

    Top-level examine() calls various individual strategies implemented in examineFiles*().
    """
        loadables = []
        allfiles = []
        for files in fileLists:
            loadables += self.examineFiles(files)

            # this strategy sorts the files into groups
            loadables += self.examineFilesIPPAcqTime(files)

            allfiles += files

        # here all files are lumped into one list for the situations when
        # individual frames should be parsed from series
        loadables += self.examineFilesMultiseries(allfiles)
        if len(allfiles) > len(files):
            # only examineFilesIPPAcqTime again if there are multiple file groups
            loadables += self.examineFilesIPPAcqTime(allfiles)

        # this strategy sorts the files into groups
        loadables += self.examineFilesIPPInstanceNumber(allfiles)

        # If Sequences module is available then duplicate all the loadables
        # for loading them as volume sequence.
        # A slightly higher confidence value is set for volume sequence loadables,
        # therefore by default data will be loaded as volume sequence.

        if hasattr(slicer.modules, 'sequences'):

            seqLoadables = []
            for loadable in loadables:
                seqLoadable = DICOMLib.DICOMLoadable()
                seqLoadable.files = loadable.files
                seqLoadable.tooltip = loadable.tooltip.replace(
                    ' frames MultiVolume by ', ' frames Volume Sequence by ')
                seqLoadable.name = loadable.name.replace(
                    ' frames MultiVolume by ', ' frames Volume Sequence by ')
                seqLoadable.multivolume = loadable.multivolume
                seqLoadable.selected = loadable.selected

                seqLoadable.confidence = loadable.confidence

                seqLoadable.loadAsVolumeSequence = True
                seqLoadables.append(seqLoadable)

            # Among all selected loadables, the ones that are listed first will be selected by default,
            # therefore we need to prepend loadables if sequence format is preferred.
            # Determine from settings loading into sequence node should have higher confidence (selected by default).
            settings = qt.QSettings()
            sequenceFormatPreferred = (settings.value(
                "DICOM/PreferredMultiVolumeImportFormat",
                "default") == "sequence")
            if sequenceFormatPreferred:
                # prepend
                loadables[0:0] = seqLoadables
            else:
                # append
                loadables += seqLoadables

        return loadables
Exemple #21
0
    def getLoadablesFromFileLists(self, fileLists):
        """Take list of file lists, return loadables by plugin dictionary
        """

        loadablesByPlugin = {}
        loadEnabled = False

        # Get selected plugins from application settings
        # Settings are filled in DICOMWidget using DICOMPluginSelector
        settings = qt.QSettings()
        selectedPlugins = []
        if settings.contains('DICOM/disabledPlugins/size'):
            size = settings.beginReadArray('DICOM/disabledPlugins')
            disabledPlugins = []

            for i in range(size):
                settings.setArrayIndex(i)
                disabledPlugins.append(str(settings.allKeys()[0]))
            settings.endArray()

            for pluginClass in slicer.modules.dicomPlugins:
                if pluginClass not in disabledPlugins:
                    selectedPlugins.append(pluginClass)
        else:
            # All DICOM plugins would be enabled by default
            for pluginClass in slicer.modules.dicomPlugins:
                selectedPlugins.append(pluginClass)

        allFileCount = missingFileCount = 0
        for fileList in fileLists:
            for filePath in fileList:
                allFileCount += 1
                if not os.path.exists(filePath):
                    missingFileCount += 1

        messages = []
        if missingFileCount > 0:
            messages.append(
                "Warning: %d of %d selected files listed in the database cannot be found on disk."
                % (missingFileCount, allFileCount))

        if missingFileCount < allFileCount:
            progressDialog = slicer.util.createProgressDialog(parent=self,
                                                              value=0,
                                                              maximum=100)

            def progressCallback(progressDialog, progressLabel, progressValue):
                progressDialog.labelText = '\nChecking %s' % progressLabel
                slicer.app.processEvents()
                progressDialog.setValue(progressValue)
                slicer.app.processEvents()
                cancelled = progressDialog.wasCanceled
                return cancelled

            loadablesByPlugin, loadEnabled = DICOMLib.getLoadablesFromFileLists(
                fileLists,
                selectedPlugins,
                messages,
                lambda progressLabel, progressValue,
                progressDialog=progressDialog: progressCallback(
                    progressDialog, progressLabel, progressValue),
                self.pluginInstances)

            progressDialog.close()

        if messages:
            slicer.util.warningDisplay(
                "Warning: %s\n\nSee python console for error message." %
                ' '.join(messages),
                windowTitle="DICOM",
                parent=self)

        return loadablesByPlugin, loadEnabled
Exemple #22
0
 def onRunListenerAtStart(self, toggled):
     settings = qt.QSettings()
     settings.setValue('DICOM/RunListenerAtStart', toggled)
Exemple #23
0
    def setup(self):
        ScriptedLoadableModuleWidget.setup(self)

        # This module is often used in developer mode, therefore
        # collapse reload & test section by default.
        if hasattr(self, "reloadCollapsibleButton"):
            self.reloadCollapsibleButton.collapsed = True

        self.dragAndDropEventFilter = DICOMLoadingByDragAndDropEventFilter()

        globals()['d'] = self

        self.testingServer = None
        self.browserWidget = None
        self.directoryButton = None

        # Load widget from .ui file (created by Qt Designer)
        uiWidget = slicer.util.loadUI(self.resourcePath('UI/DICOM.ui'))
        self.layout.addWidget(uiWidget)
        self.ui = slicer.util.childWidgetVariables(uiWidget)

        self.browserWidget = DICOMLib.SlicerDICOMBrowser()
        self.browserWidget.objectName = 'SlicerDICOMBrowser'

        slicer.modules.DICOMInstance.setBrowserWidgetInDICOMLayout(
            self.browserWidget)

        layoutManager = slicer.app.layoutManager()
        if layoutManager is not None:
            layoutManager.layoutChanged.connect(self.onLayoutChanged)
            viewArrangement = slicer.app.layoutManager().layoutLogic(
            ).GetLayoutNode().GetViewArrangement()
            self.ui.showBrowserButton.checked = (
                viewArrangement ==
                slicer.vtkMRMLLayoutNode.SlicerLayoutDicomBrowserView)

        # connect to the 'Show DICOM Browser' button
        self.ui.showBrowserButton.connect('clicked()',
                                          self.toggleBrowserWidget)

        self.ui.importButton.connect('clicked()',
                                     self.browserWidget.dicomBrowser,
                                     'openImportDialog()')

        self.ui.subjectHierarchyTree.setMRMLScene(slicer.mrmlScene)
        self.ui.subjectHierarchyTree.currentItemChanged.connect(
            self.onCurrentItemChanged)
        self.ui.subjectHierarchyTree.currentItemModified.connect(
            self.onCurrentItemModified)
        self.subjectHierarchyCurrentVisibility = False
        self.ui.subjectHierarchyTree.setColumnHidden(
            self.ui.subjectHierarchyTree.model().idColumn, True)

        #
        # DICOM networking
        #

        self.ui.networkingFrame.collapsed = True
        self.ui.queryServerButton.connect('clicked()',
                                          self.browserWidget.dicomBrowser,
                                          "openQueryDialog()")

        self.ui.toggleListener.connect('toggled(bool)', self.onToggleListener)

        settings = qt.QSettings()
        self.ui.runListenerAtStart.checked = settingsValue(
            'DICOM/RunListenerAtStart', False, converter=toBool)
        self.ui.runListenerAtStart.connect('toggled(bool)',
                                           self.onRunListenerAtStart)

        # Testing server - not exposed (used for development)

        self.toggleServer = qt.QPushButton("Start Testing Server")
        self.ui.networkingFrame.layout().addWidget(self.toggleServer)
        self.toggleServer.connect('clicked()', self.onToggleServer)

        self.verboseServer = qt.QCheckBox("Verbose")
        self.ui.networkingFrame.layout().addWidget(self.verboseServer)

        # advanced options - not exposed to end users
        # developers can uncomment these lines to access testing server
        self.toggleServer.hide()
        self.verboseServer.hide()

        #
        # Browser settings
        #

        self.ui.browserSettingsFrame.collapsed = True

        self.updateDatabaseDirectoryFromBrowser(
            self.browserWidget.dicomBrowser.databaseDirectory)
        # Synchronize database selection between browser and this widget
        self.ui.directoryButton.directoryChanged.connect(
            self.updateDatabaseDirectoryFromWidget)
        self.browserWidget.dicomBrowser.databaseDirectoryChanged.connect(
            self.updateDatabaseDirectoryFromBrowser)

        self.ui.browserAutoHideCheckBox.checked = not settingsValue(
            'DICOM/BrowserPersistent', False, converter=toBool)
        self.ui.browserAutoHideCheckBox.stateChanged.connect(
            self.onBrowserAutoHideStateChanged)

        self.ui.repairDatabaseButton.connect('clicked()',
                                             self.browserWidget.dicomBrowser,
                                             "onRepairAction()")
        self.ui.clearDatabaseButton.connect('clicked()', self.onClearDatabase)

        # connect to the main window's dicom button
        mw = slicer.util.mainWindow()
        if mw:
            try:
                action = slicer.util.findChildren(mw,
                                                  name='LoadDICOMAction')[0]
                action.connect('triggered()', self.onOpenBrowserWidget)
            except IndexError:
                logging.error(
                    'Could not connect to the main window DICOM button')

        self.databaseRefreshRequestTimer = qt.QTimer()
        self.databaseRefreshRequestTimer.setSingleShot(True)
        # If not receiving new file for 2 seconds then a database update is triggered.
        self.databaseRefreshRequestTimer.setInterval(2000)
        self.databaseRefreshRequestTimer.connect('timeout()',
                                                 self.requestDatabaseRefresh)
Exemple #24
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')
            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')
            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))
Exemple #25
0
 def getCustomElastixBinDir(self):
   settings = qt.QSettings()
   if settings.contains(self.customElastixBinDirSettingsKey):
     return slicer.util.toVTKString(settings.value(self.customElastixBinDirSettingsKey))
   return ''
Exemple #26
0
 def onRunListenerAtStart(self):
   settings = qt.QSettings()
   settings.setValue('DICOM/RunListenerAtStart', self.runListenerAtStart.checked)
Exemple #27
0
  def setup(self):

    #
    # servers
    #

    # testing server - not exposed (used for development)
    self.localFrame = ctk.ctkCollapsibleButton(self.parent)
    self.localFrame.setLayout(qt.QVBoxLayout())
    self.localFrame.setText("Servers")
    self.layout.addWidget(self.localFrame)
    self.localFrame.collapsed = False

    self.toggleServer = qt.QPushButton("Start Testing Server")
    self.localFrame.layout().addWidget(self.toggleServer)
    self.toggleServer.connect('clicked()', self.onToggleServer)

    self.verboseServer = qt.QCheckBox("Verbose")
    self.localFrame.layout().addWidget(self.verboseServer)

    # advanced options - not exposed to end users
    # developers can uncomment these lines to access testing server
    self.toggleServer.hide()
    self.verboseServer.hide()

    # Listener

    settings = qt.QSettings()
    self.toggleListener = qt.QPushButton()
    self.toggleListener.checkable = True
    if hasattr(slicer, 'dicomListener'):
      self.toggleListener.text = "Stop Listener"
      slicer.dicomListener.process.connect('stateChanged(int)',self.onListenerStateChanged)
    else:
      self.toggleListener.text = "Start Listener"
    self.localFrame.layout().addWidget(self.toggleListener)
    self.toggleListener.connect('clicked()', self.onToggleListener)

    self.runListenerAtStart = qt.QCheckBox("Start Listener when Slicer Starts")
    self.localFrame.layout().addWidget(self.runListenerAtStart)
    self.runListenerAtStart.checked = settingsValue('DICOM/RunListenerAtStart', False, converter=toBool)
    self.runListenerAtStart.connect('clicked()', self.onRunListenerAtStart)

    # the Database frame (home of the ctkDICOM widget)
    self.dicomFrame = ctk.ctkCollapsibleButton(self.parent)
    self.dicomFrame.setLayout(qt.QVBoxLayout())
    self.dicomFrame.setText("DICOM Database and Networking")
    self.layout.addWidget(self.dicomFrame)

    self.detailsPopup = self.getSavedDICOMDetailsWidgetType()()

    # XXX Slicer 4.5 - Remove these. Here only for backward compatibility.
    self.dicomBrowser = self.detailsPopup.dicomBrowser
    self.tables = self.detailsPopup.tables

    # connect to the 'Show DICOM Browser' button
    self.showBrowserButton = qt.QPushButton('Show DICOM Browser')
    self.dicomFrame.layout().addWidget(self.showBrowserButton)
    self.showBrowserButton.connect('clicked()', self.onOpenDetailsPopup)

    # connect to the main window's dicom button
    mw = slicer.util.mainWindow()
    if mw:
      try:
        action = slicer.util.findChildren(mw,name='LoadDICOMAction')[0]
        action.connect('triggered()',self.onOpenDetailsPopup)
      except IndexError:
        logging.error('Could not connect to the main window DICOM button')

    if hasattr(slicer, 'dicomListener'):
      slicer.dicomListener.fileToBeAddedCallback = self.onListenerToAddFile
      slicer.dicomListener.fileAddedCallback = self.onListenerAddedFile

    slicer.dicomDatabase.connect('databaseChanged()', self.onDatabaseChanged)

    # the recent activity frame
    self.activityFrame = ctk.ctkCollapsibleButton(self.parent)
    self.activityFrame.setLayout(qt.QVBoxLayout())
    self.activityFrame.setText("Recent DICOM Activity")
    self.layout.addWidget(self.activityFrame)

    self.recentActivity = DICOMLib.DICOMRecentActivityWidget(self.activityFrame,detailsPopup=self.detailsPopup)
    self.activityFrame.layout().addWidget(self.recentActivity)
    self.requestUpdateRecentActivity()


    # Add spacer to layout
    self.layout.addStretch(1)
Exemple #28
0
 def setDICOMDetailsWidgetType(widgetType):
   if not widgetType in DICOMWidget.getAvailableWidgetTypes():
     raise ValueError("Widget type '%s' for DICOMDetails does not exist" % widgetType)
   else:
     qt.QSettings().setValue('DICOM/BrowserWidgetType', widgetType)
Exemple #29
0
def getSortedImageFiles(filePaths, epsilon=0.01):
  """ Sort DICOM image files in increasing slice order (IS direction) corresponding to a series

      Use the first file to get the ImageOrientationPatient for the
      series and calculate the scan direction (assumed to be perpendicular
      to the acquisition plane)

      epsilon: Maximum difference in distance between slices to consider spacing uniform
  """
  warningText = ''
  if len(filePaths) == 0:
    return filePaths, [], warningText

  # Define DICOM tags used in this function
  tags = {}
  tags['position'] = "0020,0032"
  tags['orientation'] = "0020,0037"
  tags['numberOfFrames'] = "0028,0008"
  tags['seriesUID'] = "0020,000E"

  seriesUID = slicer.dicomDatabase.fileValue(filePaths[0], tags['seriesUID'])

  if slicer.dicomDatabase.fileValue(filePaths[0], tags['numberOfFrames']) != "":
    warningText += "Multi-frame image. If slice orientation or spacing is non-uniform then the image may be displayed incorrectly. Use with caution.\n"

  # Make sure first file contains valid geometry
  ref = {}
  for tag in [tags['position'], tags['orientation']]:
    value = slicer.dicomDatabase.fileValue(filePaths[0], tag)
    if not value or value == "":
      warningText += "Reference image in series does not contain geometry information. Please use caution.\n"
      return filePaths, [], warningText
    ref[tag] = value

  # Determine out-of-plane direction for first slice
  import numpy as np
  sliceAxes = [float(zz) for zz in ref[tags['orientation']].split('\\')]
  x = np.array(sliceAxes[:3])
  y = np.array(sliceAxes[3:])
  scanAxis = np.cross(x,y)
  scanOrigin = np.array([float(zz) for zz in ref[tags['position']].split('\\')])

  # For each file in series, calculate the distance along the scan axis, sort files by this
  sortList = []
  missingGeometry = False
  for file in filePaths:
    positionStr = slicer.dicomDatabase.fileValue(file,tags['position'])
    orientationStr = slicer.dicomDatabase.fileValue(file,tags['orientation'])
    if not positionStr or positionStr == "" or not orientationStr or orientationStr == "":
      missingGeometry = True
      break
    position = np.array([float(zz) for zz in positionStr.split('\\')])
    vec = position - scanOrigin
    dist = vec.dot(scanAxis)
    sortList.append((file, dist))

  if missingGeometry:
    warningText += "One or more images is missing geometry information in series. Please use caution.\n"
    return filePaths, [], warningText

  # Sort files names by distance from reference slice
  sortedFiles = sorted(sortList, key=lambda x: x[1])
  files = []
  distances = {}
  for file,dist in sortedFiles:
    files.append(file)
    distances[file] = dist

  # Get acquisition geometry regularization setting value
  settings = qt.QSettings()
  acquisitionGeometryRegularizationEnabled = (settings.value("DICOM/ScalarVolume/AcquisitionGeometryRegularization", "default") == "transform")

  # Confirm equal spacing between slices
  # - use variable 'epsilon' to determine the tolerance
  spaceWarnings = 0
  if len(files) > 1:
    file0 = files[0]
    file1 = files[1]
    dist0 = distances[file0]
    dist1 = distances[file1]
    spacing0 = dist1 - dist0
    n = 1
    for fileN in files[1:]:
      fileNminus1 = files[n-1]
      distN = distances[fileN]
      distNminus1 = distances[fileNminus1]
      spacingN = distN - distNminus1
      spaceError = spacingN - spacing0
      if abs(spaceError) > epsilon:
        spaceWarnings += 1
        warningText += "Images are not equally spaced (a difference of %g vs %g in spacings was detected)." % (spaceError, spacing0)
        if acquisitionGeometryRegularizationEnabled:
          warningText += "  Slicer will apply a transform to this series trying to regularize the volume. Please use caution.\n"
        else:
          warningText += ("  If loaded image appears distorted, enable 'Acquisition geometry regularization'"
            " in Application settings / DICOM / DICOMScalarVolumePlugin. Please use caution.\n")
        break
      n += 1

  if spaceWarnings != 0:
    logging.warning("Geometric issues were found with %d of the series. Please use caution.\n" % spaceWarnings)

  return files, distances, warningText
Exemple #30
0
 def allowLoadingByTime(self):
     settings = qt.QSettings()
     return (int(
         settings.value("DICOM/ScalarVolume/AllowLoadingByTime", "0")) != 0)