def setUp(self):
   """ Do whatever is needed to reset the state - typically a scene clear will be enough.
   """
   self.UID = '1.3.6.1.4.1.14519.5.2.1.2744.7002.886851941687931416391879144903'
   self.PatientName = 'QIN-HEADNECK-01-0139'
   self.tempDicomDatabase = os.path.join(slicer.app.temporaryPath,'PETTest')
   slicer.mrmlScene.Clear(0)
   self.originalDicomDatabase = DICOMUtils.openTemporaryDatabase(self.tempDicomDatabase)
Example #2
0
    def load_DICOM(self):
        # create temporary database. Save original database path to restore
        # it when finished
        self.original_db_path = DICOMUtils.openTemporaryDatabase()
        #assert temporary database is open

        # import DICOM to database
        DICOMUtils.importDicom(self.locations_dict['DICOM'],
                               slicer.dicomDatabase)

        # get patient name
        patient_name = slicer.dicomDatabase.nameForPatient(
            slicer.dicomDatabase.patients()[0])

        # open DICOM by name
        DICOMUtils.loadPatientByName(patient_name)
        slicer.util.selectModule('SegmentationExtractionModule')
Example #3
0
def main(argv):

    try:
        logging.info("Start batch RTSTRUCT conversion")

        # Parse command-line arguments
        parser = argparse.ArgumentParser(
            description="Batch Structure Set Conversion")
        parser.add_argument(
            "-i",
            "--input-folder",
            dest="input_folder",
            metavar="PATH",
            default="-",
            required=True,
            help=
            "Folder of input DICOM study (or database path to use existing)")
        parser.add_argument(
            "-r",
            "--ref-dicom-folder",
            dest="ref_dicom_folder",
            metavar="PATH",
            default="",
            required=False,
            help=
            "Folder containing reference anatomy DICOM image series, if stored outside the input study"
        )
        parser.add_argument(
            "-u",
            "--use-ref-image",
            dest="use_ref_image",
            default=False,
            required=False,
            action='store_true',
            help=
            "Use anatomy image as reference when converting structure set to labelmap"
        )
        parser.add_argument("-x",
                            "--exist-db",
                            dest="exist_db",
                            default=False,
                            required=False,
                            action='store_true',
                            help="Process an existing database")
        parser.add_argument("-m",
                            "--export-images",
                            dest="export_images",
                            default=False,
                            required=False,
                            action='store_true',
                            help="Export image data with labelmaps")
        parser.add_argument("-o",
                            "--output-folder",
                            dest="output_folder",
                            metavar="PATH",
                            default=".",
                            help="Folder for output labelmaps")
        parser.add_argument("-s",
                            "--export-surfaces",
                            dest="export_surfaces",
                            default=False,
                            required=False,
                            action='store_true',
                            help="Export surface mesh representation")
        parser.add_argument(
            "-c",
            "--show-python-console",
            dest="show_python_console",
            default=False,
            required=False,
            action='store_true',
            help=
            "If this flag is specified then messages are displayed in an interactive Python console and the application does not quit when the script is finished."
        )

        args = parser.parse_args(argv)

        if args.show_python_console:
            slicer.util.pythonShell().show()
            slicer.exit_when_finished = False

        # Check if SlicerRT is installed
        try:
            slicer.modules.dicomrtimportexport
        except AttributeError:
            logging.error("Please install SlicerRT extension")
            return 1

        # Check required arguments
        if args.input_folder == "-":
            logging.warning('Please specify input DICOM study folder!')
        if args.output_folder == ".":
            logging.info(
                'Current directory is selected as output folder (default). To change it, please specify --output-folder'
            )

        # Convert to python path style
        input_folder = args.input_folder.replace('\\', '/')
        ref_dicom_folder = args.ref_dicom_folder.replace('\\', '/')
        output_folder = args.output_folder.replace('\\', '/')

        use_ref_image = args.use_ref_image
        exist_db = args.exist_db
        export_images = args.export_images
        export_surfaces = args.export_surfaces

        # Perform batch conversion
        logic = BatchStructureSetConversionLogic()

        def save_rtslices(output_dir, use_ref_image, ref_image_node_id=None):
            # package the saving code into a subfunction
            logging.info("Convert loaded structure set to labelmap volumes")
            labelmaps = logic.ConvertStructureSetToLabelmap(
                use_ref_image, ref_image_node_id)

            logging.info("Save labelmaps to directory " + output_dir)
            logic.SaveLabelmaps(labelmaps, output_dir)
            if export_surfaces:
                logic.SaveModels(output_dir)
            if export_images:
                logic.SaveImages(output_dir)
            logging.info("DONE")

        if exist_db:
            logging.info('BatchStructureSet running in existing database mode')
            DICOMUtils.openDatabase(input_folder)
            all_patients = slicer.dicomDatabase.patients()
            logging.info('Processing %d patients...' % len(all_patients))

            for patient in all_patients:
                try:
                    slicer.mrmlScene.Clear(0)  # clear the scene
                    DICOMUtils.loadPatientByUID(patient)
                    output_dir = os.path.join(output_folder, patient)
                    if not os.access(output_dir, os.F_OK):
                        os.mkdir(output_dir)
                    save_rtslices(output_dir, use_ref_image)
                except OSError as e:
                    # Failed to load data from this patient, continue with the next one
                    print(e)

        else:
            logging.info('BatchStructureSet running in file mode')
            ref_volume_file_path = None
            if os.path.isdir(ref_dicom_folder):
                # If reference DICOM folder is given and valid, then import reference patient and save its ID
                logging.info("Import reference anatomy DICOM data from " +
                             ref_dicom_folder)
                DICOMUtils.openTemporaryDatabase()
                DICOMUtils.importDicom(ref_dicom_folder)
                # Save first volume to be used as reference
                logic.LoadFirstPatientIntoSlicer()
                scalarVolumeNodes = list(
                    slicer.util.getNodes('vtkMRMLScalarVolume*').values())
                if len(scalarVolumeNodes) > 0:
                    refVolNode = scalarVolumeNodes[0]
                    refVolStorageNode = refVolNode.CreateDefaultStorageNode()
                    ref_volume_file_path = os.path.join(
                        output_folder, 'refVolume.nrrd')
                    refVolStorageNode.SetFileName(ref_volume_file_path)
                    refVolStorageNode.WriteData(refVolNode)

            logging.info("Import DICOM data from " + input_folder)
            DICOMUtils.openTemporaryDatabase()
            DICOMUtils.importDicom(input_folder)

            all_patients = slicer.dicomDatabase.patients()
            logging.info('Processing %d patients...' % len(all_patients))
            for patient in all_patients:
                try:
                    slicer.mrmlScene.Clear(0)  # clear the scene
                    DICOMUtils.loadPatientByUID(patient)
                    output_dir = os.path.join(output_folder, patient)
                    if not os.access(output_dir, os.F_OK):
                        os.mkdir(output_dir)
                    ref_volume_node_id = None
                    if ref_volume_file_path:
                        try:
                            refVolNode = slicer.util.loadVolume(
                                ref_volume_file_path)
                            ref_volume_node_id = refVolNode.GetID()
                        except:
                            pass
                    save_rtslices(output_dir, use_ref_image,
                                  ref_volume_node_id)
                except OSError as e:
                    # Failed to load data from this patient, continue with the next one
                    print(e)

    except Exception as e:
        import traceback
        traceback.print_exc()
        print(e)
        return 1

    return 0
