Example #1
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)

            dataProbe = slicer.util.mainWindow().findChild(
                "QWidget", "DataProbeCollapsibleWidget")
            self.wasDataProbeVisible = dataProbe.isVisible()

            layoutManager = slicer.app.layoutManager()
            layoutManager.layoutChanged.connect(self.onLayoutChanged)
            layout = ("<layout type=\"horizontal\">"
                      " <item>"
                      "  <dicombrowser></dicombrowser>"
                      " </item>"
                      "</layout>")
            layoutNode = slicer.app.layoutManager().layoutLogic(
            ).GetLayoutNode()
            layoutNode.AddLayoutDescription(
                slicer.vtkMRMLLayoutNode.SlicerLayoutDicomBrowserView, layout)
            self.currentViewArrangement = layoutNode.GetViewArrangement()
            self.previousViewArrangement = layoutNode.GetViewArrangement()

        self.detailsPopup = None
        self.viewWidget = None
        self.browserSettingsWidget = None
        self.setDetailsPopup(DICOMWidget.getSavedDICOMDetailsWidgetType()())
Example #2
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)
Example #3
0
  def examineForLoading(self):
    """For selected plugins, give user the option
    of what to load"""

    (self.loadablesByPlugin, loadEnabled) = self.getLoadablesFromFileLists(self.fileLists)
    DICOMLib.selectHighestConfidenceLoadables(self.loadablesByPlugin)
    self.loadableTable.setLoadables(self.loadablesByPlugin)
    self.updateButtonStates()
Example #4
0
 def onClearDatabase(self):
   patientIds = slicer.dicomDatabase.patients()
   if len(patientIds) == 0:
     slicer.util.infoDisplay("DICOM database is already empty.")
   elif not slicer.util.confirmYesNoDisplay(
     'Are you sure you want to delete all data and files copied into the database (%d patients)?' % len(patientIds),
     windowTitle='Clear entire DICOM database'):
       return
   DICOMLib.clearDatabase(slicer.dicomDatabase)
Example #5
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.
   """
   # set the dicom pre-cache tags once all plugin classes have been initialized
   DICOMLib.setDatabasePrecacheTags()
   # add to the main app file menu
   self.addMenu()
   # add the settings options
   self.settingsPanel = DICOMSettingsPanel()
   slicer.app.settingsDialog().addPanel("DICOM", self.settingsPanel)
Example #6
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.
    """
    # 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)
    def load_dicom_archive(self, file_path):
        """
        Load unzipped DICOMs into Slicer.

        Args:
            file_path (str): path to the cached dicom archive.

        https://discourse.slicer.org/t/fastest-way-to-load-dicom/9317/2
        """
        with tempfile.TemporaryDirectory() as dicomDataDir:
            dicom_zip = ZipFile(file_path)
            dicom_zip.extractall(path=dicomDataDir)
            DICOMLib.importDicom(dicomDataDir)
            dicomFiles = slicer.util.getFilesInDirectory(dicomDataDir)
            loadablesByPlugin, loadEnabled = DICOMLib.getLoadablesFromFileLists([dicomFiles])
            loadedNodeIDs = DICOMLib.loadLoadables(loadablesByPlugin)
Example #8
0
    def onOk(self):
        self.sendingIsInProgress = True
        address = self.serverAddressLineEdit.text
        protocol = self.protocolSelectorCombobox.currentText
        self.settings.setValue('DICOM/Send/URL', address)
        self.settings.setValue('DICOM/Send/Protocol', protocol)
        self.progressBar.value = 0
        self.progressBar.maximum = len(self.files) + 1
        self.progressBar.show()
        self.cancelRequested = False
        okButton = self.bbox.button(self.bbox.Ok)

        try:
            #qt.QApplication.setOverrideCursor(qt.Qt.WaitCursor)
            okButton.enabled = False
            DICOMLib.DICOMSender(self.files,
                                 address,
                                 protocol,
                                 progressCallback=self.onProgress)
            logging.debug("DICOM sending of %s files succeeded" %
                          len(self.files))
            self.close()
        except Exception as result:
            import traceback
            slicer.util.errorDisplay("DICOM sending failed: %s" % str(result),
                                     parent=self.parent().window(),
                                     detailedText=traceback.format_exc())

        #qt.QApplication.restoreOverrideCursor()
        okButton.enabled = True
        self.sendingIsInProgress = False
Example #9
0
 def onExportClicked(self):
     """Associate a slicer volume as a series in the selected dicom study"""
     uid = self.selection.data(self.dicomModelUIDRole)
     exportDialog = DICOMLib.DICOMExportDialog(
         uid, onExportFinished=self.onExportFinished)
     self.dicomApp.suspendModel()
     exportDialog.open()
