def _downloadTestData(self):
   """ download DICOM PET scan and add to DICOM database
   """ 
   import urllib
   quantity = slicer.vtkCodedEntry()
   quantity.SetFromString('CodeValue:126400|CodingSchemeDesignator:DCM|CodeMeaning:Standardized Uptake Value')
   units = slicer.vtkCodedEntry()
   units.SetFromString('CodeValue:{SUVbw}g/ml|CodingSchemeDesignator:UCUM|CodeMeaning:Standardized Uptake Value body weight')      
   url = 'http://slicer.kitware.com/midas3/download/item/257234/QIN-HEADNECK-01-0139-PET.zip'
   zipFile = 'QIN-HEADNECK-01-0139-PET.zip'
   suvNormalizationFactor = 0.00040166400000000007
   destinationDirectory = self.tempDicomDatabase
   filePath = os.path.join(destinationDirectory, zipFile)
   # download dataset if necessary
   if not len(slicer.dicomDatabase.filesForSeries(self.UID)):
     filePath = os.path.join(destinationDirectory, zipFile)
     if not os.path.exists(os.path.dirname(filePath)):
       os.makedirs(os.path.dirname(filePath))
     logging.debug('Saving download %s to %s ' % (url, filePath))
     if not os.path.exists(filePath) or os.stat(filePath).st_size == 0:
       slicer.util.delayDisplay('Requesting download of %s...\n' % url, 1000)
       urllib.urlretrieve(url, filePath)
     if os.path.exists(filePath) and os.path.splitext(filePath)[1]=='.zip':
       success = slicer.app.applicationLogic().Unzip(filePath, destinationDirectory)
       if not success:
         logging.error("Archive %s was NOT unzipped successfully." %  filePath)
     indexer = ctk.ctkDICOMIndexer()
     indexer.addDirectory(slicer.dicomDatabase, destinationDirectory, None)
     indexer.waitForImportFinished()
 def importDirectory(self, inputDir):
   print('Input directory: %s' % inputDir)
   self.indexer = getattr(self, "indexer", None)
   if not self.indexer:
     self.indexer = ctk.ctkDICOMIndexer()
   self.indexer.addDirectory(self.dicomDatabase, inputDir)
   print('Import completed, total %s patients imported' % len(self.patients))
Exemple #3
0
    def importDICOMSeries(self, newFileList):
        indexer = ctk.ctkDICOMIndexer()

        newSeries = []
        for currentIndex, currentFile in enumerate(newFileList, start=1):
            self.invokeEvent(
                SlicerDevelopmentToolboxEvents.NewFileIndexedEvent, [
                    "Indexing file %s" % currentFile,
                    len(newFileList), currentIndex
                ].__str__())
            slicer.app.processEvents()
            currentFile = os.path.join(self.intraopDICOMDirectory, currentFile)
            indexer.addFile(slicer.dicomDatabase, currentFile, None)
            series = self.makeSeriesNumberDescription(currentFile)
            if series not in self.seriesList:
                self.seriesTimeStamps[series] = self.getTime()
                self.seriesList.append(series)
                newSeries.append(series)
                self.loadableList[
                    series] = self.createLoadableFileListForSeries(series)
        self.seriesList = sorted(
            self.seriesList,
            key=lambda s: RegistrationResult.getSeriesNumberFromString(s))

        if len(newFileList):
            self.verifyPatientIDEquality(newFileList)
            self.invokeEvent(self.NewImageSeriesReceivedEvent,
                             newSeries.__str__())
  def TestSection_02_LoadInputData(self):
    indexer = ctk.ctkDICOMIndexer()
    self.assertIsNotNone( indexer )

    # Import study to database
    indexer.addDirectory( slicer.dicomDatabase, self.dicomDataDir )
    indexer.waitForImportFinished()

    self.assertEqual( len(slicer.dicomDatabase.patients()), 1 )
    self.assertIsNotNone( slicer.dicomDatabase.patients()[0] )

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

    loadables = self.dicomWidget.detailsPopup.loadableTable.loadables
    self.assertTrue( len(loadables) > 0 )
    
    # Load into Slicer
    self.dicomWidget.detailsPopup.loadCheckedLoadables()
    self.inputSegmentationNode = slicer.util.getNode('vtkMRMLSegmentationNode1')
    self.assertIsNotNone(self.inputSegmentationNode)
    
    # Change master representation to closed surface (so that conversion is possible when adding segment)
    self.inputSegmentationNode.GetSegmentation().SetMasterRepresentationName(self.closedSurfaceReprName)
Exemple #5
0
def loadLoadables(loadablesByPlugin, messages=None, progressCallback=None):
  """Load each DICOM loadable item.
  Returns loaded node IDs.
  """

  # Find a plugin for each loadable that will load it
  # (the last plugin that has that loadable selected wins)
  selectedLoadables = {}
  for plugin in loadablesByPlugin:
    for loadable in loadablesByPlugin[plugin]:
      if loadable.selected:
        selectedLoadables[loadable] = plugin

  loadedNodeIDs = []

  @vtk.calldata_type(vtk.VTK_OBJECT)
  def onNodeAdded(caller, event, calldata):
    node = calldata
    if not isinstance(node, slicer.vtkMRMLStorageNode) and not isinstance(node, slicer.vtkMRMLDisplayNode):
      loadedNodeIDs.append(node.GetID())

  sceneObserverTag = slicer.mrmlScene.AddObserver(slicer.vtkMRMLScene.NodeAddedEvent, onNodeAdded)

  for step, (loadable, plugin) in enumerate(selectedLoadables.items(), start=1):
    if progressCallback:
      cancelled = progressCallback(loadable.name, step*100/len(selectedLoadables))
      if cancelled:
        break

    try:
      loadSuccess = plugin.load(loadable)
    except:
      loadSuccess = False
      import traceback
      logging.error("DICOM plugin failed to load '"
        + loadable.name + "' as a '" + plugin.loadType + "'.\n"
        + traceback.format_exc())
    if (not loadSuccess) and (messages is not None):
      messages.append('Could not load: %s as a %s' % (loadable.name, plugin.loadType))

    cancelled = False
    try:
      # DICOM reader plugins (for example, in PETDICOM extension) may generate additional DICOM files
      # during loading. These must be added to the database.
      for derivedItem in loadable.derivedItems:
        indexer = ctk.ctkDICOMIndexer()
        if progressCallback:
          cancelled = progressCallback("{0} ({1})".format(loadable.name, derivedItem), step*100/len(selectedLoadables))
          if cancelled:
            break
        indexer.addFile(slicer.dicomDatabase, derivedItem)
    except AttributeError:
      # no derived items or some other attribute error
      pass
    if cancelled:
      break

  slicer.mrmlScene.RemoveObserver(sceneObserverTag)

  return loadedNodeIDs
    def TestSection_02_LoadInputData(self):
        indexer = ctk.ctkDICOMIndexer()
        self.assertIsNotNone(indexer)

        # Import study to database
        indexer.addDirectory(slicer.dicomDatabase, self.dicomDataDir)
        indexer.waitForImportFinished()

        self.assertEqual(len(slicer.dicomDatabase.patients()), 1)
        self.assertIsNotNone(slicer.dicomDatabase.patients()[0])

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

        loadables = self.dicomWidget.detailsPopup.loadableTable.loadables
        self.assertTrue(len(loadables) > 0)

        # Load into Slicer
        self.dicomWidget.detailsPopup.loadCheckedLoadables()
        self.inputSegmentationNode = slicer.util.getNode(
            'vtkMRMLSegmentationNode1')
        self.assertIsNotNone(self.inputSegmentationNode)

        # Change master representation to closed surface (so that conversion is possible when adding segment)
        self.inputSegmentationNode.GetSegmentation(
        ).SetMasterRepresentationName(self.closedSurfaceReprName)
Exemple #7
0
    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 switchToDICOMModule(self):
   self.delayDisplay('Importing DICOM')
   mainWindow = slicer.util.mainWindow()
   mainWindow.moduleSelector().selectModule('DICOM')
   dicomFilesDirectory = slicer.app.temporaryPath + '/DICOMFilesDirectory'
   indexer = ctk.ctkDICOMIndexer()
   indexer.addDirectory(slicer.dicomDatabase, dicomFilesDirectory, None)
   indexer.waitForImportFinished()