Example #4
0
def main(argv):
  try:
    # Parse command-line arguments
    parser = argparse.ArgumentParser(description="Batch Structure Set Conversion")
    parser.add_argument("-i", "--input-folder", dest="input_folder", metavar="PATH",
                        default="-", required=True, help="Folder of input DICOM study (or database path to use existing)")
    parser.add_argument("-x", "--exist-db", dest="exist_db",
                        default=False, required=False, action='store_true',
                        help="Process an existing database")
    parser.add_argument("-m", "--export-images", dest="export_images",
                        default=False, required=False, action='store_true',
                        help="Export image data with labelmaps")
    parser.add_argument("-o", "--output-folder", dest="output_folder", metavar="PATH",
                        default=".", help="Folder for output labelmaps")

    args = parser.parse_args(argv)

    # Check required arguments
    if args.input_folder == "-":
      logging.warning('Please specify input DICOM study folder!')
    if args.output_folder == ".":
      logging.info('Current directory is selected as output folder (default). To change it, please specify --output-folder')

    # Convert to python path style
    input_folder = args.input_folder.replace('\\', '/')
    output_folder = args.output_folder.replace('\\', '/')
    exist_db = args.exist_db
    export_images = args.export_images

    # Perform batch conversion
    logic = BatchStructureSetConversionLogic()
    def save_rtslices(output_dir):
      # package the saving code into a subfunction
      logging.info("Convert loaded structure set to labelmap volumes")
      labelmaps = logic.ConvertStructureSetToLabelmap()

      logging.info("Save labelmaps to directory " + output_dir)
      logic.SaveLabelmaps(labelmaps, output_dir)
      if export_images:
        logic.SaveImages(output_dir)
      logging.info("DONE")

    if exist_db:
      logging.info('BatchStructureSet running in existing database mode')
      DICOMUtils.openDatabase(input_folder)
      all_patients = slicer.dicomDatabase.patients()
      logging.info('Must Process Patients %s' % len(all_patients))
      for patient in all_patients:
        slicer.mrmlScene.Clear(0) # clear the scene
        DICOMUtils.loadPatientByUID(patient)
        output_dir = os.path.join(output_folder,patient)
        if not os.access(output_dir, os.F_OK):
          os.mkdir(output_dir)
        save_rtslices(output_dir)
    else:
      logging.info("Import DICOM data from " + input_folder)
      DICOMUtils.openTemporaryDatabase()
      DICOMUtils.importDicom(input_folder)

      logging.info("Load first patient into Slicer")
      logic.LoadFirstPatientIntoSlicer()
      save_rtslices(output_folder)

  except Exception as e:
      print(e)
  sys.exit(0)
