Exemplo n.º 1
0
  def initializeNewLabel(newLabel, sourceVolume):
    displayNode = slicer.mrmlScene.AddNode(slicer.vtkMRMLLabelMapVolumeDisplayNode())

    threshold = vtk.vtkImageThreshold()
    threshold.ReplaceInOn()
    threshold.ReplaceOutOn()
    threshold.SetInValue(0)
    threshold.SetOutValue(0)
    threshold.SetOutputScalarTypeToUnsignedShort()
    if vtk.vtkVersion().GetVTKMajorVersion() < 6:
      threshold.SetInput(sourceVolume.GetImageData())
    else:
      threshold.SetInputData(sourceVolume.GetImageData())
    threshold.Update()

    labelImage = vtk.vtkImageData()
    labelImage.DeepCopy(threshold.GetOutput())
    
    newLabel.SetAndObserveStorageNodeID(None)
    newLabel.CopyOrientation(sourceVolume)
    ras2ijk = vtk.vtkMatrix4x4()
    sourceVolume.GetRASToIJKMatrix(ras2ijk)
    newLabel.SetRASToIJKMatrix(ras2ijk)

    newLabel.SetAttribute('ReportingReportNodeID', sourceVolume.GetAttribute('ReportingReportNodeID'))
    newLabel.SetAttribute('AssociatedNodeID', sourceVolume.GetID())
    
    newLabel.SetAndObserveDisplayNodeID(displayNode.GetID())
    newLabel.SetAndObserveImageData(labelImage)