Exemple #9
0
 def switchToDICOMModule(self):
     self.delayDisplay('Importing DICOM')
     mainWindow = slicer.util.mainWindow()
     mainWindow.moduleSelector().selectModule('DICOM')
     dicomFilesDirectory = slicer.app.temporaryPath + '/DICOMFilesDirectory'
     indexer = ctk.ctkDICOMIndexer()
     indexer.addDirectory(slicer.dicomDatabase, dicomFilesDirectory, None)
     indexer.waitForImportFinished()
  def section_LoadDicomData(self):
    try:
      # Download and unzip test CT DICOM data
      import urllib
      downloads = (
          ('http://slicer.kitware.com/midas3/download/item/137843/TestDicomCT.zip', self.dicomZipFilePath),
          )

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

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

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

      # Open test database and empty it
      with DICOMUtils.TemporaryDICOMDatabase(self.dicomDatabaseDir, True) as db:
        self.assertTrue( db.isOpen )
        self.assertEqual( slicer.dicomDatabase, db)

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

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

        self.assertEqual( len(slicer.dicomDatabase.patients()), 1 )
        self.assertIsNotNone( slicer.dicomDatabase.patients()[0] )

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

        patient = slicer.dicomDatabase.patients()[0]
        DICOMUtils.loadPatientByUID(patient)

        self.assertEqual( len( slicer.util.getNodes('vtkMRMLScalarVolumeNode*') ),  numOfScalarVolumeNodesBeforeLoad + 1 )
        self.assertEqual( len( slicer.util.getNodes('vtkMRMLSubjectHierarchyNode*') ), numOfSubjectHierarchyNodesBeforeLoad + 3 )
      
    except Exception, e:
      import traceback
      traceback.print_exc()
      self.delayDisplay('Test caused exception!\n' + str(e),self.delayMs*2)
  def section_LoadDicomData(self):
    try:
      # Download and unzip test CT DICOM data
      import urllib
      downloads = (
          ('http://slicer.kitware.com/midas3/download/item/137843/TestDicomCT.zip', self.dicomZipFilePath),
          )

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

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

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

      # Open test database and empty it
      with DICOMUtils.TemporaryDICOMDatabase(self.dicomDatabaseDir, True) as db:
        self.assertTrue( db.isOpen )
        self.assertEqual( slicer.dicomDatabase, db)

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

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

        self.assertEqual( len(slicer.dicomDatabase.patients()), 1 )
        self.assertIsNotNone( slicer.dicomDatabase.patients()[0] )

        # Load test data
        numOfScalarVolumeNodesBeforeLoad = len( slicer.util.getNodes('vtkMRMLScalarVolumeNode*') )
        self.assertEqual( len( slicer.util.getNodes('vtkMRMLSubjectHierarchyNode*') ), 1 )

        patient = slicer.dicomDatabase.patients()[0]
        DICOMUtils.loadPatientByUID(patient)

        self.assertEqual( len( slicer.util.getNodes('vtkMRMLScalarVolumeNode*') ),  numOfScalarVolumeNodesBeforeLoad + 1 )
        self.assertEqual( len( slicer.util.getNodes('vtkMRMLSubjectHierarchyNode*') ), 1 )

    except Exception, e:
      import traceback
      traceback.print_exc()
      self.delayDisplay('Test caused exception!\n' + str(e),self.delayMs*2)
 def addFilesToDatabase(self):
   self.progress('Adding to DICOM Database...')
   indexer = ctk.ctkDICOMIndexer()
   destinationDir = os.path.dirname(slicer.dicomDatabase.databaseFilename)
   if self.sdbFile:
     files = [self.sdbFile]
   else:
     files = glob.glob('%s/*' % self.dicomDirectory)
   for file in files:
     indexer.addFile( slicer.dicomDatabase, file, destinationDir )
     slicer.util.showStatusMessage("Loaded: %s" % file, 1000)
Exemple #13
0
 def addFilesToDatabase(self):
     self.progress('Adding to DICOM Database...')
     indexer = ctk.ctkDICOMIndexer()
     destinationDir = os.path.dirname(slicer.dicomDatabase.databaseFilename)
     if self.sdbFile:
         files = [self.sdbFile]
     else:
         files = glob.glob('%s/*' % self.dicomDirectory)
     for file in files:
         indexer.addFile(slicer.dicomDatabase, file, destinationDir)
         slicer.util.showStatusMessage("Loaded: %s" % file, 1000)
  def TestSection_2ImportStudy(self):
    self.delayDisplay("Import study",self.delayMs)

    indexer = ctk.ctkDICOMIndexer()
    self.assertIsNotNone( indexer )

    # Import study to database
    indexer.addDirectory( slicer.dicomDatabase, self.dataDir )
    indexer.waitForImportFinished()

    self.assertEqual( len(slicer.dicomDatabase.patients()), 1 )
    self.assertIsNotNone( slicer.dicomDatabase.patients()[0] )
Exemple #15
0
 def addFilesToDatabase(self):
   if not slicer.dicomDatabase.isOpen:
     slicer.util.warningDisplay("DICOM database is not open, so the (otherwise successfully) exported dataset cannot be imported back")
     return
   self.progress('Adding to DICOM Database...')
   indexer = ctk.ctkDICOMIndexer()
   destinationDir = os.path.dirname(slicer.dicomDatabase.databaseFilename)
   if self.sdbFile:
     files = [self.sdbFile]
   else:
     files = glob.glob('%s/*' % self.dicomDirectory)
   indexer.addListOfFiles( slicer.dicomDatabase, files, True)
    def TestSection_ImportStudy(self):
        # slicer.util.delayDisplay("Import study",self.delayMs)
        logging.info("Import study")

        indexer = ctk.ctkDICOMIndexer()
        self.assertIsNotNone(indexer)

        # Import study to database
        indexer.addDirectory(slicer.dicomDatabase, self.dataDir)
        indexer.waitForImportFinished()

        self.assertEqual(len(slicer.dicomDatabase.patients()), 1)
        self.assertIsNotNone(slicer.dicomDatabase.patients()[0])
Exemple #17
0
 def addFilesToDatabase(self):
   if not slicer.dicomDatabase:
     slicer.util.warningDisplay("No DICOM database is set, so the (otherwise successfully) exported dataset cannot be imported back")
     return
   self.progress('Adding to DICOM Database...')
   indexer = ctk.ctkDICOMIndexer()
   destinationDir = os.path.dirname(slicer.dicomDatabase.databaseFilename)
   if self.sdbFile:
     files = [self.sdbFile]
   else:
     files = glob.glob('%s/*' % self.dicomDirectory)
   for file in files:
     indexer.addFile( slicer.dicomDatabase, file, destinationDir )
 def importStudy(self, inputDir, progressCallback=None):
   self.progressCallback = progressCallback
   self.canceled = False
   print('Database location: '+self.dicomDatabaseDir)
   print('FIXME: revert back to the original DB location when done!')
   self.openDatabase()
   print('Input directory: ' + inputDir)
   if not self.indexer:
     self.indexer = ctk.ctkDICOMIndexer()
     self.indexer.connect("progress(int)", self.updateProgress)
   self.indexer.addDirectory(slicer.dicomDatabase, inputDir)
   self.patients = slicer.dicomDatabase.patients()
   print('Import completed, total '+str(len(slicer.dicomDatabase.patients()))+' patients imported')
  def _importStudy(self, inputDir, progressCallback=None):
    self.progressCallback = progressCallback
    logging.debug('Input directory: %s' % inputDir)
    self.indexer = getattr(self, "indexer", None)
    if not self.indexer:
      self.indexer = ctk.ctkDICOMIndexer()

      def updateProgress(progress):
        if self.progressCallback:
          self.progressCallback(windowTitle='DICOMIndexer', labelText='Processing files', value=progress)
      self.indexer.connect("progress(int)", updateProgress)
    self.indexer.addDirectory(self.dicomDatabase, inputDir)
    logging.debug('Import completed, total %s patients imported' % len(self.patients))
Exemple #20
0
  def __init__(self, database, fileToBeAddedCallback=None, fileAddedCallback=None):
    self.dicomDatabase = database
    self.indexer = ctk.ctkDICOMIndexer()
    self.fileToBeAddedCallback = fileToBeAddedCallback
    self.fileAddedCallback = fileAddedCallback
    self.lastFileAdded = None

    settings = qt.QSettings()
    databaseDirectory = settings.value('DatabaseDirectory')
    if not databaseDirectory:
      raise UserWarning('Database directory not set: cannot start DICOMListener')
    if not os.path.exists(databaseDirectory):
      os.mkdir(databaseDirectory)
    incomingDir = databaseDirectory + "/incoming"
    super(DICOMListener,self).__init__(incomingDataDir=incomingDir)
 def saveReport(self, completed=False):
   self._metadata = self.retrieveMetaDataFromUser()
   if not self._metadata:
     return False, "Saving process canceled. Meta-information was not confirmed by user."
   try:
     dcmSegPath = self.createSEG()
     dcmSRPath = self.createDICOMSR(dcmSegPath, completed)
     if dcmSegPath and dcmSRPath:
       indexer = ctk.ctkDICOMIndexer()
       indexer.addFile(slicer.dicomDatabase, dcmSegPath, "copy")
       indexer.addFile(slicer.dicomDatabase, dcmSRPath, "copy")
   except (RuntimeError, ValueError, AttributeError) as exc:
     return False, exc.message
   finally:
     self.cleanupTemporaryData()
   return True, None
Exemple #22
0
 def saveReport(self, completed=False):
   self._metadata = self.retrieveMetaDataFromUser()
   if not self._metadata:
     return False, "Saving process canceled. Meta-information was not confirmed by user."
   try:
     dcmSegPath = self.createSEG()
     dcmSRPath = self.createDICOMSR(dcmSegPath, completed)
     if dcmSegPath and dcmSRPath:
       indexer = ctk.ctkDICOMIndexer()
       indexer.addFile(slicer.dicomDatabase, dcmSegPath, "copy")
       indexer.addFile(slicer.dicomDatabase, dcmSRPath, "copy")
   except (RuntimeError, ValueError, AttributeError) as exc:
     return False, exc.args
   finally:
     self.cleanupTemporaryData()
   return True, None