Example #5
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)
Example #6
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))
Example #7
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
Example #8
0
    def test_Part1DICOM(self):
        """ Test the DICOM part of the test using the head atlas
        """
        import os
        self.delayDisplay("Starting the DICOM test")
        #
        # first, get the data - a zip file of dicom data
        #
        import SampleData
        dicomFilesDirectory = SampleData.downloadFromURL(
            fileNames='Dcmtk-db.zip',
            uris=TESTING_DATA_URL + 'MD5/7a43d121a51a631ab0df02071e5ba6ed',
            checksums='MD5:7a43d121a51a631ab0df02071e5ba6ed')[0]

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

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

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

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

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

            self.delayDisplay('Retrieve DICOM')
            slicer.util.selectModule('DICOM')
            dicomRetrieve = ctk.ctkDICOMRetrieve()
            dicomRetrieve.setKeepAssociationOpen(True)
            dicomRetrieve.setDatabase(slicer.dicomDatabase)
            dicomRetrieve.setCallingAETitle('SlicerAE')
            dicomRetrieve.setCalledAETitle('DCMTK')
            dicomRetrieve.setPort(12345)
            dicomRetrieve.setHost('localhost')
            dicomRetrieve.getStudy(
                '1.2.124.113932.1.170.223.162.178.20050502.160340.12640015')
            popen.kill()

            # Select first patient
            browserWidget = slicer.modules.DICOMWidget.browserWidget
            browserWidget.dicomBrowser.dicomTableManager().patientsTable(
            ).selectFirst()
            browserWidget.examineForLoading()

            self.delayDisplay('Loading Selection')
            browserWidget.loadCheckedLoadables()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            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)