def DoIt(inputDir, labelFile, outputDir, forceLabel, forceResample):

  dbDir1 = slicer.app.temporaryPath+'/LabelConverter'

  if not hasattr(slicer.modules, 'reporting'):
    print 'The Reporting module has not been loaded into Slicer, script cannot run!\n\tTry setting the --additional-module-path parameter.'
    sys.exit(1)

  reportingLogic = slicer.modules.reporting.logic()

  print('Temporary directory location: '+dbDir1)
  qt.QDir().mkpath(dbDir1)

  dbDir0 = None
  if slicer.dicomDatabase:
    dbDir0 = os.path.split(slicer.dicomDatabase.databaseFilename)[0]

  dicomWidget = slicer.modules.dicom.widgetRepresentation().self()
  dicomWidget.onDatabaseDirectoryChanged(dbDir1)

  # import DICOM study
  indexer = ctk.ctkDICOMIndexer()
  indexer.addDirectory(slicer.dicomDatabase, inputDir, None)
  indexer.waitForImportFinished()

  print('DICOM import finished!')

  #
  # Read the input DICOM series as a volume
  #
  dcmList = []
  for dcm in os.listdir(inputDir):
    if len(dcm)-dcm.rfind('.dcm') == 4:
      dcmList.append(inputDir+'/'+dcm)

  scalarVolumePlugin = slicer.modules.dicomPlugins['DICOMScalarVolumePlugin']()

  loadables = scalarVolumePlugin.examine([dcmList])

  if len(loadables) == 0:
    print 'Could not parse the DICOM Study!'
    sys.exit(1)

  inputVolume = scalarVolumePlugin.load(loadables[0])
  print 'Input volume loaded! ID = ', inputVolume.GetID()

  # read the label volume
  labelVolume = slicer.vtkMRMLLabelMapVolumeNode()
  sNode = slicer.vtkMRMLVolumeArchetypeStorageNode()
  sNode.SetFileName(labelFile)
  sNode.ReadData(labelVolume)

  if forceLabel>0:
    # print('Forcing label to '+str(forceLabel))
    labelImage = labelVolume.GetImageData()
    thresh = vtk.vtkImageThreshold()
    if vtk.vtkVersion().GetVTKMajorVersion() < 6:
      thresh.SetInput(labelImage)
    else:
      thresh.SetInputData(labelImage)
      thresh.ThresholdBetween(1, labelImage.GetScalarRange()[1])
      thresh.SetInValue(int(forceLabel))
      thresh.SetOutValue(0)
      thresh.ReplaceInOn()
      thresh.ReplaceOutOn()
      thresh.Update()
      labelImage = thresh.GetOutput()
      labelVolume.SetAndObserveImageData(labelImage)

  slicer.mrmlScene.AddNode(labelVolume)
  print 'Label volume added, id = ', labelVolume.GetID()

  # ensure that the label volume scalar type is unsigned short
  if labelVolume.GetImageData() != None:
    scalarType = labelVolume.GetImageData().GetScalarType()
    if scalarType != vtk.VTK_UNSIGNED_SHORT:
      print 'Label volume has pixel type of ',vtk.vtkImageScalarTypeNameMacro(scalarType),', casting to unsigned short'
      cast = vtk.vtkImageCast()
      cast.SetOutputScalarTypeToUnsignedShort()
      if vtk.vtkVersion().GetVTKMajorVersion() < 6:
        cast.SetInput(labelVolume.GetImageData())
        cast.Update()
        labelVolume.SetAndObserveImageData(cast.GetOutput())
      else:
        cast.SetInputConnection(labelVolume.GetImageDataConnection())
        cast.Update()
        labelVolume.SetImageDataConnection(cast.GetOutputPort())
      if labelVolume.GetImageData().GetScalarType() != vtk.VTK_UNSIGNED_SHORT:
        print 'Failed to cast label volume to unsigned short, type is ',  vtk.vtkImageScalarTypeNameMacro(labelVolume.GetImageData().GetScalarType())
        sys.exit(1)

  volumesLogic = slicer.modules.volumes.logic()
  geometryCheckString = volumesLogic.CheckForLabelVolumeValidity(inputVolume, labelVolume)
  if geometryCheckString != "":
    # has the user specified that forced resampling is okay?
    if forceResample == False:
      print 'Label volume mismatch with input volume:\n',geometryCheckString,'\nForced resample not specified, aborting. Re-run with --force option to ignore geometric inconsistencies'
      sys.exit(1)
    # resample label to the input volume raster
    resampledLabel = slicer.vtkMRMLLabelMapVolumeNode()
    slicer.mrmlScene.AddNode(resampledLabel)
    print 'Resampled label added, id = ', resampledLabel.GetID()
    resampledLabel = volumesLogic.ResampleVolumeToReferenceVolume(labelVolume, inputVolume)
    labelVolume = resampledLabel

  displayNode = slicer.vtkMRMLLabelMapVolumeDisplayNode()
  displayNode.SetAndObserveColorNodeID(reportingLogic.GetDefaultColorNode().GetID())
  slicer.mrmlScene.AddNode(displayNode)

  labelVolume.SetAttribute('AssociatedNodeID',inputVolume.GetID())
  labelVolume.SetAndObserveDisplayNodeID(displayNode.GetID())

  # initialize the DICOM DB for Reporting logic, save as DICOM SEG
  labelCollection = vtk.vtkCollection()
  labelCollection.AddItem(labelVolume)

  print('About to write DICOM SEG!')
  dbFileName = slicer.dicomDatabase.databaseFilename
  reportingLogic.InitializeDICOMDatabase(dbFileName)
  reportingLogic.DicomSegWrite(labelCollection, outputDir)

  dicomWidget.onDatabaseDirectoryChanged(dbDir0)

  exit()
  def test_LabelToDICOMSEGConverterRoundTrip(self):
    print("CTEST_FULL_OUTPUT")

    dir(slicer.modules)

    """ Load the data using DICOM module
    """

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

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

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

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

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

      self.importDICOM(slicer.dicomDatabase, dicomFilesDirectory)

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

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

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

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

      self.delayDisplay('Configure Module')
      mainWindow = slicer.util.mainWindow()
      mainWindow.moduleSelector().selectModule('LabelToDICOMSEGConverter')
  
      module = slicer.modules.labeltodicomsegconverter.widgetRepresentation().self()

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

      self.delayDisplay('Input label initialized')

      module.outputDir = reportingTempDir+'/Output'

      # Save the report

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

      self.delayDisplay('Report saved')

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

      loadablesByPlugin = dicomWidget.detailsPopup.loadablesByPlugin

      self.delayDisplay('Wait',10000)

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

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

      self.delayDisplay('Test passed')

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

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


  #
  # Read the input DICOM series as a volume
  #
  dcmList = []
  for dcm in os.listdir(inputDir):
    if len(dcm)-dcm.rfind('.dcm') == 4:
      dcmList.append(inputDir+'/'+dcm)

  scalarVolumePlugin = slicer.modules.dicomPlugins['DICOMScalarVolumePlugin']()

  print 'Will examine: ',dcmList


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

  loadables = scalarVolumePlugin.examine([dcmList])

  if len(loadables) == 0:
    print 'Could not parse the DICOM Study!'
    exit()

  inputVolume = scalarVolumePlugin.load(loadables[0])

  sNode = slicer.vtkMRMLVolumeArchetypeStorageNode()
  '''
  sNode.ResetFileNameList()
  for f in loadables[0].files:
    sNode.AddFileName(f)
  sNode.SetFileName(loadables[0].files[0])
  sNode.SetSingleFile(0)
  inputVolume = slicer.vtkMRMLScalarVolumeNode()
  sNode.ReadData(inputVolume)
  '''

  sNode.SetWriteFileFormat('nrrd')
  sNode.SetFileName(os.path.join(outputDir,'input_volume.nrrd'))
  sNode.WriteData(inputVolume)

  #
  # Order the input RGBs and rename in a temp directory
  #
  rgbList = []
  for rgb in os.listdir(rgbDir):
    if len(rgb)-rgb.rfind('.bmp') == 4:
      rgbList.append(rgb)

  tmpDir = slicer.app.settings().value('Modules/TemporaryDirectory')
  tmpDir = tmpDir+'/PNGStackLabelConverter'
  if not os.path.exists(tmpDir):
    os.mkdir(tmpDir)

  oldFiles = os.listdir(tmpDir)
  # just in case there is anything in that directory
  for f in oldFiles:
    os.unlink(tmpDir+'/'+f)

  rgbOrdered = [None] * len(loadables[0].files)
  rgbCnt = 0
  rgbExt = rgbList[0][rgbList[0].rfind('.')+1:len(rgbList[0])]
  print 'Extension for RGBs: ',rgbExt

  dcmFileList = loadables[0].files
  rgbRenamedList = []

  print 'Number of dcm files: ',len(dcmFileList), ' and rgb files: ',len(rgbOrdered)

  dcmIdx = 0
  for dcm in dcmFileList:
    rgbIdx = 0

    for rgb in rgbList:

      dcmPrefix = dcm[dcm.rfind('/')+1:dcm.rfind('.')]

      if rgb.find(dcmPrefix) != -1:
        name = string.zfill(str(dcmIdx),5)
        rgbCnt = rgbCnt+1
        src = rgbDir+'/'+rgb
        dest = tmpDir+'/'+name+'.'+rgbExt
        rgbRenamedList.append(dest)
        shutil.copy(src,dest)

        break
      rgbIdx = rgbIdx+1

    # remove the matched DICOM file from the list
    if rgbIdx == len(rgbList):
      print('ERROR: failed to find matching label file for DICOM file '+dcm)
      return

    del rgbList[rgbIdx]
    dcmIdx = dcmIdx+1

  if len(rgbRenamedList) == 0:
    print 'Could not parse the DICOM Study!'
    return

  sNode = slicer.vtkMRMLVolumeArchetypeStorageNode()
  sNode.ResetFileNameList()
  for f in rgbRenamedList:
    sNode.AddFileName(f)
  sNode.SetFileName(rgbRenamedList[0])
  sNode.SetSingleFile(0)
  inputRGBVolume = slicer.vtkMRMLVectorVolumeNode()
  sNode.ReadData(inputRGBVolume)


  # run the filter
  # - extract the RGB portions
  extract = vtk.vtkImageExtractComponents()
  extract.SetComponents(0,1,2)
  if vtk.vtkVersion().GetVTKMajorVersion() < 6:
    extract.SetInput(inputRGBVolume.GetImageData())
  else:
    extract.SetInputData(inputRGBVolume.GetImageData())

  luminance = vtk.vtkImageLuminance()
  if vtk.vtkVersion().GetVTKMajorVersion() < 6:
    luminance.SetInput(extract.GetOutput())
  else:
    luminance.SetInputData(extract.GetOutput())

  cast = vtk.vtkImageCast()
  if vtk.vtkVersion().GetVTKMajorVersion() < 6:
    cast.SetInput(luminance.GetOutput())
  else:
    cast.SetInputData(luminance.GetOutput())
  cast.SetOutputScalarTypeToShort()
  cast.GetOutput().Update()

  ijkToRAS = vtk.vtkMatrix4x4()
  inputVolume.GetIJKToRASMatrix(ijkToRAS)

  outputLabel = slicer.vtkMRMLLabelMapVolumeNode()
  outputLabel.SetIJKToRASMatrix(ijkToRAS)
  outputLabel.SetAndObserveImageData(cast.GetOutput())

  reportingLogic = slicer.modules.reporting.logic()

  displayNode = slicer.vtkMRMLLabelMapVolumeDisplayNode()
  displayNode.SetAndObserveColorNodeID(reportingLogic.GetDefaultColorNode().GetID())
  slicer.mrmlScene.AddNode(displayNode)
  outputLabel.SetAndObserveDisplayNodeID(displayNode.GetID())

  sNode.SetWriteFileFormat('nrrd')
  sNode.SetFileName(os.path.join(outputDir,'label_output.nrrd'))
  sNode.WriteData(outputLabel)

  # save as DICOM SEG
  labelCollection = vtk.vtkCollection()
  labelCollection.AddItem(outputLabel)

  slicer.mrmlScene.AddNode(inputVolume)
  outputLabel.SetAttribute('AssociatedNodeID',inputVolume.GetID())
  slicer.mrmlScene.AddNode(outputLabel)

  # initialize the DICOM DB for Reporting logic
  settings = qt.QSettings()
  dbFileName = settings.value('DatabaseDirectory','')
  if dbFileName =='':
    print('ERROR: database must be initialized')
  else:
    dbFileName = dbFileName +'/ctkDICOM.sql'
    reportingLogic.InitializeDICOMDatabase(dbFileName)

    reportingLogic.DicomSegWrite(labelCollection, outputDir)