Example #10
0
  def proceedWithReferencedLoadablesSelection(self):
    if not self.warnUserIfLoadableWarningsAndProceed():
      return

    progressDialog = slicer.util.createProgressDialog(parent=self, value=0, maximum=100)

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

    qt.QApplication.setOverrideCursor(qt.Qt.WaitCursor)

    messages = []
    loadedNodeIDs = DICOMLib.loadLoadables(self.loadablesByPlugin, messages,
      lambda progressLabel, progressValue, progressDialog=progressDialog: progressCallback(progressDialog, progressLabel, progressValue))

    loadedFileParameters = {}
    loadedFileParameters['nodeIDs'] = loadedNodeIDs
    slicer.app.ioManager().emitNewFileLoaded(loadedFileParameters)

    qt.QApplication.restoreOverrideCursor()

    progressDialog.close()

    if messages:
      slicer.util.warningDisplay('\n'.join(messages), windowTitle='DICOM loading')

    self.onLoadingFinished()
Example #11
0
  def onToggleServer(self):
    if self.testingServer and self.testingServer.qrRunning():
      self.testingServer.stop()
      self.toggleServer.text = "Start Testing Server"
    else:
      #
      # create&configure the testingServer if needed, start the server, and populate it
      #
      if not self.testingServer:
        # find the helper executables (only works on build trees
        # with standard naming conventions)
        self.exeDir = slicer.app.slicerHome
        if slicer.app.intDir:
          self.exeDir = self.exeDir + '/' + slicer.app.intDir
        self.exeDir = self.exeDir + '/../CTK-build/DCMTK-build'

        # TODO: deal with Debug/RelWithDebInfo on windows

        # set up temp dir
        tmpDir = slicer.app.userSettings().value('Modules/TemporaryDirectory')
        if not os.path.exists(tmpDir):
          os.mkdir(tmpDir)
        self.tmpDir = tmpDir + '/DICOM'
        if not os.path.exists(self.tmpDir):
          os.mkdir(self.tmpDir)
        self.testingServer = DICOMLib.DICOMTestingQRServer(exeDir=self.exeDir,tmpDir=self.tmpDir)

      # look for the sample data to load (only works on build trees
      # with standard naming conventions)
      self.dataDir =  slicer.app.slicerHome + '/../../Slicer4/Testing/Data/Input/CTHeadAxialDicom'
      files = glob.glob(self.dataDir+'/*.dcm')

      # now start the server
      self.testingServer.start(verbose=self.verboseServer.checked,initialFiles=files)
    def getLoadablesFromRWVMFile(self, file):
        rwvLoadable = DICOMLib.DICOMLoadable()
        rwvLoadable.files.append(file)
        rwvLoadable.patientName = self.__getSeriesInformation(
            rwvLoadable.files, self.tags['patientName'])
        rwvLoadable.patientID = self.__getSeriesInformation(
            rwvLoadable.files, self.tags['patientID'])
        rwvLoadable.studyDate = self.__getSeriesInformation(
            rwvLoadable.files, self.tags['studyDate'])
        dicomFile = dicom.read_file(file)
        rwvmSeq = dicomFile.ReferencedImageRealWorldValueMappingSequence[
            0].RealWorldValueMappingSequence
        unitsSeq = rwvmSeq[0].MeasurementUnitsCodeSequence
        rwvLoadable.name = rwvLoadable.patientName + ' ' + self.convertStudyDate(
            rwvLoadable.studyDate) + ' ' + unitsSeq[0].CodeMeaning
        rwvLoadable.unitName = unitsSeq[0].CodeMeaning

        (quantity, units) = self.getQuantityAndUnitsFromDICOM(dicomFile)

        rwvLoadable.quantity = quantity
        rwvLoadable.units = units

        rwvLoadable.tooltip = rwvLoadable.name
        rwvLoadable.selected = True
        rwvLoadable.confidence = 0.90
        return [rwvLoadable]
Example #13
0
    def onOk(self):
        self.sendingIsInProgress = True
        address = self.serverAddressLineEdit.text
        aeTitle = self.serverAETitleEdit.text
        protocol = self.protocolSelectorCombobox.currentText
        self.settings.setValue('DICOM/Send/URL', address)
        self.settings.setValue('DICOM/Send/AETitle', aeTitle)
        self.settings.setValue('DICOM/Send/Protocol', protocol)
        self.progressBar.value = 0
        self.progressBar.maximum = len(self.files) + 1
        self.progressBar.show()
        self.cancelRequested = False
        okButton = self.bbox.button(self.bbox.Ok)

        with slicer.util.tryWithErrorDisplay("DICOM sending failed."):
            okButton.enabled = False
            DICOMLib.DICOMSender(self.files,
                                 address,
                                 protocol,
                                 aeTitle=aeTitle,
                                 progressCallback=self.onProgress)
            logging.debug("DICOM sending of %s files succeeded" %
                          len(self.files))
            self.close()

        okButton.enabled = True
        self.sendingIsInProgress = False