Example #9
0
def main(argv):
    # Parse command-line arguments
    parser = argparse.ArgumentParser(description="Batch Structure Set Conversion")
    parser.add_argument(
        "-i",
        "--input-folder",
        dest="input_folder",
        metavar="PATH",
        default="-",
        required=True,
        help="Folder of input DICOM study (or database path to use existing)",
    )
    parser.add_argument(
        "-o", "--output-folder", dest="output_folder", metavar="PATH", default=".", help="Folder for output labelmaps"
    )
    parser.add_argument(
        "-r",
        "--register",
        dest="register",
        metavar="PATH",
        default="no_registration",
        help='"T1" for registration to T1 image, "T2" for registration to T2 image. ' 'Defaults to "no_registration".',
    )
    parser.add_argument(
        "--export_all_structures",
        dest="export_all_structures",
        action="store_true",
        help="All available structures will be exported. By default, only the VS is exported.",
    )
    parser.set_defaults(export_all_structures=False)

    args = parser.parse_args(argv)

    # Check required arguments
    if args.input_folder == "-":
        logging.warning("Please specify input DICOM study folder!")
    if args.output_folder == ".":
        logging.info(
            "Current directory is selected as output folder (default). To change it, please specify --output-folder"
        )
    if args.register not in ["no_registration", "T1", "T2"]:
        logging.error('Invalid value for keyword "--register": choose "T1" or "T2" or "no_registration"')

    # Convert to python path style
    input_folder = args.input_folder.replace("\\", "/")
    output_folder = args.output_folder.replace("\\", "/")
    register = args.register
    export_all_structures = args.export_all_structures

    register_T1_image_and_contour_points_to_T2_image = False
    register_T2_image_and_contour_points_to_T1_image = False
    if register == "T1":
        register_T2_image_and_contour_points_to_T1_image = True
    elif register == "T2":
        register_T1_image_and_contour_points_to_T2_image = True

    if export_all_structures:
        export_only_tumour_seg = False
    else:
        export_only_tumour_seg = True

    if not os.access(output_folder, os.F_OK):
        os.mkdir(output_folder)

    DICOMUtils.openTemporaryDatabase()

    patient_dirs = glob.glob(os.path.join(input_folder, "vs_gk_*"))

    # create and compile a regex pattern
    pattern = re.compile(r"_([0-9]+)_t[1-2]$")

    case_numbers = []

    # first_case = 1
    # last_case = 2

    # for case_number in range(first_case, last_case + 1):
    # exclude cases
    # if case_number in [39, 97, 130, 160, 168, 208, 219, 227]:
    #     continue

    for i in range(len(patient_dirs)):
        # get case number from folder name
        print(pattern.findall(patient_dirs[i]))
        case_number = pattern.findall(patient_dirs[i])[0]

        # skip iteration if case has already been dealt with
        if case_number in case_numbers:
            continue
        case_numbers.append(case_number)

        print(f"case: {case_number}")

        [ref1, ref2, RTSS1, RTSS2] = import_T1_and_T2_data(input_folder, case_number)

        ## REGISTRATION

        if register_T1_image_and_contour_points_to_T2_image:
            transform_path = os.path.join(input_folder, f"vs_gk_{case_number}" + "_t1", "inv_T1_LPS_to_T2_LPS.tfm")
            transformNode = slicer.util.loadNodeFromFile(transform_path, filetype="TransformFile")
            ref1 = register_and_resample(
                input_node=ref1, reference_node=ref2, transform_node=transformNode, interpolationMode="Linear"
            )
            # also transform contour points
            RTSS1.SetAndObserveTransformNodeID(transformNode.GetID())

        elif register_T2_image_and_contour_points_to_T1_image:
            transform_path = os.path.join(input_folder, f"vs_gk_{case_number}" + "_t2", "inv_T2_LPS_to_T1_LPS.tfm")
            transformNode = slicer.util.loadNodeFromFile(transform_path, filetype="TransformFile")
            ref2 = register_and_resample(
                input_node=ref2, reference_node=ref1, transform_node=transformNode, interpolationMode="Linear"
            )
            # also transform contour points
            RTSS2.SetAndObserveTransformNodeID(transformNode.GetID())

        ## Create segments from contour files
        # Create segmentation node where we will store segments
        segmentationNode_T1 = create_segmentation_node_with_reference_geometry(
            "SegmentationFromContourPoints_refT1", ref_geometry_image_node=ref1
        )
        segmentationNode_T2 = create_segmentation_node_with_reference_geometry(
            "SegmentationFromContourPoints_refT2", ref_geometry_image_node=ref2
        )

        # load structure contour list from json file
        # these are registered to original T1 and T2 images (they are not affected by registrations of the ref_geometry
        # node, which only defines extent and the IJK to RAS transformation)
        structure_contour_list_T1 = load_LPS_contour_points(
            os.path.join(input_folder, f"vs_gk_{case_number}" + "_t1", "contours.json")
        )
        structure_contour_list_T2 = load_LPS_contour_points(
            os.path.join(input_folder, f"vs_gk_{case_number}" + "_t2", "contours.json")
        )

        # create segments for all structures
        create_segments_from_structure_contour_list(segmentationNode_T1, structure_contour_list_T1)
        create_segments_from_structure_contour_list(segmentationNode_T2, structure_contour_list_T2)

        ## export all files

        if register_T1_image_and_contour_points_to_T2_image:
            lm_node_in_T2_list = save_labelmaps_from_planar_contour(
                segmentationNode_T2, ref2, export_only_tumour_seg, case_number, output_folder
            )  # save contour points registered to T2 image
        if register_T2_image_and_contour_points_to_T1_image:
            lm_node_in_T1_list = save_labelmaps_from_planar_contour(
                segmentationNode_T1, ref1, export_only_tumour_seg, case_number, output_folder
            )

        if not register_T1_image_and_contour_points_to_T2_image and not register_T2_image_and_contour_points_to_T1_image:
            lm_node_in_T2_list = save_labelmaps_from_planar_contour(
                segmentationNode_T2, ref2, export_only_tumour_seg, case_number, output_folder
            )  # save contour points registered to T2 image
            lm_node_in_T1_list = save_labelmaps_from_planar_contour(
                segmentationNode_T1, ref1, export_only_tumour_seg, case_number, output_folder
            )

        # save images as nifti files
        if register_T1_image_and_contour_points_to_T2_image:
            slicer.util.saveNode(
                ref1, os.path.join(output_folder, f"vs_gk_{case_number}", f"vs_gk_t1_refT2.nii.gz")
            )  # pass vol node and destination filename
            slicer.util.saveNode(
                ref2, os.path.join(output_folder, f"vs_gk_{case_number}", f"vs_gk_t2_refT2.nii.gz")
            )  # pass vol node and destination filename
        if register_T2_image_and_contour_points_to_T1_image:
            slicer.util.saveNode(
                ref1, os.path.join(output_folder, f"vs_gk_{case_number}", f"vs_gk_t1_refT1.nii.gz")
            )  # pass vol node and destination filename
            slicer.util.saveNode(
                ref2, os.path.join(output_folder, f"vs_gk_{case_number}", f"vs_gk_t2_refT1.nii.gz")
            )  # pass vol node and destination filename

        if not register_T1_image_and_contour_points_to_T2_image and not register_T2_image_and_contour_points_to_T1_image:
            slicer.util.saveNode(
                ref1, os.path.join(output_folder, f"vs_gk_{case_number}", f"vs_gk_t1_refT1.nii.gz")
            )  # pass vol node and destination filename
            slicer.util.saveNode(
                ref2, os.path.join(output_folder, f"vs_gk_{case_number}", f"vs_gk_t2_refT2.nii.gz")
            )  # pass vol node and destination filename
    sys.exit(0)