Exemple #23
0
def importDicom(dicomDataDir, dicomDatabase=None, copyFiles=False):
  """ Import DICOM files from folder into Slicer database
  """
  try:
    indexer = ctk.ctkDICOMIndexer()
    assert indexer is not None
    if dicomDatabase is None:
      dicomDatabase = slicer.dicomDatabase
    indexer.addDirectory(dicomDatabase, dicomDataDir, copyFiles)
    indexer.waitForImportFinished()
  except Exception as e:
    import traceback
    traceback.print_exc()
    logging.error('Failed to import DICOM folder ' + dicomDataDir)
    return False
  return True
Exemple #24
0
def importDicom(dicomDataDir, dicomDatabase=None):
    """ Import DICOM files from folder into Slicer database
  """
    try:
        slicer.util.selectModule('DICOM')

        dicomWidget = slicer.modules.dicom.widgetRepresentation().self()
        indexer = ctk.ctkDICOMIndexer()
        assert indexer is not None

        indexer.addDirectory(slicer.dicomDatabase, dicomDataDir)
        indexer.waitForImportFinished()
    except Exception, e:
        import traceback
        traceback.print_exc()
        logging.error('Failed to import DICOM folder ' + dicomDataDir)
        return False
Exemple #25
0
    def _importStudy(self, inputDir, progressCallback=None):
        self.progressCallback = progressCallback
        logging.debug('Input directory: %s' % inputDir)
        self.indexer = getattr(self, "indexer", None)
        if not self.indexer:
            self.indexer = ctk.ctkDICOMIndexer()

            def updateProgress(progress):
                if self.progressCallback:
                    self.progressCallback(windowTitle='DICOMIndexer',
                                          labelText='Processing files',
                                          value=progress)

            self.indexer.connect("progress(int)", updateProgress)
        self.indexer.addDirectory(self.dicomDatabase, inputDir)
        logging.debug('Import completed, total %s patients imported' %
                      len(self.patients))
Exemple #26
0
    def __init__(self,
                 database,
                 fileToBeAddedCallback=None,
                 fileAddedCallback=None):
        self.dicomDatabase = database
        self.indexer = ctk.ctkDICOMIndexer()
        self.fileToBeAddedCallback = fileToBeAddedCallback
        self.fileAddedCallback = fileAddedCallback
        self.lastFileAdded = None

        databaseDirectory = self.dicomDatabase.databaseDirectory
        if not databaseDirectory:
            raise UserWarning(
                'Database directory not set: cannot start DICOMListener')
        if not os.path.exists(databaseDirectory):
            os.mkdir(databaseDirectory)
        incomingDir = databaseDirectory + "/incoming"
        super(DICOMListener, self).__init__(incomingDataDir=incomingDir)
Exemple #27
0
def importDicom(dicomDataDir, dicomDatabase=None):
  """ Import DICOM files from folder into Slicer database
  """
  try:
    slicer.util.selectModule('DICOM')

    dicomWidget = slicer.modules.dicom.widgetRepresentation().self()
    indexer = ctk.ctkDICOMIndexer()
    assert indexer is not None

    if dicomDatabase is None:
      dicomDatabase = slicer.dicomDatabase
    indexer.addDirectory( dicomDatabase, dicomDataDir )
    indexer.waitForImportFinished()
  except Exception, e:
    import traceback
    traceback.print_exc()
    logging.error('Failed to import DICOM folder ' + dicomDataDir)
    return False
Exemple #28
0
    def __init__(self,
                 database,
                 fileToBeAddedCallback=None,
                 fileAddedCallback=None):
        self.dicomDatabase = database
        self.indexer = ctk.ctkDICOMIndexer()
        # Enable background indexing to improve performance.
        self.indexer.backgroundImportEnabled = True
        self.fileToBeAddedCallback = fileToBeAddedCallback
        self.fileAddedCallback = fileAddedCallback
        self.lastFileAdded = None

        # A timer is used to ensure that indexing is completed after new files come in,
        # but without enforcing completing the indexing after each file (because
        # waiting for indexing to be completed has an overhead).
        autoUpdateDelaySec = 10.0
        self.delayedAutoUpdateTimer = qt.QTimer()
        self.delayedAutoUpdateTimer.setSingleShot(True)
        self.delayedAutoUpdateTimer.interval = autoUpdateDelaySec * 1000
        self.delayedAutoUpdateTimer.connect('timeout()',
                                            self.completeIncomingFilesIndexing)

        # List of received files that are being indexed
        self.incomingFiles = []
        # After self.incomingFiles reaches maximumIncomingFiles, indexing will be forced
        # to limit disk space usage (until indexing is completed, the file is present both
        # in the incoming folder and in the database) and make sure some updates are visible
        # in the DICOM browser (even if files are continuously coming in).
        # Smaller values result in more frequent updates, slightly less disk space usage,
        # slightly slower import.
        self.maximumIncomingFiles = 400

        databaseDirectory = self.dicomDatabase.databaseDirectory
        if not databaseDirectory:
            raise UserWarning(
                'Database directory not set: cannot start DICOMListener')
        if not os.path.exists(databaseDirectory):
            os.mkdir(databaseDirectory)
        incomingDir = databaseDirectory + "/incoming"
        super().__init__(incomingDataDir=incomingDir)
    def generateReport(self, obj):
        """ Generates a qiicrx DICOM report from an existing studyID and adds resulting series to DICOMDatabase

    Args:
      obj: studyID or list of series UIDs that is used as the input for creating a qiicrx DICOM report

    Todo:
      add option to add predecessor
    """
        if type(obj) is str:
            seriesUIDs = DICOMQIICRXLoaderPluginClass.getEligibleSeriesForStudy(
                obj)
            if not seriesUIDs:
                raise StudyNotEligibleError
        elif type(obj) in [tuple, list]:
            seriesUIDs = obj
        else:
            raise ValueError("Value of type %s is not supported" % type(obj))

        try:
            params = self._generateJSON(seriesUIDs)
        except StudyNotEligibleError:
            logging.error("Series '%s' is not eligible for PIRADS reading" %
                          seriesUIDs)
            return

        outputSRPath = os.path.join(self.tempDir, "sr.dcm")
        params.update({"outputFileName": outputSRPath})

        logging.debug(params)
        cliNode = slicer.cli.run(slicer.modules.qiicrxsr,
                                 None,
                                 params,
                                 wait_for_completion=True)

        if cliNode.GetStatusString() != 'Completed':
            raise Exception("qiicrxsr CLI did not complete cleanly")
        else:
            indexer = ctk.ctkDICOMIndexer()
            indexer.addFile(self.db, outputSRPath, "copy")
Exemple #30
0
  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')
  def _loadTestData_WithPETDICOMExtension(self):
    """ load SUV normalized PET scan from DICOM fileassuming Slicer-PETDICOM extension is installed and enabled
    """
    from DICOMLib import DICOMUtils
    import urllib
    data = {
      'PETVolume': {
        'UID': '1.3.6.1.4.1.14519.5.2.1.2744.7002.886851941687931416391879144903',
        'url': 'http://slicer.kitware.com/midas3/download/item/257234/QIN-HEADNECK-01-0139-PET.zip',
        'zipFile': 'QIN-HEADNECK-01-0139-PET.zip',
        'SUVNormalizationFactor': 0.00040166400000000007
      }
    }
    destinationDirectory = self.tempDataDir
    for key, value in data.iteritems(): # download data if necessary
      UID = value['UID']
      if not len(slicer.dicomDatabase.filesForSeries(UID)):
        url = value['url']
        zipFile = value['zipFile']
        filePath = os.path.join(destinationDirectory, zipFile)
        if not os.path.exists(os.path.dirname(filePath)):
          os.makedirs(os.path.dirname(filePath))
        logging.debug('Saving download %s to %s ' % (url, filePath))
        if not os.path.exists(filePath) or os.stat(filePath).st_size == 0:
          slicer.util.delayDisplay('Requesting download of %s...\n' % url, 1000)
          urllib.urlretrieve(url, filePath)
        if os.path.exists(filePath) and os.path.splitext(filePath)[1]=='.zip':
          success = slicer.app.applicationLogic().Unzip(filePath, destinationDirectory)
          if not success:
            logging.error("Archive %s was NOT unzipped successfully." %  filePath)
      indexer = ctk.ctkDICOMIndexer()
      indexer.addDirectory(slicer.dicomDatabase, destinationDirectory, None)
      indexer.waitForImportFinished()
    # load dataset
    success=DICOMUtils.loadSeriesByUID([data['PETVolume']['UID']])
    if not success:
      logging.error("Unable to load dicom data %s\n." %  data['PETVolume']['UID'])

    return slicer.mrmlScene.GetFirstNodeByClass('vtkMRMLScalarVolumeNode')
Exemple #32
0
 def importIntoDICOMDatabase(dicomFilesDirectory):
   indexer = ctk.ctkDICOMIndexer()
   indexer.addDirectory(slicer.dicomDatabase, dicomFilesDirectory, None)
   indexer.waitForImportFinished()