Example #14
0
    def __init__(self, parent):
        import string
        parent.title = "DICOM"
        parent.categories = ["", "Informatics"]  # top level module
        parent.contributors = ["Steve Pieper (Isomics)"]
        parent.helpText = string.Template("""
The DICOM module integrates DICOM classes from CTK (based on DCMTK).  See <a href=\"$a/Documentation/$b.$c/Modules/DICOM\">the documentaiton</a> for more information.
""").substitute({
            'a': parent.slicerWikiUrl,
            'b': slicer.app.majorVersion,
            'c': slicer.app.minorVersion
        })
        parent.acknowledgementText = """
This work is supported by NA-MIC, NAC, BIRN, NCIGT, and the Slicer Community. See <a href=http://www.slicer.org>http://www.slicer.org</a> for details.  Module implemented by Steve Pieper.  Based on work from CommonTK (http://www.commontk.org).
    """
        parent.icon = qt.QIcon(':Icons/Medium/SlicerLoadDICOM.png')
        self.parent = parent

        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:
                    # the dicom listener is also global, but only started on app start if
                    # the user so chooses
                    if settings.contains('DICOM/RunListenerAtStart'):
                        if settings.value(
                                'DICOM/RunListenerAtStart') == 'true':
                            if not hasattr(slicer, 'dicomListener'):
                                try:
                                    slicer.dicomListener = DICOMLib.DICOMListener(
                                        slicer.dicomDatabase)
                                    slicer.dicomListener.start()
                                except (UserWarning, OSError) as message:
                                    # TODO: how to put this into the error log?
                                    print(
                                        'Problem trying to start DICOMListener:\n %s'
                                        % message)
                if slicer.dicomDatabase:
                    slicer.app.setDICOMDatabase(slicer.dicomDatabase)

        # Trigger the menu to be added when application has started up
        if not slicer.app.commandOptions().noMainWindow:
            qt.QTimer.singleShot(0, self.addMenu)
        # set the dicom pre-cache tags once all plugin classes have been initialized
        qt.QTimer.singleShot(0, DICOM.setDatabasePrecacheTags)
Example #15
0
    def examineFilesMultiseries(self, files):
        """
    This strategy is similar to examineFiles(), but
    does not separate the files by individual series before
    parsing multivolumes out.
    """

        if self.detailedLogging:
            logging.debug('MultiVolumeImporterPlugin: examineMultiseries')

        loadables = []

        mvNodes = self.initMultiVolumes(files,
                                        prescribedTags=[
                                            'SeriesTime', 'AcquisitionTime',
                                            'FlipAngle', 'CardiacCycle'
                                        ])

        if self.detailedLogging:
            logging.debug(
                'MultiVolumeImporterPlugin: found {} multivolumes!'.format(
                    len(mvNodes)))

        for mvNode in mvNodes:
            tagName = mvNode.GetAttribute(
                'MultiVolume.FrameIdentifyingDICOMTagName')
            nFrames = mvNode.GetNumberOfFrames()
            orderedFiles = mvNode.GetAttribute(
                'MultiVolume.FrameFileList').split(',')

            desc = slicer.dicomDatabase.fileValue(
                orderedFiles[0],
                self.tags['studyDescription'])  # SeriesDescription
            num = slicer.dicomDatabase.fileValue(orderedFiles[0],
                                                 self.tags['seriesNumber'])
            if num != "":
                name = num + ": " + desc
            else:
                name = desc

            if self.isFrameOriginConsistent(orderedFiles, mvNode) == False:
                continue

            loadable = DICOMLib.DICOMLoadable()
            loadable.files = orderedFiles
            loadable.tooltip = name + ' - ' + str(
                nFrames) + ' frames MultiVolume by ' + tagName
            loadable.name = name
            loadable.selected = True
            loadable.multivolume = mvNode
            if tagName == 'TemporalPositionIdentifier':
                loadable.confidence = 0.9
            else:
                loadable.confidence = 1.
            loadables.append(loadable)

        return loadables