Example #10
0
parser.add_argument("--input", help="Input DICOM directory")
parser.add_argument("--output", help="Output directory")
parser.add_argument("--filename", help="File name")
args = parser.parse_args()

if args.dcmtk and args.gdcm:
    raise ValueError("Cannot specify both gdcm and dcmtk")
if args.dcmtk:
    setDICOMReaderApproach('DCMTK')
if args.gdcm:
    setDICOMReaderApproach('GDCM')

indexer = ctk.ctkDICOMIndexer()
dbDir = "/tmp/SlicerDB"
print("Temporary directory:  " + dbDir)
DICOMUtils.openTemporaryDatabase(dbDir)
db = slicer.dicomDatabase
print("indexing {}".format(args.input))
indexer.addDirectory(db, args.input)
indexer.waitForImportFinished()

slicer.util.selectModule('DICOM')

fileLists = []
for patient in db.patients():
    print("Patient:" + patient)
    for study in db.studiesForPatient(patient):
        print("Study:" + study)
        for series in db.seriesForStudy(study):
            print("Series:" + series)
            fileLists.append(db.filesForSeries(series))
Example #11
0
def main(argv):
    try:
        # Parse command-line arguments
        parser = argparse.ArgumentParser(
            description="Batch Structure Set Conversion")
        parser.add_argument(
            "-i",
            "--input-folder",
            dest="input_folder",
            metavar="PATH",
            default="-",
            required=True,
            help=
            "Folder of input DICOM study (or database path to use existing)")
        parser.add_argument(
            "-r",
            "--ref-dicom-folder",
            dest="ref_dicom_folder",
            metavar="PATH",
            default="",
            required=False,
            help=
            "Folder containing reference anatomy DICOM image series, if stored outside the input study"
        )
        parser.add_argument(
            "-u",
            "--use-ref-image",
            dest="use_ref_image",
            default=False,
            required=False,
            action='store_true',
            help=
            "Use anatomy image as reference when converting structure set to labelmap"
        )
        parser.add_argument("-x",
                            "--exist-db",
                            dest="exist_db",
                            default=False,
                            required=False,
                            action='store_true',
                            help="Process an existing database")
        parser.add_argument("-m",
                            "--export-images",
                            dest="export_images",
                            default=False,
                            required=False,
                            action='store_true',
                            help="Export image data with labelmaps")
        parser.add_argument("-o",
                            "--output-folder",
                            dest="output_folder",
                            metavar="PATH",
                            default=".",
                            help="Folder for output labelmaps")

        args = parser.parse_args(argv)

        # Check required arguments
        if args.input_folder == "-":
            logging.warning('Please specify input DICOM study folder!')
        if args.output_folder == ".":
            logging.info(
                'Current directory is selected as output folder (default). To change it, please specify --output-folder'
            )

        # Convert to python path style
        input_folder = args.input_folder.replace('\\', '/')
        ref_dicom_folder = args.ref_dicom_folder.replace('\\', '/')
        output_folder = args.output_folder.replace('\\', '/')

        use_ref_image = args.use_ref_image
        exist_db = args.exist_db
        export_images = args.export_images

        # Perform batch conversion
        logic = BatchStructureSetConversionLogic()

        def save_rtslices(output_dir, use_ref_image, ref_image_node_id=None):
            # package the saving code into a subfunction
            logging.info("Convert loaded structure set to labelmap volumes")
            labelmaps = logic.ConvertStructureSetToLabelmap(
                use_ref_image, ref_image_node_id)

            logging.info("Save labelmaps to directory " + output_dir)
            logic.SaveLabelmaps(labelmaps, output_dir)
            if export_images:
                logic.SaveImages(output_dir)
            logging.info("DONE")

        if exist_db:
            logging.info('BatchStructureSet running in existing database mode')
            DICOMUtils.openDatabase(input_folder)
            all_patients = slicer.dicomDatabase.patients()
            logging.info('Must Process Patients %s' % len(all_patients))

            for patient in all_patients:
                slicer.mrmlScene.Clear(0)  # clear the scene
                DICOMUtils.loadPatientByUID(patient)
                output_dir = os.path.join(output_folder, patient)
                if not os.access(output_dir, os.F_OK):
                    os.mkdir(output_dir)
                save_rtslices(output_dir, use_ref_image)

        else:
            ref_image_node_id = None
            if os.path.isdir(ref_dicom_folder):
                # If reference DICOM folder is given and valid, then load that volume
                logging.info("Import reference anatomy DICOM data from " +
                             ref_dicom_folder)
                DICOMUtils.openTemporaryDatabase()
                DICOMUtils.importDicom(ref_dicom_folder)
                logic.LoadFirstPatientIntoSlicer()
                # Remember first volume
                scalarVolumeNodes = list(
                    slicer.util.getNodes('vtkMRMLScalarVolume*').values())
                if len(scalarVolumeNodes) > 0:
                    ref_image_node_id = scalarVolumeNodes[0].GetID()

            logging.info("Import DICOM data from " + input_folder)
            DICOMUtils.openTemporaryDatabase()
            DICOMUtils.importDicom(input_folder)

            logging.info("Load first patient into Slicer")
            logic.LoadFirstPatientIntoSlicer()
            save_rtslices(output_folder, use_ref_image, ref_image_node_id)

    except Exception as e:
        print(e)
    sys.exit(0)