Exemple #33
0
  def test_Part1DICOM(self,enableScreenshotsFlag=0,screenshotScaleFactor=1):
    """ Test the DICOM part of the test using the head atlas
    """

    logic = RSNAVisTutorialLogic()
    logic.enableScreenshots = enableScreenshotsFlag
    logic.screenshotScaleFactor = screenshotScaleFactor

    import os
    self.delayDisplay("Starting the DICOM test")
    #
    # first, get the data - a zip file of dicom data
    #
    import SampleData
    dicomFilesDirectory = SampleData.downloadFromURL(
      fileNames='dataset1_Thorax_Abdomen.zip',
      uris='http://slicer.kitware.com/midas3/download?items=124183')[0]

    try:
      self.delayDisplay("Switching to temp database directory")
      originalDatabaseDirectory = DICOMUtils.openTemporaryDatabase('tempDICOMDatabase')

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

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

      dicomWidget = slicer.modules.DICOMWidget
      dicomWidget.detailsPopup.open()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

      self.delayDisplay('Test passed!')
    except Exception as e:
      import traceback
      traceback.print_exc()
      self.delayDisplay('Test caused exception!\n' + str(e))

    self.delayDisplay("Restoring original database directory")
    DICOMUtils.closeTemporaryDatabase(originalDatabaseDirectory)
Exemple #34
0
  def proceedWithReferencedLoadablesSelection(self):
    # each check box corresponds to a referenced loadable
    # that was selected by examine; if the user confirmed
    # that reference should be loaded, add it to the self.loadablesByPlugin
    # dictionary
    if self.referencesDialog:
      children = self.referencesDialog.children()
      loadableCnt = 0
      for plugin in self.referencedLoadables:
        for loadable in self.referencedLoadables[plugin]:
          if loadable.selected:
            if children[loadableCnt+2].checked:
              self.loadablesByPlugin[plugin].append(loadable)

      self.referencesDialog.close()
      self.referencesDialog = None

    loadableCount = 0
    for plugin in self.loadablesByPlugin:
      for loadable in self.loadablesByPlugin[plugin]:
        if loadable.selected:
          loadableCount += 1
    self.progress = slicer.util.createProgressDialog(parent=self.window, value=0, maximum=loadableCount)
    step = 0
    loadingResult = ''

    loadedNodeIDs = []

    @vtk.calldata_type(vtk.VTK_OBJECT)
    def onNodeAdded(caller, event, calldata):
      node = calldata
      if isinstance(node, slicer.vtkMRMLVolumeNode):
        loadedNodeIDs.append(node.GetID())

    self.addObserver(slicer.mrmlScene, slicer.vtkMRMLScene.NodeAddedEvent, onNodeAdded);

    for plugin in self.loadablesByPlugin:
      for loadable in self.loadablesByPlugin[plugin]:
        if self.progress.wasCanceled:
          break
        slicer.app.processEvents()
        self.progress.setValue(step)
        slicer.app.processEvents()
        if loadable.selected:
          self.progress.labelText = '\nLoading %s' % loadable.name
          slicer.app.processEvents()
          if not plugin.load(loadable):
            loadingResult = '%s\nCould not load: %s as a %s' % (loadingResult,loadable.name,plugin.loadType)
          step += 1
          self.progress.setValue(step)
          slicer.app.processEvents()
        try:
          for derivedItem in loadable.derivedItems:
            indexer = ctk.ctkDICOMIndexer()
            self.progress.labelText = '\nIndexing %s' % derivedItem
            slicer.app.processEvents()
            indexer.addFile(slicer.dicomDatabase, derivedItem)
        except AttributeError:
          # no derived items or some other attribute error
          pass

    self.removeObserver(slicer.mrmlScene, slicer.vtkMRMLScene.NodeAddedEvent, onNodeAdded);

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

    self.progress.close()
    self.progress = None
    if loadingResult:
      slicer.util.warningDisplay(loadingResult, windowTitle='DICOM loading')
    if not self.browserPersistent:
      self.close()

    return
Exemple #35
0
  def test_SEGExporterSelfTest1(self):
    """ Test DICOM import, segmentation, export
    """
    self.messageDelay = 50

    import os
    self.delayDisplay("Starting the DICOM SEG Export test")

    #
    # first, get the data - a zip file of dicom data
    #
    filePath = self.logic.downloadSampleData()
    self.delayDisplay('Finished with download\n')

    self.delayDisplay("Unzipping")
    dicomFilesDirectory = self.logic.unzipSampleData(filePath)

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

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

      self.logic.importIntoDICOMDatabase(dicomFilesDirectory)

      dicomWidget.detailsPopup.open()

      # load the data by series UID
      mrHeadSeriesUID = "2.16.840.1.113662.4.4168496325.1025306170.548651188813145058"
      dicomWidget.detailsPopup.offerLoadables(mrHeadSeriesUID, 'Series')
      dicomWidget.detailsPopup.examineForLoading()
      self.delayDisplay('Loading Selection')
      dicomWidget.detailsPopup.loadCheckedLoadables()

      #
      # create a label map and set it for editing
      #
      masterNode = slicer.util.getNode('2: SAG*')
      volumesLogic = slicer.modules.volumes.logic()
      mergeNode = volumesLogic.CreateAndAddLabelVolume( slicer.mrmlScene, masterNode, masterNode.GetName() + '-label' )
      mergeNode.GetDisplayNode().SetAndObserveColorNodeID('vtkMRMLColorTableNodeFileGenericAnatomyColors.txt')
      selectionNode = slicer.app.applicationLogic().GetSelectionNode()
      selectionNode.SetReferenceActiveVolumeID( masterNode.GetID() )
      selectionNode.SetReferenceActiveLabelVolumeID( mergeNode.GetID() )
      slicer.app.applicationLogic().PropagateVolumeSelection(0)

      #
      # go to the editor and do some drawing
      #
      slicer.util.selectModule('Editor')

      import EditorLib
      from EditorLib.EditUtil import EditUtil
      parameterNode = EditUtil.getParameterNode()
      parameterNode.SetParameter("LabelEffect,paintThreshold", "1")
      parameterNode.SetParameter("LabelEffect,paintThresholdMin", "70.0")
      parameterNode.SetParameter("LabelEffect,paintThresholdMax", "279.75")
      parameterNode.SetParameter("PaintEffect,radius", "40")
      parameterNode.SetParameter("PaintEffect,sphere", "1")

      self.delayDisplay("Paint some things")
      parameterNode = EditUtil.getParameterNode()
      lm = slicer.app.layoutManager()
      paintEffect = EditorLib.PaintEffectOptions()
      paintEffect.setMRMLDefaults()
      paintEffect.__del__()
      sliceWidget = lm.sliceWidget('Red')
      paintTool = EditorLib.PaintEffectTool(sliceWidget)
      EditUtil.setLabel(1)
      paintTool.paintAddPoint(100,100)
      paintTool.paintApply()
      EditUtil.setLabel(2)
      paintTool.paintAddPoint(200,200)
      paintTool.paintApply()
      paintTool.cleanup()
      paintTool = None

      # save these to compare with the one we read back
      originalSegmentationArray = slicer.util.array(mergeNode.GetID())
      originalSegmentationNodeCopy = slicer.vtkMRMLLabelMapVolumeNode()
      originalSegmentationNodeCopy.CopyOrientation(mergeNode)

      # export the volumes into a SEG
      tempSEGDirectory = slicer.app.temporaryPath + '/tempDICOMSEG'
      qt.QDir().mkpath(tempSEGDirectory)
      segFilePath = os.path.join(tempSEGDirectory, "test.SEG.dcm")


      self.delayDisplay('spliting...', 200)
      EditUtil.splitPerStructureVolumes(masterNode, mergeNode)

      self.delayDisplay('exporting...', 200)
      EditUtil.exportAsDICOMSEG(masterNode)

      # close scene re-load the input data and SEG
      slicer.mrmlScene.Clear(0)
      indexer = ctk.ctkDICOMIndexer()
      indexer.addDirectory(slicer.dicomDatabase, tempSEGDirectory, None)
      indexer.waitForImportFinished()

      mrHeadStudyUID = "2.16.840.1.113662.4.4168496325.1025305873.7118351817185979330"
      dicomWidget.detailsPopup.offerLoadables(mrHeadStudyUID, 'Study')
      dicomWidget.detailsPopup.examineForLoading()
      self.delayDisplay('Loading Selection')
      dicomWidget.detailsPopup.loadCheckedLoadables()

      # confirm that segmentations are correctly reloaded
      headLabelName = '2: SAG/RF-FAST/VOL/FLIP 30-label'
      reloadedLabel = slicer.util.getNode(headLabelName)
      reloadedSegmentationArray = slicer.util.array(reloadedLabel.GetID())

      import numpy
      self.assertTrue(numpy.alltrue(originalSegmentationArray == reloadedSegmentationArray))
      geometryWarnings = volumesLogic.CompareVolumeGeometry(mergeNode, reloadedLabel)
      print(geometryWarnings)
      self.assertTrue(geometryWarnings == '')

      # re-export

      # close scene re-load the input data and SEG

      # confirm that segmentations are available again as per-structure volumes


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

    self.enableScreenshots = enableScreenshotsFlag
    self.screenshotScaleFactor = screenshotScaleFactor

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

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

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

    try:
      self.delayDisplay("Switching to temp database directory")
      originalDatabaseDirectory = DICOMUtils.openTemporaryDatabase('tempDICOMDatabase')

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

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

      dicomWidget = slicer.modules.DICOMWidget
      dicomWidget.detailsPopup.open()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

      self.delayDisplay('Test passed!')
    except Exception, e:
      import traceback
      traceback.print_exc()
      self.delayDisplay('Test caused exception!\n' + str(e))