Example #16
0
    def __init__(self, parent):
        ScriptedLoadableModule.__init__(self, parent)

        import string
        self.parent.title = "DICOM"
        self.parent.categories = ["", "Informatics"]  # top level module
        self.parent.contributors = ["Steve Pieper (Isomics)"]
        self.parent.helpText = """
The DICOM module integrates DICOM classes from CTK (based on DCMTK).
"""
        self.parent.helpText += self.getDefaultModuleDocumentationLink()
        self.parent.acknowledgementText = """
This work is supported by NA-MIC, NAC, BIRN, NCIGT, and the Slicer Community. See <a href=http://www.slicer.org>http://www.slicer.org</a> for details.  Module implemented by Steve Pieper.  Based on work from CommonTK (http://www.commontk.org).
"""
        self.parent.icon = qt.QIcon(':Icons/Medium/SlicerLoadDICOM.png')
        self.parent.dependencies = ["SubjectHierarchy"]

        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:
                    # the dicom listener is also global, but only started on app start if
                    # the user so chooses
                    if settings.contains('DICOM/RunListenerAtStart'):
                        if settings.value(
                                'DICOM/RunListenerAtStart') == 'true':
                            if not hasattr(slicer, 'dicomListener'):
                                try:
                                    slicer.dicomListener = DICOMLib.DICOMListener(
                                        slicer.dicomDatabase)
                                    slicer.dicomListener.start()
                                except (UserWarning, OSError) as message:
                                    logging.error(
                                        'Problem trying to start DICOMListener:\n %s'
                                        % message)
                if slicer.dicomDatabase:
                    slicer.app.setDICOMDatabase(slicer.dicomDatabase)

        # Tasks to execute after the application has started up
        slicer.app.connect("startupCompleted()",
                           self.performPostModuleDiscoveryTasks)
Example #17
0
    def getLoadablesFromFileLists(self, fileLists):
        """Take list of file lists, return loadables by plugin dictionary
    """

        loadablesByPlugin = {}
        loadEnabled = False

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

        if missingFileCount > 0:
            messages.appendslicer.util.warningDisplay(
                "Warning: %d of %d selected files listed in the database cannot be found on disk."
                % (missingFileCount, allFileCount),
                windowTitle="DICOM")

        if missingFileCount == allFileCount:
            # Nothing to load
            return loadablesByPlugin, loadEnabled

        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

        messages = []
        loadablesByPlugin, loadEnabled = DICOMLib.getLoadablesFromFileLists(
            fileLists,
            self.pluginSelector.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
Example #18
0
 def startListener(self):
   # the dicom listener is also global, but only started on app start if
   # the user so chooses
   settings = qt.QSettings()
   if settings.contains('DICOM/RunListenerAtStart'):
     if settings.value('DICOM/RunListenerAtStart') == 'true':
       if not hasattr(slicer, 'dicomListener'):
         try:
           slicer.dicomListener = DICOMLib.DICOMListener(slicer.dicomDatabase)
           slicer.dicomListener.start()
         except (UserWarning,OSError) as message:
           logging.error('Problem trying to start DICOMListener:\n %s' % message)
Example #19
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)
Example #20
0
 def onToggleListener(self):
   if hasattr(slicer, 'dicomListener'):
     slicer.dicomListener.stop()
     del slicer.dicomListener
     self.toggleListener.text = "Start Listener"
   else:
     try:
       slicer.dicomListener = DICOMLib.DICOMListener(database=slicer.dicomDatabase)
       slicer.dicomListener.start()
       self.onListenerStateChanged(slicer.dicomListener.process.state())
       slicer.dicomListener.process.connect('stateChanged(QProcess::ProcessState)',self.onListenerStateChanged)
       slicer.dicomListener.fileToBeAddedCallback = self.onListenerToAddFile
       slicer.dicomListener.fileAddedCallback = self.onListenerAddedFile
       self.toggleListener.text = "Stop Listener"
     except UserWarning as message:
       self.messageBox(self,"Could not start listener:\n %s" % message,title='DICOM')
Example #21
0
 def onOk(self):
   address = self.dicomEntries['Destination Address'].text
   port = self.dicomEntries['Destination Port'].text
   settings = qt.QSettings()
   settings.setValue('DICOM.sendAddress', address)
   settings.setValue('DICOM.sendPort', port)
   self.progress = qt.QProgressDialog(slicer.util.mainWindow())
   self.progress.minimumDuration = 0
   self.progress.setMaximum(len(self.files))
   self.progressValue = 0
   try:
     DICOMLib.DICOMSender(self.files, address, port, progressCallback = self.onProgress)
   except Exception as result:
     qt.QMessageBox.warning(self.dialog, 'DICOM Send', 'Could not send data: %s' % result)
   self.progress.close()
   self.dialog.close()