Example #12
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 main(argv):
  try:
    # Parse command-line arguments
    parser = argparse.ArgumentParser(description="Batch Structure Set Conversion")
    parser.add_argument("-i", "--input-folder", dest="input_folder", metavar="PATH",
                        default="-", required=True, help="Folder of input DICOM study (or database path to use existing)")
    parser.add_argument("-x", "--exist-db", dest="exist_db",
                        default=False, required=False, action='store_true',
                        help="Process an existing database")
    parser.add_argument("-m", "--export-images", dest="export_images",
                        default=False, required=False, action='store_true',
                        help="Export image data with labelmaps")
    parser.add_argument("-o", "--output-folder", dest="output_folder", metavar="PATH",
                        default=".", help="Folder for output labelmaps")

    args = parser.parse_args(argv)

    # Check required arguments
    if args.input_folder == "-":
      logging.warning('Please specify input DICOM study folder!')
    if args.output_folder == ".":
      logging.info('Current directory is selected as output folder (default). To change it, please specify --output-folder')

    # Convert to python path style
    input_folder = args.input_folder.replace('\\', '/')
    output_folder = args.output_folder.replace('\\', '/')
    exist_db = args.exist_db
    export_images = args.export_images

    # Perform batch conversion
    logic = BatchStructureSetConversionLogic()
    def save_rtslices(output_dir):
      # package the saving code into a subfunction
      logging.info("Convert loaded structure set to labelmap volumes")
      labelmaps = logic.ConvertStructureSetToLabelmap()

      logging.info("Save labelmaps to directory " + output_dir)
      logic.SaveLabelmaps(labelmaps, output_dir)
      if export_images:
        logic.SaveImages(output_dir)
      logging.info("DONE")

    if exist_db:
      logging.info('BatchStructureSet running in existing database mode')
      DICOMUtils.openDatabase(input_folder)
      all_patients = slicer.dicomDatabase.patients()
      logging.info('Must Process Patients %s' % len(all_patients))
      for patient in all_patients:
        slicer.mrmlScene.Clear(0) # clear the scene
        DICOMUtils.loadPatientByUID(patient)
        output_dir = os.path.join(output_folder,patient)
        if not os.access(output_dir, os.F_OK):
          os.mkdir(output_dir)
        save_rtslices(output_dir)
    else:
      logging.info("Import DICOM data from " + input_folder)
      DICOMUtils.openTemporaryDatabase()
      DICOMUtils.importDicom(input_folder)

      logging.info("Load first patient into Slicer")
      logic.LoadFirstPatientIntoSlicer()
      save_rtslices(output_folder)

  except Exception, e:
      print(e)