def DoIt(inputDir, rgbDir, outputDir):

    #
    # Read the input DICOM series as a volume
    #
    dcmList = []
    for dcm in os.listdir(inputDir):
        if len(dcm) - dcm.rfind('.dcm') == 4:
            dcmList.append(inputDir + '/' + dcm)

    scalarVolumePlugin = slicer.modules.dicomPlugins[
        'DICOMScalarVolumePlugin']()

    print 'Will examine: ', dcmList

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

    loadables = scalarVolumePlugin.examine([dcmList])

    if len(loadables) == 0:
        print 'Could not parse the DICOM Study!'
        exit()

    inputVolume = scalarVolumePlugin.load(loadables[0])

    sNode = slicer.vtkMRMLVolumeArchetypeStorageNode()
    '''
  sNode.ResetFileNameList()
  for f in loadables[0].files:
    sNode.AddFileName(f)
  sNode.SetFileName(loadables[0].files[0])
  sNode.SetSingleFile(0)
  inputVolume = slicer.vtkMRMLScalarVolumeNode()
  sNode.ReadData(inputVolume)
  '''

    sNode.SetWriteFileFormat('nrrd')
    sNode.SetFileName(os.path.join(outputDir, 'input_volume.nrrd'))
    sNode.WriteData(inputVolume)

    #
    # Order the input RGBs and rename in a temp directory
    #
    rgbList = []
    for rgb in os.listdir(rgbDir):
        if len(rgb) - rgb.rfind('.bmp') == 4:
            rgbList.append(rgb)

    tmpDir = slicer.app.settings().value('Modules/TemporaryDirectory')
    tmpDir = tmpDir + '/PNGStackLabelConverter'
    if not os.path.exists(tmpDir):
        os.mkdir(tmpDir)

    oldFiles = os.listdir(tmpDir)
    # just in case there is anything in that directory
    for f in oldFiles:
        os.unlink(tmpDir + '/' + f)

    rgbOrdered = [None] * len(loadables[0].files)
    rgbCnt = 0
    rgbExt = rgbList[0][rgbList[0].rfind('.') + 1:len(rgbList[0])]
    print 'Extension for RGBs: ', rgbExt

    dcmFileList = loadables[0].files
    rgbRenamedList = []

    print 'Number of dcm files: ', len(dcmFileList), ' and rgb files: ', len(
        rgbOrdered)

    dcmIdx = 0
    for dcm in dcmFileList:
        rgbIdx = 0

        for rgb in rgbList:

            dcmPrefix = dcm[dcm.rfind('/') + 1:dcm.rfind('.')]

            if rgb.find(dcmPrefix) != -1:
                name = string.zfill(str(dcmIdx), 5)
                rgbCnt = rgbCnt + 1
                src = rgbDir + '/' + rgb
                dest = tmpDir + '/' + name + '.' + rgbExt
                rgbRenamedList.append(dest)
                shutil.copy(src, dest)

                break
            rgbIdx = rgbIdx + 1

        # remove the matched DICOM file from the list
        if rgbIdx == len(rgbList):
            print('ERROR: failed to find matching label file for DICOM file ' +
                  dcm)
            return

        del rgbList[rgbIdx]
        dcmIdx = dcmIdx + 1

    if len(rgbRenamedList) == 0:
        print 'Could not parse the DICOM Study!'
        return

    sNode = slicer.vtkMRMLVolumeArchetypeStorageNode()
    sNode.ResetFileNameList()
    for f in rgbRenamedList:
        sNode.AddFileName(f)
    sNode.SetFileName(rgbRenamedList[0])
    sNode.SetSingleFile(0)
    inputRGBVolume = slicer.vtkMRMLVectorVolumeNode()
    sNode.ReadData(inputRGBVolume)

    # run the filter
    # - extract the RGB portions
    extract = vtk.vtkImageExtractComponents()
    extract.SetComponents(0, 1, 2)
    if vtk.vtkVersion().GetVTKMajorVersion() < 6:
        extract.SetInput(inputRGBVolume.GetImageData())
    else:
        extract.SetInputData(inputRGBVolume.GetImageData())

    luminance = vtk.vtkImageLuminance()
    if vtk.vtkVersion().GetVTKMajorVersion() < 6:
        luminance.SetInput(extract.GetOutput())
    else:
        luminance.SetInputData(extract.GetOutput())

    cast = vtk.vtkImageCast()
    if vtk.vtkVersion().GetVTKMajorVersion() < 6:
        cast.SetInput(luminance.GetOutput())
    else:
        cast.SetInputData(luminance.GetOutput())
    cast.SetOutputScalarTypeToShort()
    cast.GetOutput().Update()

    ijkToRAS = vtk.vtkMatrix4x4()
    inputVolume.GetIJKToRASMatrix(ijkToRAS)

    outputLabel = slicer.vtkMRMLLabelMapVolumeNode()
    outputLabel.SetIJKToRASMatrix(ijkToRAS)
    outputLabel.SetAndObserveImageData(cast.GetOutput())

    reportingLogic = slicer.modules.reporting.logic()

    displayNode = slicer.vtkMRMLLabelMapVolumeDisplayNode()
    displayNode.SetAndObserveColorNodeID(
        reportingLogic.GetDefaultColorNode().GetID())
    slicer.mrmlScene.AddNode(displayNode)
    outputLabel.SetAndObserveDisplayNodeID(displayNode.GetID())

    sNode.SetWriteFileFormat('nrrd')
    sNode.SetFileName(os.path.join(outputDir, 'label_output.nrrd'))
    sNode.WriteData(outputLabel)

    # save as DICOM SEG
    labelCollection = vtk.vtkCollection()
    labelCollection.AddItem(outputLabel)

    slicer.mrmlScene.AddNode(inputVolume)
    outputLabel.SetAttribute('AssociatedNodeID', inputVolume.GetID())
    slicer.mrmlScene.AddNode(outputLabel)

    # initialize the DICOM DB for Reporting logic
    settings = qt.QSettings()
    dbFileName = settings.value('DatabaseDirectory', '')
    if dbFileName == '':
        print('ERROR: database must be initialized')
    else:
        dbFileName = dbFileName + '/ctkDICOM.sql'
        reportingLogic.InitializeDICOMDatabase(dbFileName)

        reportingLogic.DicomSegWrite(labelCollection, outputDir)
  def test_ReportingAIMRoundTrip(self):
    print("CTEST_FULL_OUTPUT")
    """ Load the data using DICOM module
    """
 
    import os
    self.delayDisplay("Starting the DICOM test")
    #
    # first, get the data - a zip file of dicom data
    #
    import urllib
    downloads = (
        ('http://slicer.kitware.com/midas3/download?items=10881', 'JANCT-CT.zip'),
        )

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

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

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

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

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

      loadablesByPlugin = dicomWidget.detailsPopup.loadablesByPlugin

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

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

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

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

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

      # place some markups and add a segmentation label

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

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

      # Save the report

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

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


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

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

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

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

    except Exception, e:
      if self.originalDatabaseDirectory:
        dicomWidget.onDatabaseDirectoryChanged(self.originalDatabaseDirectory)
      import traceback
      traceback.print_exc()
      self.delayDisplay('Test caused exception!\n' + str(e))
      self.assertTrue(False)