Example #22
0
 def onToggleListener(self):
   self.toggleListener.checked = False
   if hasattr(slicer, 'dicomListener'):
     slicer.dicomListener.stop()
     del slicer.dicomListener
   else:
     try:
       dicomListener = DICOMLib.DICOMListener(database=slicer.dicomDatabase)
       dicomListener.start()
       if dicomListener.process:
         self.onListenerStateChanged(dicomListener.process.state())
         dicomListener.process.connect('stateChanged(QProcess::ProcessState)',self.onListenerStateChanged)
         dicomListener.fileToBeAddedCallback = self.onListenerToAddFile
         dicomListener.fileAddedCallback = self.onListenerAddedFile
         slicer.dicomListener = dicomListener
     except UserWarning as message:
       slicer.util.warningDisplay("Could not start listener:\n %s" % message, windowTitle="DICOM")
Example #23
0
  def startListener(self):

    if not slicer.dicomDatabase.isOpen:
      logging.error("Failed to start DICOM listener. DICOM database is not open.")
      return False

    if not hasattr(slicer, 'dicomListener'):
      try:
        dicomListener = DICOMLib.DICOMListener(slicer.dicomDatabase)
        dicomListener.start()
      except (UserWarning, OSError) as message:
        logging.error('Problem trying to start DICOM listener:\n %s' % message)
        return False
      if not dicomListener.process:
        logging.error("Failed to start DICOM listener. Process start failed.")
        return False
      slicer.dicomListener = dicomListener
      logging.info("DICOM C-Store SCP service started at port "+str(slicer.dicomListener.port))
Example #24
0
    def examineFilesMultiseries(self, files):

        print('MultiVolumeImportPlugin:examineMultiseries')
        loadables = []

        mvNodes = self.initMultiVolumes(
            files,
            prescribedTags=['SeriesTime', 'AcquisitionTime', 'FlipAngle'])

        print('DICOMMultiVolumePlugin found ' + str(len(mvNodes)) +
              ' multivolumes!')

        for mvNode in mvNodes:
            tagName = mvNode.GetAttribute(
                'MultiVolume.FrameIdentifyingDICOMTagName')
            nFrames = mvNode.GetNumberOfFrames()
            orderedFiles = string.split(
                mvNode.GetAttribute('MultiVolume.FrameFileList'), ',')

            desc = slicer.dicomDatabase.fileValue(
                orderedFiles[0],
                self.tags['studyDescription'])  # SeriesDescription
            num = slicer.dicomDatabase.fileValue(orderedFiles[0],
                                                 self.tags['seriesNumber'])
            if num != "":
                name = num + ": " + desc
            else:
                name = desc

            if self.isFrameOriginConsistent(orderedFiles, mvNode) == False:
                continue

            loadable = DICOMLib.DICOMLoadable()
            loadable.files = orderedFiles
            loadable.tooltip = name + ' - ' + str(
                nFrames) + ' frames MultiVolume by ' + tagName
            loadable.name = name
            loadable.selected = True
            loadable.multivolume = mvNode
            loadable.confidence = 0.9
            loadables.append(loadable)

        return loadables
Example #25
0
 def onOk(self):
   """Run the export process for either the scene or the selected volume"""
   if self.exportScene.checked:
     volumeNode = None
   else:
     volumeNode = self.volumeSelector.currentNode()
   if volumeNode or self.exportScene.checked:
     parameters = {}
     for label in self.dicomParameters.keys():
       parameters[label] = self.dicomEntries[label].text
     try:
       exporter = DICOMLib.DICOMExporter(self.studyUID,volumeNode,parameters)
       exporter.export()
     except Exception as result:
       import traceback
       qt.QMessageBox.warning(self.dialog, 'DICOM Export', 'Could not export data: %s\n\n%s' % (result, traceback.format_exception(*sys.exc_info())))
   if self.onExportFinished:
     self.onExportFinished()
   self.dialog.close()