Exemple #37
0
    def test_AlternateReaders(self):
        """ Test the DICOM loading of sample testing data
    """
        testPass = True
        import os, json
        self.delayDisplay("Starting the DICOM test")

        referenceData = [{
            "url": "http://slicer.kitware.com/midas3/download?items=292839",
            "fileName": "Mouse-MR-example-where-GDCM_fails.zip",
            "name": "Mouse-MR-example-where-GDCM_fails",
            "seriesUID":
            "1.3.6.1.4.1.9590.100.1.2.366426457713813178933224342280246227461",
            "expectedFailures": ["GDCM", "Archetype"],
            "voxelValueQuantity": "(110852, DCM, \"MR signal intensity\")",
            "voxelValueUnits": "(1, UCUM, \"no units\")"
        }, {
            "url": "http://slicer.kitware.com/midas3/download?items=294857",
            "fileName": "deidentifiedMRHead-dcm-one-series.zip",
            "name": "deidentifiedMRHead-dcm-one-series",
            "seriesUID":
            "1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.270.0",
            "expectedFailures": [],
            "voxelValueQuantity": "(110852, DCM, \"MR signal intensity\")",
            "voxelValueUnits": "(1, UCUM, \"no units\")"
        }]

        # another dataset that could be added in the future - currently fails for all readers
        # due to invalid format - see https://issues.slicer.org/view.php?id=3569
        #{ "url": "http://slicer.kitware.com/midas3/download/item/293587/RIDER_bug.zip",
        #"fileName": "RIDER_bug.zip",
        #"name": "RIDER_bug",
        #"seriesUID": "1.3.6.1.4.1.9328.50.7.261772317324041365541450388603508531852",
        #"expectedFailures": []
        #}

        loadingResult = {}
        #
        # first, get the data - a zip file of dicom data
        #
        self.delayDisplay("Downloading")
        for dataset in referenceData:
            try:
                import SampleData
                dicomFilesDirectory = SampleData.downloadFromURL(
                    fileNames=dataset['fileName'], uris=dataset['url'])[0]
                self.delayDisplay('Finished with download')

                #
                # insert the data into th database
                #
                self.delayDisplay("Switching to temp database directory")
                originalDatabaseDirectory = DICOMUtils.openTemporaryDatabase(
                    'tempDICOMDatabase')

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

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

                #
                # select the series
                #
                detailsPopup = slicer.modules.DICOMWidget.detailsPopup
                detailsPopup.open()
                # load the data by series UID
                detailsPopup.offerLoadables(dataset['seriesUID'], 'Series')
                detailsPopup.examineForLoading()
                loadable = detailsPopup.getAllSelectedLoadables().keys()[0]

                #
                # try loading using each of the selected readers, fail
                # on enexpected load issue
                #
                scalarVolumePlugin = slicer.modules.dicomPlugins[
                    'DICOMScalarVolumePlugin']()
                readerApproaches = scalarVolumePlugin.readerApproaches()
                basename = loadable.name
                volumesByApproach = {}
                for readerApproach in readerApproaches:
                    self.delayDisplay('Loading Selection with approach: %s' %
                                      readerApproach)
                    loadable.name = basename + "-" + readerApproach
                    volumeNode = scalarVolumePlugin.load(
                        loadable, readerApproach)
                    if not volumeNode and readerApproach not in dataset[
                            'expectedFailures']:
                        raise Exception(
                            "Expected to be able to read with %s, but couldn't"
                            % readerApproach)
                    if volumeNode and readerApproach in dataset[
                            'expectedFailures']:
                        raise Exception(
                            "Expected to NOT be able to read with %s, but could!"
                            % readerApproach)
                    if volumeNode:
                        volumesByApproach[readerApproach] = volumeNode

                        self.delayDisplay('Test quantity and unit')
                        if 'voxelValueQuantity' in dataset.keys():
                            self.assertEqual(
                                volumeNode.GetVoxelValueQuantity(
                                ).GetAsPrintableString(),
                                dataset['voxelValueQuantity'])
                        if 'voxelValueUnits' in dataset.keys():
                            self.assertEqual(
                                volumeNode.GetVoxelValueUnits(
                                ).GetAsPrintableString(),
                                dataset['voxelValueUnits'])

                #
                # for each approach that loaded as expected, compare the volumes
                # to ensure they match in terms of pixel data and metadata
                #
                failedComparisons = {}
                approachesThatLoaded = volumesByApproach.keys()
                print('approachesThatLoaded %s' % approachesThatLoaded)
                for approachIndex in range(len(approachesThatLoaded)):
                    firstApproach = approachesThatLoaded[approachIndex]
                    firstVolume = volumesByApproach[firstApproach]
                    for secondApproachIndex in range(
                            approachIndex + 1, len(approachesThatLoaded)):
                        secondApproach = approachesThatLoaded[
                            secondApproachIndex]
                        secondVolume = volumesByApproach[secondApproach]
                        print('comparing  %s,%s' %
                              (firstApproach, secondApproach))
                        comparison = slicer.modules.dicomPlugins[
                            'DICOMScalarVolumePlugin'].compareVolumeNodes(
                                firstVolume, secondVolume)
                        if comparison != "":
                            print('failed: %s', comparison)
                            failedComparisons[firstApproach,
                                              secondApproach] = comparison

                if len(failedComparisons.keys()) > 0:
                    raise Exception("Loaded volumes don't match: %s" %
                                    failedComparisons)

                self.delayDisplay('%s Test passed!' % dataset['name'])

            except Exception, e:
                import traceback
                traceback.print_exc()
                self.delayDisplay('%s Test caused exception!\n' %
                                  dataset['name'] + str(e))
                testPass = False
Exemple #38
0
 def importIntoDICOMDatabase(dicomFilesDirectory):
   indexer = ctk.ctkDICOMIndexer()
   indexer.addDirectory(slicer.dicomDatabase, dicomFilesDirectory, None)
   indexer.waitForImportFinished()
Exemple #39
0
  def test_Part1DICOM(self):
    """ Test the DICOM loading of sample testing data
    """
    testPass = True
    import os, json
    self.delayDisplay("Starting the DICOM test", 100)

    referenceData = json.JSONDecoder().decode('''[
      { "url": "http://slicer.kitware.com/midas3/download/item/292839/Mouse-MR-example-where-GDCM_fails.zip",
        "fileName": "Mouse-MR-example-where-GDCM_fails.zip",
        "name": "Mouse-MR-example-where-GDCM_fails",
        "seriesUID": "1.3.6.1.4.1.9590.100.1.2.366426457713813178933224342280246227461",
        "expectedFailures": ["GDCM", "Archetype"]
      },
      { "url": "http://slicer.kitware.com/midas3/download/item/294857/deidentifiedMRHead-dcm-one-series.zip",
        "fileName": "deidentifiedMRHead-dcm-one-series.zip",
        "name": "deidentifiedMRHead-dcm-one-series",
        "seriesUID": "1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.270.0",
        "expectedFailures": []
      }
    ]''') 

    # another dataset that could be added in the future - currently fails for all readers
    # due to invalid format - see https://issues.slicer.org/view.php?id=3569
      #{ "url": "http://slicer.kitware.com/midas3/download/item/293587/RIDER_bug.zip",
        #"fileName": "RIDER_bug.zip",
        #"name": "RIDER_bug",
        #"seriesUID": "1.3.6.1.4.1.9328.50.7.261772317324041365541450388603508531852",
        #"expectedFailures": []
      #}

    loadingResult = {}
    #
    # first, get the data - a zip file of dicom data
    #
    self.delayDisplay("Downloading", 100)
    for dataset in referenceData:
      try:
        filePath = slicer.app.temporaryPath + '/' + dataset['fileName']
        if not os.path.exists(filePath) or os.stat(filePath).st_size == 0:
          self.delayDisplay('Requesting download %s from %s...\n' % (dataset['fileName'], dataset['url']), 100)
          urllib.urlretrieve(dataset['url'], filePath)
        self.delayDisplay('Finished with download\n', 100)

        self.delayDisplay("Unzipping", 100)
        dicomFilesDirectory = slicer.app.temporaryPath + dataset['name']
        qt.QDir().mkpath(dicomFilesDirectory)
        slicer.app.applicationLogic().Unzip(filePath, dicomFilesDirectory)

        #
        # insert the data into th database
        #
        self.delayDisplay("Switching to temp database directory", 100)
        originalDatabaseDirectory = DICOMUtils.openTemporaryDatabase('tempDICOMDatabase')

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

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

        #
        # selct the series
        #
        detailsPopup = slicer.modules.DICOMWidget.detailsPopup
        detailsPopup.open()
        # load the data by series UID
        detailsPopup.offerLoadables(dataset['seriesUID'],'Series')
        detailsPopup.examineForLoading()
        loadable = detailsPopup.getAllSelectedLoadables().keys()[0]

        #
        # try loading using each of the selected readers, fail 
        # on enexpected load issue
        #
        scalarVolumePlugin = slicer.modules.dicomPlugins['DICOMScalarVolumePlugin']()
        readerApproaches = scalarVolumePlugin.readerApproaches()   
        basename = loadable.name
        volumesByApproach = {}
        for readerApproach in readerApproaches:
          self.delayDisplay('Loading Selection with approach: %s' % readerApproach, 100)
          loadable.name = basename + "-" + readerApproach
          volumeNode = scalarVolumePlugin.load(loadable,readerApproach)
          if not volumeNode and readerApproach not in dataset['expectedFailures']:
            raise Exception("Expected to be able to read with %s, but couldn't" % readerApproach)
          if volumeNode and readerApproach in dataset['expectedFailures']:
            raise Exception("Expected to NOT be able to read with %s, but could!" % readerApproach)
          if volumeNode:
            volumesByApproach[readerApproach] = volumeNode

        #
        # for each approach that loaded as expected, compare the volumes
        # to ensure they match in terms of pixel data and metadata
        #
        failedComparisons = {}
        approachesThatLoaded = volumesByApproach.keys()
        print('approachesThatLoaded %s' % approachesThatLoaded)
        for approachIndex in range(len(approachesThatLoaded)):
          firstApproach = approachesThatLoaded[approachIndex]
          firstVolume = volumesByApproach[firstApproach]
          for secondApproachIndex in range(approachIndex+1,len(approachesThatLoaded)):
            secondApproach = approachesThatLoaded[secondApproachIndex]
            secondVolume = volumesByApproach[secondApproach]
            print('comparing  %s,%s' % (firstApproach, secondApproach))
            comparison = slicer.modules.dicomPlugins['DICOMScalarVolumePlugin'].compareVolumeNodes(firstVolume,secondVolume)
            if comparison != "":
              print('failed: %s', comparison)
              failedComparisons[firstApproach,secondApproach] = comparison

        if len(failedComparisons.keys()) > 0:
          raise Exception("Loaded volumes don't match: %s" % failedComparisons)

        self.delayDisplay('%s Test passed!' % dataset['name'], 200)

      except Exception, e:
        import traceback
        traceback.print_exc()
        self.delayDisplay('%s Test caused exception!\n' % dataset['name'] + str(e), 2000)
        testPass = False
 def importStudy(dicomDataDir):
     indexer = ctk.ctkDICOMIndexer()
     indexer.addDirectory(slicer.dicomDatabase, dicomDataDir)
     indexer.waitForImportFinished()