Exemplo n.º 7
0
    def test_ReportingAIMRoundTrip(self):
        print ("CTEST_FULL_OUTPUT")
        """ Load the data using DICOM module
    """

        import os

        self.delayDisplay("Starting the DICOM test")
        #
        # first, get the data - a zip file of dicom data
        #
        import urllib

        downloads = (("http://slicer.kitware.com/midas3/download?items=10881", "JANCT-CT.zip"),)

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

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

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

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

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

            loadablesByPlugin = dicomWidget.detailsPopup.loadablesByPlugin

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

            # initialize the module with the report and volume

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

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

            self.delayDisplay("Configure Module")
            mainWindow = slicer.util.mainWindow()
            mainWindow.moduleSelector().selectModule("Reporting")

            reporting = slicer.modules.reporting.widgetRepresentation().self()

            report = slicer.mrmlScene.CreateNodeByClass("vtkMRMLReportingReportNode")
            report.SetReferenceCount(report.GetReferenceCount() - 1)
            slicer.mrmlScene.AddNode(report)
            report.SetFindingLabel(7)

            reporting.reportSelector.setCurrentNode(report)
            self.delayDisplay("Setting volume to %s" % volume.GetName())
            reporting.volumeSelector.setCurrentNode(volume)
            slicer.app.processEvents()

            # place some markups and add a segmentation label

            # add fiducial
            fidNode = slicer.vtkMRMLAnnotationFiducialNode()
            fidName = "AIM Round Trip Test Fiducial"
            fidNode.SetName(fidName)
            fidNode.SetSelected(1)
            fidNode.SetDisplayVisibility(1)
            fidNode.SetLocked(0)
            # TODO: ask Nicole where this is assigned in the regular workflow
            fidNode.SetAttribute("AssociatedNodeID", volume.GetID())
            print ("Calling set fid coords")
            startCoords = [15.8, 70.8, -126.7]
            fidNode.SetFiducialCoordinates(startCoords[0], startCoords[1], startCoords[2])
            print ("Starting fiducial coordinates: " + str(startCoords))
            slicer.mrmlScene.AddNode(fidNode)

            # add ruler
            rulerNode = slicer.vtkMRMLAnnotationRulerNode()
            rulerNode.SetName("Test Ruler")
            m = vtk.vtkMatrix4x4()
            volume.GetIJKToRASMatrix(m)
            ijk0 = [0, 0, 1, 1]
            ijk1 = [50, 50, 1, 1]
            ras0 = m.MultiplyPoint(ijk0)
            ras1 = m.MultiplyPoint(ijk1)
            rulerNode.SetPosition1(19.386751174926758, 68.528785705566406, -127.69000244140625)
            rulerNode.SetPosition2(132.72709655761719, -34.349384307861328, -127.69000244140625)
            rulerNode.SetAttribute("AssociatedNodeID", volume.GetID())
            slicer.mrmlScene.AddNode(rulerNode)
            slicer.app.processEvents()

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

            # Save the report

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

            self.delayDisplay("Report saved")

            slicer.mrmlScene.Clear(0)

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

            # try to load back the saved AIM
            import glob

            print glob.glob(exportDir + "/*")
            xmlFiles = glob.glob(exportDir + "/*xml")
            print xmlFiles

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

            self.delayDisplay("Report loaded from AIM! Test passed.")

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

        except Exception, e:
            if self.originalDatabaseDirectory:
                dicomWidget.onDatabaseDirectoryChanged(self.originalDatabaseDirectory)
            import traceback

            traceback.print_exc()
            self.delayDisplay("Test caused exception!\n" + str(e))
            self.assertTrue(False)
Exemplo n.º 8
0
    def test_LabelToDICOMSEGConverterRoundTrip(self):
        print("CTEST_FULL_OUTPUT")

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

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

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

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

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

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

            self.importDICOM(slicer.dicomDatabase, dicomFilesDirectory)

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

            loadablesByPlugin = dicomWidget.detailsPopup.loadablesByPlugin

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

            # initialize the module with the report and volume

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

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

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

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

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

            self.delayDisplay('Input label initialized')

            module.outputDir = reportingTempDir + '/Output'

            # Save the report

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

            self.delayDisplay('Report saved')

            self.importDICOM(slicer.dicomDatabase, exportDir)

            slicer.mrmlScene.Clear(0)

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

            loadablesByPlugin = dicomWidget.detailsPopup.loadablesByPlugin

            self.delayDisplay('Wait', 10000)

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

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

            self.delayDisplay('Test passed')

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

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