Example #26
0
    def __init__(self, parent):
        parent.title = "DICOM"
        parent.category = ""  # top level module
        parent.contributor = "Steve Pieper"
        parent.helpText = """
The DICOM module is a place to experiment a bit with dicom classes from CTK (based on DCMTK).  It is a 'tent' because it is meant to be suitable for explorers, but may not be robust enough for civilized people.

Warning: all data directories are temporary and data may be gone next time you look!
    """
        parent.acknowledgementText = """
This work is supported by NA-MIC, NAC, BIRN, NCIGT, and the Slicer Community. See <a>http://www.slicer.org</a> for details.  Module implemented by Steve Pieper.  Based on work from CommonTK (http://www.commontk.org).
    """
        self.parent = parent

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

        # initialize the dicom infrastructure
        settings = qt.QSettings()
        # the dicom database is a global object for slicer
        databaseDirectory = settings.value('DatabaseDirectory')
        if databaseDirectory:
            slicer.dicomDatabase = ctk.ctkDICOMDatabase()
            slicer.dicomDatabase.openDatabase(
                databaseDirectory + "/ctkDICOM.sql", "SLICER")
            # the dicom listener is also global, but only started on app start if
            # the user so chooses
            if settings.contains('DICOM/RunListenerAtStart'):
                if bool(settings.value('DICOM/RunListenerAtStart')):
                    if not hasattr(slicer, 'dicomListener'):
                        try:
                            slicer.dicomListener = DICOMLib.DICOMListener(
                                slicer.dicomDatabase)
                        except UserWarning as message:
                            # TODO: how to put this into the error log?
                            print(
                                'Problem trying to start DICOMListener:\n %s' %
                                message)
                        slicer.dicomListener.start()
Example #27
0
 def onSendClicked(self):
   """Perform a dicom store of slicer data to a peer"""
   # TODO: this should migrate to ctk for a more complete implementation
   # - just the basics for now
   uid = self.selection.data(self.dicomModelUIDRole)
   role = self.dicomModelTypes[self.selection.data(self.dicomModelTypeRole)]
   studies = []
   if role == "Patient":
     studies = slicer.dicomDatabase.studiesForPatient(uid)
   if role == "Study":
     studies = [uid]
   series = []
   if role == "Series":
     series = [uid]
   else:
     for study in studies:
       series += slicer.dicomDatabase.seriesForStudy(study)
   files = []
   for serie in series:
     files += slicer.dicomDatabase.filesForSeries(serie)
   sendDialog = DICOMLib.DICOMSendDialog(files)
   sendDialog.open()
Example #28
0
    def convertData(self, plugin, loadable):
        node = plugin.load(loadable)
        dcmFile = loadable.files[0]
        seriesNumber = self.dicomDatabase.fileValue(dcmFile, "0020,0011")
        patientID = self.dicomDatabase.fileValue(dcmFile, "0010,0020")
        studyDate = self.dicomDatabase.fileValue(dcmFile, "0008,0020")
        studyTime = self.dicomDatabase.fileValue(dcmFile, "0008,0030")[0:4]

        if node:
            storageNode = node.CreateDefaultStorageNode()
            studyID = '{}_{}_{}'.format(patientID, studyDate, studyTime)
            dirName = os.path.join(self.outputDir, studyID, "RESOURCES",
                                   seriesNumber, "Reconstructions")
            xmlName = os.path.join(dirName, seriesNumber + '.xml')
            try:
                os.makedirs(dirName)
            except:
                pass
            DICOMLib.DICOMCommand("dcm2xml", [dcmFile, xmlName]).start()
            nrrdName = os.path.join(dirName, seriesNumber + ".nrrd")
            # print(nrrdName)
            storageNode.SetFileName(nrrdName)
            storageNode.WriteData(node)

            if self.copyDICOM:
                fileCount = 0
                dirName = os.path.join(self.outputDir, studyID, "RESOURCES",
                                       seriesNumber, "DICOM")
                try:
                    os.makedirs(dirName)
                except:
                    pass
                for dcm in loadable.files:
                    shutil.copy(dcm,
                                os.path.join(dirName, "%06d.dcm" % fileCount))
                    fileCount = fileCount + 1
        else:
            print('No node!')
Example #29
0
    def onOk(self):
        address = self.dicomEntries['Destination Address'].text
        port = self.dicomEntries['Destination Port'].text
        self.settings.setValue('DICOM.sendAddress', address)
        self.settings.setValue('DICOM.sendPort', port)
        self.progress = slicer.util.createProgressDialog(value=0,
                                                         maximum=len(
                                                             self.files))
        self.progressValue = 0

        try:
            DICOMLib.DICOMSender(self.files,
                                 address,
                                 port,
                                 progressCallback=self.onProgress)
        except Exception as result:
            slicer.util.warningDisplay('Could not send data: %s' % result,
                                       windowTitle='DICOM Send',
                                       parent=self)
        self.progress.close()
        self.progress = None
        self.progressValue = None
        self.close()