Exemple #41
0
    def test_SEGExporterSelfTest1(self):
        """ Test DICOM import, segmentation, export
    """
        self.messageDelay = 50

        import os
        self.delayDisplay("Starting the DICOM SEG Export test")

        #
        # first, get the data - a zip file of dicom data
        #
        import urllib
        downloads = ((
            'http://slicer.kitware.com/midas3/download/item/220834/PieperMRHead.zip',
            'PieperMRHead.zip'), )
        self.delayDisplay("Downloading")
        for url, name in downloads:
            filePath = slicer.app.temporaryPath + '/' + name
            if not os.path.exists(filePath) or os.stat(filePath).st_size == 0:
                self.delayDisplay('Requesting download %s from %s...\n' %
                                  (name, url))
                urllib.urlretrieve(url, filePath)
        self.delayDisplay('Finished with download\n')

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

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

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

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

            dicomWidget.detailsPopup.open()

            # load the data by series UID
            mrHeadSeriesUID = "2.16.840.1.113662.4.4168496325.1025306170.548651188813145058"
            dicomWidget.detailsPopup.offerLoadables(mrHeadSeriesUID, 'Series')
            dicomWidget.detailsPopup.examineForLoading()
            self.delayDisplay('Loading Selection')
            dicomWidget.detailsPopup.loadCheckedLoadables()

            #
            # create a label map and set it for editing
            #
            masterNode = slicer.util.getNode('2: SAG*')
            volumesLogic = slicer.modules.volumes.logic()
            mergeNode = volumesLogic.CreateAndAddLabelVolume(
                slicer.mrmlScene, masterNode,
                masterNode.GetName() + '-label')
            mergeNode.GetDisplayNode().SetAndObserveColorNodeID(
                'vtkMRMLColorTableNodeFileGenericAnatomyColors.txt')
            selectionNode = slicer.app.applicationLogic().GetSelectionNode()
            selectionNode.SetReferenceActiveVolumeID(masterNode.GetID())
            selectionNode.SetReferenceActiveLabelVolumeID(mergeNode.GetID())
            slicer.app.applicationLogic().PropagateVolumeSelection(0)

            #
            # go to the editor and do some drawing
            #
            slicer.util.selectModule('Editor')

            import EditorLib
            from EditorLib.EditUtil import EditUtil
            parameterNode = EditUtil.getParameterNode()
            parameterNode.SetParameter("LabelEffect,paintThreshold", "1")
            parameterNode.SetParameter("LabelEffect,paintThresholdMin", "70.0")
            parameterNode.SetParameter("LabelEffect,paintThresholdMax",
                                       "279.75")
            parameterNode.SetParameter("PaintEffect,radius", "40")
            parameterNode.SetParameter("PaintEffect,sphere", "1")

            self.delayDisplay("Paint some things")
            parameterNode = EditUtil.getParameterNode()
            lm = slicer.app.layoutManager()
            paintEffect = EditorLib.PaintEffectOptions()
            paintEffect.setMRMLDefaults()
            paintEffect.__del__()
            sliceWidget = lm.sliceWidget('Red')
            paintTool = EditorLib.PaintEffectTool(sliceWidget)
            EditUtil.setLabel(1)
            paintTool.paintAddPoint(100, 100)
            paintTool.paintApply()
            EditUtil.setLabel(2)
            paintTool.paintAddPoint(200, 200)
            paintTool.paintApply()
            paintTool.cleanup()
            paintTool = None

            # save these to compare with the one we read back
            originalSegmentationArray = slicer.util.array(mergeNode.GetID())
            originalSegmentationNodeCopy = slicer.vtkMRMLLabelMapVolumeNode()
            originalSegmentationNodeCopy.CopyOrientation(mergeNode)

            # export the volumes into a SEG
            tempSEGDirectory = slicer.app.temporaryPath + '/tempDICOMSEG'
            qt.QDir().mkpath(tempSEGDirectory)
            segFilePath = os.path.join(tempSEGDirectory, "test.SEG.dcm")

            self.delayDisplay('spliting...', 200)
            EditUtil.splitPerStructureVolumes(masterNode, mergeNode)

            self.delayDisplay('exporting...', 200)
            EditUtil.exportAsDICOMSEG(masterNode)

            # close scene re-load the input data and SEG
            slicer.mrmlScene.Clear(0)
            indexer.addDirectory(slicer.dicomDatabase, tempSEGDirectory, None)
            indexer.waitForImportFinished()

            mrHeadStudyUID = "2.16.840.1.113662.4.4168496325.1025305873.7118351817185979330"
            dicomWidget.detailsPopup.offerLoadables(mrHeadStudyUID, 'Study')
            dicomWidget.detailsPopup.examineForLoading()
            self.delayDisplay('Loading Selection')
            dicomWidget.detailsPopup.loadCheckedLoadables()

            # confirm that segmentations are correctly reloaded
            headLabelName = '2: SAG/RF-FAST/VOL/FLIP 30-label'
            reloadedLabel = slicer.util.getNode(headLabelName)
            reloadedSegmentationArray = slicer.util.array(
                reloadedLabel.GetID())

            import numpy
            self.assertTrue(
                numpy.alltrue(
                    originalSegmentationArray == reloadedSegmentationArray))
            geometryWarnings = volumesLogic.CompareVolumeGeometry(
                mergeNode, reloadedLabel)
            print(geometryWarnings)
            self.assertTrue(geometryWarnings == '')

            # re-export

            # close scene re-load the input data and SEG

            # confirm that segmentations are available again as per-structure volumes

            self.delayDisplay('Test passed!')
        except Exception, e:
            import traceback
            traceback.print_exc()
            self.delayDisplay('Test caused exception!\n' + str(e))