Example #14
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")

    settings = qt.QSettings()
    settings.setValue("DICOM/ScalarVolume/AcquisitionGeometryRegularization", "transform")

    import SampleData
    dicomFilesDirectory = SampleData.downloadFromURL(
      fileNames='deidentifiedMRHead-dcm-one-series.zip',
      uris='http://slicer.kitware.com/midas3/download?items=294857',
      checksums='SHA256:899f3f8617ca53bad7dca0b2908478319e708b48ff41dfa64b6bac1d76529928')[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')
      slicer.util.selectModule("DICOM")

      browserWidget = slicer.modules.DICOMWidget.browserWidget
      dicomBrowser = browserWidget.dicomBrowser
      dicomBrowser.importDirectory(dicomFilesDirectory, dicomBrowser.ImportDirectoryAddLink)
      dicomBrowser.waitForImportFinished()

      #
      # select the series
      #
      browserWidget.onSeriesSelected([seriesUID])
      # load the data by series UID
      browserWidget.examineForLoading()
      loadable = list(browserWidget.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 as e:
      import traceback
      traceback.print_exc()
      self.delayDisplay('Missing Slices Test caused exception!\n' + str(e))
      testPass = False

    self.delayDisplay("Restoring original database directory")
    DICOMUtils.closeTemporaryDatabase(originalDatabaseDirectory)
    slicer.util.selectModule('DICOMReaders')

    return testPass
Example #15
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
Example #16
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",
        "checksum": "SHA256:3450ef9372a3460a2f181c8d3bb35a74b4f0acb10c6e18cfcf7804e1d99bf843",
        "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",
        # GDCM rejects loading. 
        # DCMTK reads it but then ITK rejects loading the image with 0 spacing.
        "expectedFailures": ["GDCM", "Archetype", "DCMTK", "GDCM with DCMTK fallback"],
        "voxelValueQuantity": "(110852, DCM, \"MR signal intensity\")",
        "voxelValueUnits": "(1, UCUM, \"no units\")"
      },
      { "url": "http://slicer.kitware.com/midas3/download?items=294857",
        "checksum": "SHA256:899f3f8617ca53bad7dca0b2908478319e708b48ff41dfa64b6bac1d76529928",
        "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'], checksums=dataset['checksum'])[0]
        self.delayDisplay('Finished with download')

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

        self.delayDisplay('Importing DICOM')
        slicer.util.selectModule("DICOM")

        browserWidget = slicer.modules.DICOMWidget.browserWidget
        dicomBrowser = browserWidget.dicomBrowser
        dicomBrowser.importDirectory(dicomFilesDirectory, dicomBrowser.ImportDirectoryAddLink)
        dicomBrowser.waitForImportFinished()

        #
        # select the series
        #
        browserWidget.onSeriesSelected([dataset['seriesUID']])
        # load the data by series UID
        browserWidget.examineForLoading()
        loadable = list(browserWidget.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 = list(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 as e:
        import traceback
        traceback.print_exc()
        self.delayDisplay('%s Test caused exception!\n' % dataset['name'] + str(e))
        testPass = False

    self.delayDisplay("Restoring original database directory")
    DICOMUtils.closeTemporaryDatabase(originalDatabaseDirectory)
    slicer.util.selectModule('DICOMReaders')

    logging.info(loadingResult)

    return testPass
Example #17
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
Example #18
0
  def test_Part1DICOM(self):
    """ Test the DICOM part of the test using the head atlas
    """

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

      self.delayDisplay('Test passed!')
    except Exception, e:
      import traceback
      traceback.print_exc()
      self.delayDisplay('Test caused exception!\n' + str(e))
    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=TESTING_DATA_URL +
            'SHA256/17a4199aad03a373dab27dc17e5bfcf84fc194d0a30975b4073e5b595d43a56a',
            checksums=
            'SHA256:17a4199aad03a373dab27dc17e5bfcf84fc194d0a30975b4073e5b595d43a56a'
        )[0]

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

            slicer.util.selectModule('DICOM')
            browserWidget = slicer.modules.DICOMWidget.browserWidget
            dicomBrowser = browserWidget.dicomBrowser
            dicomBrowser.importDirectory(dicomFilesDirectory,
                                         dicomBrowser.ImportDirectoryAddLink)
            dicomBrowser.waitForImportFinished()

            # load the data by series UID
            dicomBrowser.dicomTableManager().patientsTable().selectFirst()
            browserWidget.examineForLoading()

            self.delayDisplay('Loading Selection')
            browserWidget.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.mrmlVolumePropertyNode().Copy(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)
Example #20
0
    def test_Part1DICOM(self):
        """ Test the DICOM part of the test using the head atlas
    """

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            self.delayDisplay('Test passed!')
        except Exception, e:
            import traceback
            traceback.print_exc()
            self.delayDisplay('Test caused exception!\n' + str(e))
Example #21
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