Example #30
0
  def createDICOMFileForScene(self):
    """
    Export the scene data:
    - first to a directory using the utility in the mrmlScene
    - create a zip file using the application logic
    - create secondary capture based on the sample dataset
    - add the zip file as a private creator tag
    TODO: confirm that resulting file is valid - may need to change the CLI
    to include more parameters or do a new implementation ctk/DCMTK
    See:
    http://sourceforge.net/apps/mediawiki/gdcm/index.php?title=Writing_DICOM
    """

    # set up temp directories and files
    self.dicomDirectory = tempfile.mkdtemp('', 'dicomExport', slicer.app.temporaryPath)
    self.sceneDirectory = os.path.join(self.dicomDirectory,'scene')
    os.mkdir(self.sceneDirectory) # known to be unique
    self.imageFile = os.path.join(self.dicomDirectory, "scene.jpg")
    self.zipFile = os.path.join(self.dicomDirectory, "scene.zip")
    self.dumpFile = os.path.join(self.dicomDirectory, "dicom.dump")
    self.sdbFile = os.path.join(self.dicomDirectory, "SlicerDataBundle.dcm")
    # Clean up paths on Windows (some commands and operations are not performed properly with mixed slash and backslash)
    self.dicomDirectory = self.dicomDirectory.replace('\\','/')
    self.sceneDirectory = self.sceneDirectory.replace('\\','/') # otherwise invalid zip file is created on Windows (with the same size strangely)
    self.imageFile = self.imageFile.replace('\\','/')
    self.zipFile = self.zipFile.replace('\\','/')
    self.dumpFile = self.dumpFile.replace('\\','/')
    self.sdbFile = self.sdbFile.replace('\\','/')

    # get the screen image
    self.progress('Saving Image...')
    image = ctk.ctkWidgetsUtils.grabWidget(slicer.util.mainWindow())
    image.save(self.imageFile)
    imageReader = vtk.vtkJPEGReader()
    imageReader.SetFileName(self.imageFile)
    imageReader.Update()

    #add storage node for each storable node in the scene, add file name if file name doesn't exist
    # TODO: this could be moved to appLogic.SaveSceneToSlicerDataBundleDirectory
    lnodes = slicer.mrmlScene.GetNodesByClass("vtkMRMLLinearTransformNode")
    lnodes.UnRegister(slicer.mrmlScene)
    lnum = lnodes.GetNumberOfItems()
    for itemNum in range(lnum):
      print(itemNum)
      node = lnodes.GetItemAsObject(itemNum)
      snode = node.GetStorageNode()
      if snode is None:
        print("something is none")
        snode = node.CreateDefaultStorageNode()
        slicer.mrmlScene.AddNode(snode)
        node.SetAndObserveStorageNodeID(snode.GetID())
      if snode.GetFileName() is None:
        snode.SetFileName(node.GetID()+".h5")

    # save the scene to the temp dir
    self.progress('Saving Scene...')
    appLogic = slicer.app.applicationLogic()
    appLogic.SaveSceneToSlicerDataBundleDirectory(self.sceneDirectory, imageReader.GetOutput())

    # make the zip file
    self.progress('Making zip...')
    appLogic.Zip(self.zipFile, self.sceneDirectory)
    zipSize = os.path.getsize(self.zipFile)

    # now create the dicom file
    # - create the dump (capture stdout)
    # cmd = "dcmdump --print-all --write-pixel %s %s" % (self.dicomDirectory, self.referenceFile)
    self.progress('Making dicom reference file...')
    if not self.referenceFile:
      # set reference file the first file found in the DICOM database
      self.getFirstFileInDatabase()
      # if there is still no reference file, then there are no files in the database, cannot continue
      if not self.referenceFile:
        logging.error('No reference file! DICOM database is empty')
        return False
    args = ['--print-all', '--write-pixel', self.dicomDirectory, self.referenceFile]
    dump = DICOMLib.DICOMCommand('dcmdump', args).start()

    # append this to the dumped output and save the result as self.dicomDirectory/dcm.dump
    # with %s as self.zipFile and %d being its size in bytes
    zipSizeString = "%d" % zipSize

    # hack: encode the file zip file size as part of the creator string
    # because none of the normal types (UL, DS, LO) seem to survive
    # the dump2dcm step (possibly due to the Unknown nature of the private tag)
    creatorString = "3D Slicer %s" % zipSizeString
    candygram = """(cadb,0010) LO [%s]           #  %d, 1 PrivateCreator
(cadb,1008) LO [%s]                                   #   4, 1 Unknown Tag & Data
(cadb,1010) OB =%s                                      #  %d, 1 Unknown Tag & Data
""" % (creatorString, len(creatorString), zipSizeString, self.zipFile, zipSize)

    dump = str(dump) + candygram

    logging.debug('dumping to: %s/dump.dcm' % self.dicomDirectory, 'w')
    fp = open('%s/dump.dcm' % self.dicomDirectory, 'w')
    fp.write(dump)
    fp.close()

    self.progress('Encapsulating Scene in DICOM Dump...')
    args = [
        '%s/dump.dcm' % self.dicomDirectory,
        '%s/template.dcm' % self.dicomDirectory,
        '--generate-new-uids', '--overwrite-uids', '--ignore-errors']
    DICOMLib.DICOMCommand('dump2dcm', args).start()

    # now create the Secondary Capture data set
    # cmd = "img2dcm -k 'InstanceNumber=1' -k 'SeriesDescription=Slicer Data Bundle' -df %s/template.dcm %s %s" % (self.dicomDirectory, self.imageFile, self.sdbFile)
    args = [
        '-k', 'InstanceNumber=1',
        '-k', 'StudyDescription=Slicer Scene Export',
        '-k', 'SeriesDescription=Slicer Data Bundle',
        '--dataset-from', '%s/template.dcm' % self.dicomDirectory,
        self.imageFile, self.sdbFile]
    self.progress('Creating DICOM Binary File...')
    DICOMLib.DICOMCommand('img2dcm', args).start()
    self.progress('Done')
    return True