Exemple #42
0
  def test_AlternateReaders(self):
    """ Test the DICOM loading of sample testing data
    """
    testPass = True
    import os, json
    self.delayDisplay("Starting the DICOM test", 100)

    referenceData = json.JSONDecoder().decode('''[
      { "url": "http://slicer.kitware.com/midas3/download/item/292839/Mouse-MR-example-where-GDCM_fails.zip",
        "fileName": "Mouse-MR-example-where-GDCM_fails.zip",
        "name": "Mouse-MR-example-where-GDCM_fails",
        "seriesUID": "1.3.6.1.4.1.9590.100.1.2.366426457713813178933224342280246227461",
        "expectedFailures": ["GDCM", "Archetype"],
        "voxelValueQuantity": "(110852, DCM, \\"MR signal intensity\\")",
        "voxelValueUnits": "(1, UCUM, \\"no units\\")"
      },
      { "url": "http://slicer.kitware.com/midas3/download/item/294857/deidentifiedMRHead-dcm-one-series.zip",
        "fileName": "deidentifiedMRHead-dcm-one-series.zip",
        "name": "deidentifiedMRHead-dcm-one-series",
        "seriesUID": "1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.270.0",
        "expectedFailures": [],
        "voxelValueQuantity": "(110852, DCM, \\"MR signal intensity\\")",
        "voxelValueUnits": "(1, UCUM, \\"no units\\")"
      }
    ]''')

    # another dataset that could be added in the future - currently fails for all readers
    # due to invalid format - see https://issues.slicer.org/view.php?id=3569
      #{ "url": "http://slicer.kitware.com/midas3/download/item/293587/RIDER_bug.zip",
        #"fileName": "RIDER_bug.zip",
        #"name": "RIDER_bug",
        #"seriesUID": "1.3.6.1.4.1.9328.50.7.261772317324041365541450388603508531852",
        #"expectedFailures": []
      #}

    loadingResult = {}
    #
    # first, get the data - a zip file of dicom data
    #
    self.delayDisplay("Downloading", 100)
    for dataset in referenceData:
      try:
        filePath = slicer.app.temporaryPath + '/' + dataset['fileName']
        if not os.path.exists(filePath) or os.stat(filePath).st_size == 0:
          self.delayDisplay('Requesting download %s from %s...\n' % (dataset['fileName'], dataset['url']), 100)
          urllib.urlretrieve(dataset['url'], filePath)
        self.delayDisplay('Finished with download\n', 100)

        self.delayDisplay("Unzipping", 100)
        dicomFilesDirectory = slicer.app.temporaryPath + dataset['name']
        qt.QDir().mkpath(dicomFilesDirectory)
        slicer.app.applicationLogic().Unzip(filePath, dicomFilesDirectory)

        #
        # insert the data into th database
        #
        self.delayDisplay("Switching to temp database directory", 100)
        originalDatabaseDirectory = DICOMUtils.openTemporaryDatabase('tempDICOMDatabase')

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

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

        #
        # select the series
        #
        detailsPopup = slicer.modules.DICOMWidget.detailsPopup
        detailsPopup.open()
        # load the data by series UID
        detailsPopup.offerLoadables(dataset['seriesUID'],'Series')
        detailsPopup.examineForLoading()
        loadable = detailsPopup.getAllSelectedLoadables().keys()[0]

        #
        # try loading using each of the selected readers, fail
        # on enexpected load issue
        #
        scalarVolumePlugin = slicer.modules.dicomPlugins['DICOMScalarVolumePlugin']()
        readerApproaches = scalarVolumePlugin.readerApproaches()
        basename = loadable.name
        volumesByApproach = {}
        for readerApproach in readerApproaches:
          self.delayDisplay('Loading Selection with approach: %s' % readerApproach, 100)
          loadable.name = basename + "-" + readerApproach
          volumeNode = scalarVolumePlugin.load(loadable,readerApproach)
          if not volumeNode and readerApproach not in dataset['expectedFailures']:
            raise Exception("Expected to be able to read with %s, but couldn't" % readerApproach)
          if volumeNode and readerApproach in dataset['expectedFailures']:
            raise Exception("Expected to NOT be able to read with %s, but could!" % readerApproach)
          if volumeNode:
            volumesByApproach[readerApproach] = volumeNode

            self.delayDisplay('Test quantity and unit')
            if 'voxelValueQuantity' in dataset.keys():
              self.assertEqual(volumeNode.GetVoxelValueQuantity().GetAsPrintableString(), dataset['voxelValueQuantity'])
            if 'voxelValueUnits' in dataset.keys():
              self.assertEqual(volumeNode.GetVoxelValueUnits().GetAsPrintableString(), dataset['voxelValueUnits'])


        #
        # for each approach that loaded as expected, compare the volumes
        # to ensure they match in terms of pixel data and metadata
        #
        failedComparisons = {}
        approachesThatLoaded = volumesByApproach.keys()
        print('approachesThatLoaded %s' % approachesThatLoaded)
        for approachIndex in range(len(approachesThatLoaded)):
          firstApproach = approachesThatLoaded[approachIndex]
          firstVolume = volumesByApproach[firstApproach]
          for secondApproachIndex in range(approachIndex+1,len(approachesThatLoaded)):
            secondApproach = approachesThatLoaded[secondApproachIndex]
            secondVolume = volumesByApproach[secondApproach]
            print('comparing  %s,%s' % (firstApproach, secondApproach))
            comparison = slicer.modules.dicomPlugins['DICOMScalarVolumePlugin'].compareVolumeNodes(firstVolume,secondVolume)
            if comparison != "":
              print('failed: %s', comparison)
              failedComparisons[firstApproach,secondApproach] = comparison

        if len(failedComparisons.keys()) > 0:
          raise Exception("Loaded volumes don't match: %s" % failedComparisons)

        self.delayDisplay('%s Test passed!' % dataset['name'], 200)

      except Exception, e:
        import traceback
        traceback.print_exc()
        self.delayDisplay('%s Test caused exception!\n' % dataset['name'] + str(e), 2000)
        testPass = False
Exemple #43
0
    def test_Part1DICOM(self,
                        enableScreenshotsFlag=0,
                        screenshotScaleFactor=1):
        """ Test the DICOM part of the test using the head atlas
    """

        logic = RSNAVisTutorialLogic()
        logic.enableScreenshots = enableScreenshotsFlag
        logic.screenshotScaleFactor = screenshotScaleFactor

        import os
        self.delayDisplay("Starting the DICOM test")
        #
        # first, get the data - a zip file of dicom data
        #
        import SampleData
        dicomFilesDirectory = SampleData.downloadFromURL(
            fileNames='dataset1_Thorax_Abdomen.zip',
            uris='http://slicer.kitware.com/midas3/download?items=124183',
            checksums=
            'SHA256:17a4199aad03a373dab27dc17e5bfcf84fc194d0a30975b4073e5b595d43a56a'
        )[0]

        try:
            self.delayDisplay("Switching to temp database directory")
            originalDatabaseDirectory = DICOMUtils.openTemporaryDatabase(
                'tempDICOMDatabase')

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

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

            dicomWidget = slicer.modules.DICOMWidget
            dicomWidget.detailsPopup.open()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            self.delayDisplay('Test passed!')
        except Exception as e:
            import traceback
            traceback.print_exc()
            self.delayDisplay('Test caused exception!\n' + str(e))

        self.delayDisplay("Restoring original database directory")
        DICOMUtils.closeTemporaryDatabase(originalDatabaseDirectory)
Exemple #44
0
 def importStudy(dicomDataDir):
   indexer = ctk.ctkDICOMIndexer()
   indexer.addDirectory(slicer.dicomDatabase, dicomDataDir)
   indexer.waitForImportFinished()
    def section_LoadDicomData(self):
        try:
            # Download and unzip test CT DICOM data
            import urllib
            downloads = ((
                'http://slicer.kitware.com/midas3/download/item/137843/TestDicomCT.zip',
                self.dicomZipFilePath), )

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

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

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

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

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

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

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

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

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

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

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

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

            if originalDatabaseDirectory:
                dicomWidget.onDatabaseDirectoryChanged(
                    originalDatabaseDirectory)

        except Exception, e:
            import traceback
            traceback.print_exc()
            self.delayDisplay('Test caused exception!\n' + str(e),
                              self.delayMs * 2)
Exemple #46
0
    def ImportStudy(self, dicomDataDir):
        indexer = ctk.ctkDICOMIndexer()

        # Import study to database
        indexer.addDirectory(slicer.dicomDatabase, dicomDataDir)
        indexer.waitForImportFinished()
  def section_LoadDicomData(self):
    try:
      # Download and unzip test CT DICOM data
      import urllib
      downloads = (
          ('http://slicer.kitware.com/midas3/download/item/137843/TestDicomCT.zip', self.dicomZipFilePath),
          )

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

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

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

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

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

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

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

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

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

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

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

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

      if originalDatabaseDirectory:
        dicomWidget.onDatabaseDirectoryChanged(originalDatabaseDirectory)
      
    except Exception, e:
      import traceback
      traceback.print_exc()
      self.delayDisplay('Test caused exception!\n' + str(e),self.delayMs*2)
  def ImportStudy(self,dicomDataDir):
    indexer = ctk.ctkDICOMIndexer()

    # Import study to database
    indexer.addDirectory( slicer.dicomDatabase, dicomDataDir )
    indexer.waitForImportFinished()
Exemple #49
0
    def test_MissingSlices(self):
        """ Test behavior of the readers when slices are missing

    To edit and run this test from the python console, paste this below:

reloadScriptedModule('DICOMReaders'); import DICOMReaders; tester = DICOMReaders.DICOMReadersTest(); tester.setUp(); tester.test_MissingSlices()

    """
        testPass = True
        import os, json
        self.delayDisplay("Starting the DICOM test")

        import SampleData
        dicomFilesDirectory = SampleData.downloadFromURL(
            fileNames='deidentifiedMRHead-dcm-one-series.zip',
            uris='http://slicer.kitware.com/midas3/download?items=294857')[0]
        self.delayDisplay('Finished with download\n')

        seriesUID = "1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.270.0"
        seriesRASBounds = [
            -87.29489517211913, 81.70450973510744, -121.57139587402344,
            134.42860412597656, -138.71430206298828, 117.28569793701172
        ]
        seriesDirectory = "Series 004 [MR - SAG RF FAST VOL FLIP 20]"
        lastSliceCorners = [[[81.05451202, 133.92860413, 116.78569794],
                             [81.05451202, -122.07139587, 116.78569794]],
                            [[81.05451202, 133.92860413, -139.21429443],
                             [81.05451202, -122.07139587, -139.21429443]]]
        filesToRemove = [
            "1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.361.0.dcm",
            "1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.362.0.dcm",
            "1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.363.0.dcm",
            "1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.364.0.dcm",
            "1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.365.0.dcm",
            "1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.366.0.dcm",
            "1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.367.0.dcm",
            "1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.368.0.dcm",
            "1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.369.0.dcm",
            "1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.370.0.dcm",
            "1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.371.0.dcm",
            "1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.372.0.dcm",
            "1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.373.0.dcm",
            "1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.374.0.dcm",
            "1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.375.0.dcm",
            "1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.376.0.dcm",
        ]

        try:

            print('Removing %d files from the middle of the series' %
                  len(filesToRemove))
            for file in filesToRemove:
                filePath = os.path.join(dicomFilesDirectory, seriesDirectory,
                                        file)
                os.remove(filePath)

            #
            # insert the data into the database
            #
            self.delayDisplay("Switching to temp database directory")
            originalDatabaseDirectory = DICOMUtils.openTemporaryDatabase(
                'tempDICOMDatabase')

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

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

            #
            # select the series
            #
            detailsPopup = slicer.modules.DICOMWidget.detailsPopup
            detailsPopup.open()
            # load the data by series UID
            detailsPopup.offerLoadables(seriesUID, 'Series')
            detailsPopup.examineForLoading()
            loadable = detailsPopup.getAllSelectedLoadables().keys()[0]

            if len(loadable.warning) == 0:
                raise Exception(
                    "Expected warning about geometry issues due to missing slices!"
                )

            #
            # load and correct for acquisition then check the geometry
            #
            scalarVolumePlugin = slicer.modules.dicomPlugins[
                'DICOMScalarVolumePlugin']()
            volumeNode = scalarVolumePlugin.load(loadable)

            if not numpy.allclose(
                    scalarVolumePlugin.acquisitionModeling.fixedCorners[-1],
                    lastSliceCorners):
                raise Exception(
                    "Acquisition transform didn't fix slice corners!")

            self.delayDisplay('test_MissingSlices passed!')

        except Exception, e:
            import traceback
            traceback.print_exc()
            self.delayDisplay('Missing Slices Test caused exception!\n' +
                              str(e))
            testPass = False
Exemple #50
0
  def test_MissingSlices(self):
    """ Test behavior of the readers when slices are missing

    To edit and run this test from the python console, paste this below:

reloadScriptedModule('DICOMReaders'); import DICOMReaders; tester = DICOMReaders.DICOMReadersTest(); tester.setUp(); tester.test_MissingSlices()

    """
    testPass = True
    import os, json
    self.delayDisplay("Starting the DICOM test", 100)

    datasetURL = "http://slicer.kitware.com/midas3/download/item/294857/deidentifiedMRHead-dcm-one-series.zip"
    fileName = "deidentifiedMRHead-dcm-one-series.zip"
    filePath = os.path.join(slicer.app.temporaryPath,fileName)
    seriesUID = "1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.270.0"
    seriesRASBounds = [-87.29489517211913, 81.70450973510744,
                       -121.57139587402344, 134.42860412597656,
                       -138.71430206298828, 117.28569793701172]
    seriesDirectory = "Series 004 [MR - SAG RF FAST VOL FLIP 20]"
    lastSliceCorners = [[[81.05451202, 133.92860413, 116.78569794], [81.05451202, -122.07139587, 116.78569794]],
                        [[81.05451202, 133.92860413, -139.21429443], [81.05451202, -122.07139587, -139.21429443]]]
    filesToRemove = [
      "1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.361.0.dcm",
      "1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.362.0.dcm",
      "1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.363.0.dcm",
      "1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.364.0.dcm",
      "1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.365.0.dcm",
      "1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.366.0.dcm",
      "1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.367.0.dcm",
      "1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.368.0.dcm",
      "1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.369.0.dcm",
      "1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.370.0.dcm",
      "1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.371.0.dcm",
      "1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.372.0.dcm",
      "1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.373.0.dcm",
      "1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.374.0.dcm",
      "1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.375.0.dcm",
      "1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.376.0.dcm",
    ]

    try:
      if not os.path.exists(filePath) or os.stat(filePath).st_size == 0:
        self.delayDisplay('Requesting download %s from %s...\n' % (fileName, datasetURL), 100)
        urllib.urlretrieve(datasetURL, filePath)
      self.delayDisplay('Finished with download\n', 100)

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

      print('Removing %d files from the middle of the series' % len(filesToRemove))
      for file in filesToRemove:
        filePath = os.path.join(dicomFilesDirectory, seriesDirectory, file)
        os.remove(filePath)

      #
      # insert the data into the database
      #
      self.delayDisplay("Switching to temp database directory", 100)
      originalDatabaseDirectory = DICOMUtils.openTemporaryDatabase('tempDICOMDatabase')

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

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

      #
      # select the series
      #
      detailsPopup = slicer.modules.DICOMWidget.detailsPopup
      detailsPopup.open()
      # load the data by series UID
      detailsPopup.offerLoadables(seriesUID,'Series')
      detailsPopup.examineForLoading()
      loadable = detailsPopup.getAllSelectedLoadables().keys()[0]

      if len(loadable.warning) == 0:
        raise Exception("Expected warning about geometry issues due to missing slices!")

      #
      # load and correct for acquisition then check the geometry
      #
      scalarVolumePlugin = slicer.modules.dicomPlugins['DICOMScalarVolumePlugin']()
      volumeNode = scalarVolumePlugin.load(loadable)

      if not numpy.allclose(scalarVolumePlugin.acquisitionModeling.fixedCorners[-1], lastSliceCorners):
        raise Exception("Acquisition transform didn't fix slice corners!")

      self.delayDisplay('test_MissingSlices passed!', 200)

    except Exception, e:
      import traceback
      traceback.print_exc()
      self.delayDisplay('Missing Slices Test caused exception!\n' + str(e), 2000)
      testPass = False
 def addProducedDataToDICOMDatabase(self):
   indexer = ctk.ctkDICOMIndexer()
   indexer.addFile(slicer.dicomDatabase, os.path.join(self.tempDir,'seg.dcm'), "copy")  # Note: doesn't really expect a destination dir
   indexer.addFile(slicer.dicomDatabase, os.path.join(self.tempDir,'sr.dcm'), "copy")  # Note: doesn't really expect a destination dir
Exemple #52
0
  def proceedWithReferencedLoadablesSelection(self):
    # each check box corresponds to a referenced loadable
    # that was selected by examine; if the user confirmed
    # that reference should be loaded, add it to the self.loadablesByPlugin
    # dictionary
    if self.referencesDialog:
      children = self.referencesDialog.children()
      loadableCnt = 0
      for plugin in self.referencedLoadables:
        for loadable in self.referencedLoadables[plugin]:
          if loadable.selected:
            if children[loadableCnt+2].checked:
              self.loadablesByPlugin[plugin].append(loadable)

      self.referencesDialog.close()
      self.referencesDialog = None

    loadableCount = 0
    for plugin in self.loadablesByPlugin:
      for loadable in self.loadablesByPlugin[plugin]:
        if loadable.selected:
          loadableCount += 1
    self.progress = qt.QProgressDialog(self.window)
    self.progress.minimumDuration = 0
    self.progress.show()
    self.progress.setValue(0)
    self.progress.setMaximum(loadableCount)
    step = 0
    loadingResult = ''

    loadedNodeIDs = []

    @vtk.calldata_type(vtk.VTK_OBJECT)
    def onNodeAdded(caller, event, calldata):
      node = calldata
      if isinstance(node, slicer.vtkMRMLVolumeNode):
        loadedNodeIDs.append(node.GetID())

    self.addObserver(slicer.mrmlScene, slicer.vtkMRMLScene.NodeAddedEvent, onNodeAdded);

    for plugin in self.loadablesByPlugin:
      for loadable in self.loadablesByPlugin[plugin]:
        if self.progress.wasCanceled:
          break
        slicer.app.processEvents()
        self.progress.setValue(step)
        slicer.app.processEvents()
        if loadable.selected:
          self.progress.labelText = '\nLoading %s' % loadable.name
          slicer.app.processEvents()
          if not plugin.load(loadable):
            loadingResult = '%s\nCould not load: %s as a %s' % (loadingResult,loadable.name,plugin.loadType)
          step += 1
          self.progress.setValue(step)
          slicer.app.processEvents()
        try:
          for derivedItem in loadable.derivedItems:
            indexer = ctk.ctkDICOMIndexer()
            self.progress.labelText = '\nIndexing %s' % derivedItem
            slicer.app.processEvents()
            indexer.addFile(slicer.dicomDatabase, derivedItem)
        except AttributeError:
          # no derived items or some other attribute error
          pass

    self.removeObserver(slicer.mrmlScene, slicer.vtkMRMLScene.NodeAddedEvent, onNodeAdded);

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

    self.progress.close()
    self.progress = None
    if loadingResult:
      qt.QMessageBox.warning(slicer.util.mainWindow(), 'DICOM loading', loadingResult)
    if not self.browserPersistent:
      self.close()

    return
Exemple #53
0
  def test_Part1DICOM(self,enableScreenshotsFlag=0,screenshotScaleFactor=1):
    """ Test the DICOM part of the test using the head atlas
    """

    self.enableScreenshots = enableScreenshotsFlag
    self.screenshotScaleFactor = screenshotScaleFactor

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

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

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

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

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

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

      dicomWidget.detailsPopup.open()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

      self.delayDisplay('Test passed!')
    except Exception, e:
      import traceback
      traceback.print_exc()
      self.delayDisplay('Test caused exception!\n' + str(e))