Example #31
0
    def open(self):

        # main dialog
        self.dialog = qt.QDialog(slicer.util.mainWindow())
        self.dialog.setWindowTitle('Export to DICOM Study')
        self.dialog.setWindowModality(1)
        layout = qt.QVBoxLayout()
        self.dialog.setLayout(layout)

        self.studyLabel = qt.QLabel('Attach Data to Study: %s' % self.studyUID)
        layout.addWidget(self.studyLabel)

        # scene or volume option
        self.selectFrame = qt.QFrame(self.dialog)
        layout.addWidget(self.selectFrame)
        self.selectLayout = qt.QGridLayout()
        self.selectFrame.setLayout(self.selectLayout)
        self.exportScene = qt.QRadioButton("Export Entire Scene",
                                           self.selectFrame)
        self.exportScene.setToolTip(
            "Create a Slicer Data Bundle in a DICOM Private Creator\n(Only compatible with Slicer)"
        )
        self.exportVolume = qt.QRadioButton("Export Selected Volume",
                                            self.selectFrame)
        self.exportVolume.setToolTip(
            "Create a compatible DICOM series of slice images")
        self.exportVolume.checked = True
        self.selectLayout.addWidget(self.exportScene, 0, 0)
        self.selectLayout.addWidget(self.exportVolume, 1, 0)
        self.exportScene.connect('toggled(bool)', self.onExportRadio)
        self.exportVolume.connect('toggled(bool)', self.onExportRadio)

        # select volume
        self.volumeSelector = slicer.qMRMLNodeComboBox(self.dialog)
        self.volumeSelector.nodeTypes = ("vtkMRMLScalarVolumeNode", "")
        self.volumeSelector.selectNodeUponCreation = False
        self.volumeSelector.addEnabled = False
        self.volumeSelector.noneEnabled = False
        self.volumeSelector.removeEnabled = False
        self.volumeSelector.showHidden = False
        self.volumeSelector.showChildNodeTypes = False
        self.volumeSelector.setMRMLScene(slicer.mrmlScene)
        self.volumeSelector.setToolTip("Pick the label map to edit")
        self.selectLayout.addWidget(self.volumeSelector, 1, 1)

        # DICOM Parameters
        self.dicomFrame = qt.QFrame(self.dialog)
        self.dicomFormLayout = qt.QFormLayout()
        self.dicomFrame.setLayout(self.dicomFormLayout)
        self.dicomEntries = {}
        exporter = DICOMLib.DICOMExporter(self.studyUID)
        self.dicomParameters = exporter.parametersFromStudy()
        self.dicomParameters['Series Description'] = '3D Slicer Export'
        for label in self.dicomParameters.keys():
            self.dicomEntries[label] = qt.QLineEdit()
            self.dicomEntries[label].text = self.dicomParameters[label]
            self.dicomFormLayout.addRow(label + ": ", self.dicomEntries[label])
        layout.addWidget(self.dicomFrame)

        # button box
        bbox = qt.QDialogButtonBox(self.dialog)
        bbox.addButton(bbox.Ok)
        bbox.addButton(bbox.Cancel)
        bbox.connect('accepted()', self.onOk)
        bbox.connect('rejected()', self.onCancel)
        layout.addWidget(bbox)

        self.dialog.open()
Example #32
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