Example #1
0
def generateSlicenamesTextfile(ctDicomSeriesUID, slicenamesFilename,
                               outputFolder):
    """ Generate slicenames.txt file, with list of ct dicom slices, in increasing slice order (IS direction)
  """
    filePaths = slicer.dicomDatabase.filesForSeries(ctDicomSeriesUID)
    if len(filePaths) == 0:
        logging.error('Failed to find files in DICOM database for UID ' +
                      str(ctDicomSeriesUID))
        return False

    from DICOMLib import DICOMUtils
    unsortedFileList = slicer.dicomDatabase.filesForSeries(ctDicomSeriesUID)
    sortedFileList, distances, warnings = DICOMUtils.getSortedImageFiles(
        unsortedFileList)

    outFile = open(os.path.join(outputFolder, slicenamesFilename), "w")
    counter = 1
    numDicomFiles = len(sortedFileList)
    for sliceFileName in sortedFileList:
        outFile.write(sliceFileName)
        if counter != numDicomFiles:
            outFile.write("\n")
        counter += 1
    outFile.close()
    return True
def generateSlicenamesTextfile(ctDicomSeriesUID, slicenamesFilename, 
  outputFolder):
  """ Generate slicenames.txt file, with list of ct dicom slices, in increasing slice order (IS direction)
  """
  filePaths = slicer.dicomDatabase.filesForSeries(ctDicomSeriesUID)
  if len(filePaths) == 0:
    logging.error('Failed to find files in DICOM database for UID ' + str(ctDicomSeriesUID))
    return False

  unsortedFileList = slicer.dicomDatabase.filesForSeries(ctDicomSeriesUID)
  sortedFileList, distances, warnings = DICOMUtils.getSortedImageFiles(unsortedFileList)

  outFile = open(os.path.join(outputFolder, slicenamesFilename), "wb")
  counter = 1
  numDicomFiles = len(sortedFileList)
  for sliceFileName in   sortedFileList:
    outFile.write(sliceFileName)
    if counter != numDicomFiles:
      outFile.write("\n")
    counter += 1
  outFile.close()
  return True
Example #3
0
    def examineFiles(self, files):
        """ Returns a list of DICOMLoadable instances
    corresponding to ways of interpreting the
    files parameter.
    """

        seriesUID = slicer.dicomDatabase.fileValue(files[0],
                                                   self.tags['seriesUID'])
        seriesName = self.defaultSeriesNodeName(seriesUID)

        # default loadable includes all files for series
        loadable = DICOMLoadable()
        loadable.files = files
        loadable.name = seriesName
        loadable.tooltip = "%d files, first file: %s" % (len(
            loadable.files), loadable.files[0])
        loadable.selected = True
        # add it to the list of loadables later, if pixel data is available in at least one file

        # make subseries volumes based on tag differences
        subseriesTags = [
            "seriesInstanceUID",
            "imageOrientationPatient",
            "diffusionGradientOrientation",
        ]

        if self.allowLoadingByTime():
            subseriesTags.append("contentTime")
            subseriesTags.append("triggerTime")

        #
        # first, look for subseries within this series
        # - build a list of files for each unique value
        #   of each tag
        #
        subseriesFiles = {}
        subseriesValues = {}
        for file in loadable.files:
            # check for subseries values
            for tag in subseriesTags:
                value = slicer.dicomDatabase.fileValue(file, self.tags[tag])
                value = value.replace(
                    ",", "_")  # remove commas so it can be used as an index
                if tag not in subseriesValues:
                    subseriesValues[tag] = []
                if not subseriesValues[tag].__contains__(value):
                    subseriesValues[tag].append(value)
                if (tag, value) not in subseriesFiles:
                    subseriesFiles[tag, value] = []
                subseriesFiles[tag, value].append(file)

        loadables = []

        # Pixel data is available, so add the default loadable to the output
        loadables.append(loadable)

        #
        # second, for any tags that have more than one value, create a new
        # virtual series
        #
        for tag in subseriesTags:
            if len(subseriesValues[tag]) > 1:
                for valueIndex, value in enumerate(subseriesValues[tag]):
                    # default loadable includes all files for series
                    loadable = DICOMLoadable()
                    loadable.files = subseriesFiles[tag, value]
                    # value can be a long string (and it will be used for generating node name)
                    # therefore use just an index instead
                    loadable.name = seriesName + " - %s %d" % (tag,
                                                               valueIndex + 1)
                    loadable.tooltip = "%d files, grouped by %s = %s. First file: %s" % (
                        len(loadable.files), tag, value, loadable.files[0])
                    loadable.selected = False
                    loadables.append(loadable)

        # remove any files from loadables that don't have pixel data (no point sending them to ITK for reading)
        # also remove DICOM SEG, since it is not handled by ITK readers
        newLoadables = []
        for loadable in loadables:
            newFiles = []
            excludedLoadable = False
            for file in loadable.files:
                if slicer.dicomDatabase.fileValue(
                        file, self.tags['pixelData']) != '':
                    newFiles.append(file)
                if slicer.dicomDatabase.fileValue(
                        file, self.tags['sopClassUID']
                ) == '1.2.840.10008.5.1.4.1.1.66.4':
                    excludedLoadable = True
                    logging.error(
                        'Please install Quantitative Reporting extension to enable loading of DICOM Segmentation objects'
                    )
                elif slicer.dicomDatabase.fileValue(
                        file, self.tags['sopClassUID']
                ) == '1.2.840.10008.5.1.4.1.1.481.3':
                    excludedLoadable = True
                    logging.error(
                        'Please install SlicerRT extension to enable loading of DICOM RT Structure Set objects'
                    )
            if len(newFiles) > 0 and not excludedLoadable:
                loadable.files = newFiles
                newLoadables.append(loadable)
            elif excludedLoadable:
                continue
            else:
                # here all files in have no pixel data, so they might be
                # secondary capture images which will read, so let's pass
                # them through with a warning and low confidence
                loadable.warning += "There is no pixel data attribute for the DICOM objects, but they might be readable as secondary capture images.  "
                loadable.confidence = 0.2
                newLoadables.append(loadable)
        loadables = newLoadables

        #
        # now for each series and subseries, sort the images
        # by position and check for consistency
        #
        for loadable in loadables:
            loadable.files, distances, loadable.warning = DICOMUtils.getSortedImageFiles(
                loadable.files, self.epsilon)

        return loadables
Example #4
0
  def examineFiles(self,files):
    """ Returns a list of DICOMLoadable instances
    corresponding to ways of interpreting the
    files parameter.
    """

    seriesUID = slicer.dicomDatabase.fileValue(files[0],self.tags['seriesUID'])
    seriesName = self.defaultSeriesNodeName(seriesUID)

    # default loadable includes all files for series
    loadable = DICOMLoadable()
    loadable.files = files
    loadable.name = seriesName
    loadable.tooltip = "%d files, first file: %s" % (len(loadable.files), loadable.files[0])
    loadable.selected = True
    # add it to the list of loadables later, if pixel data is available in at least one file

    # make subseries volumes based on tag differences
    subseriesTags = [
        "seriesInstanceUID",
        "imageOrientationPatient",
        "diffusionGradientOrientation",
    ]

    if self.allowLoadingByTime():
      subseriesTags.append("contentTime")
      subseriesTags.append("triggerTime")

    #
    # first, look for subseries within this series
    # - build a list of files for each unique value
    #   of each tag
    #
    subseriesFiles = {}
    subseriesValues = {}
    for file in loadable.files:
      # check for subseries values
      for tag in subseriesTags:
        value = slicer.dicomDatabase.fileValue(file,self.tags[tag])
        value = value.replace(",","_") # remove commas so it can be used as an index
        if tag not in subseriesValues:
          subseriesValues[tag] = []
        if not subseriesValues[tag].__contains__(value):
          subseriesValues[tag].append(value)
        if (tag,value) not in subseriesFiles:
          subseriesFiles[tag,value] = []
        subseriesFiles[tag,value].append(file)

    loadables = []

    # Pixel data is available, so add the default loadable to the output
    loadables.append(loadable)

    #
    # second, for any tags that have more than one value, create a new
    # virtual series
    #
    for tag in subseriesTags:
      if len(subseriesValues[tag]) > 1:
        for valueIndex, value in enumerate(subseriesValues[tag]):
          # default loadable includes all files for series
          loadable = DICOMLoadable()
          loadable.files = subseriesFiles[tag,value]
          # value can be a long string (and it will be used for generating node name)
          # therefore use just an index instead
          loadable.name = seriesName + " - %s %d" % (tag,valueIndex+1)
          loadable.tooltip = "%d files, grouped by %s = %s. First file: %s" % (len(loadable.files), tag, value, loadable.files[0])
          loadable.selected = False
          loadables.append(loadable)

    # remove any files from loadables that don't have pixel data (no point sending them to ITK for reading)
    # also remove DICOM SEG, since it is not handled by ITK readers
    newLoadables = []
    for loadable in loadables:
      newFiles = []
      excludedLoadable = False
      for file in loadable.files:
        if slicer.dicomDatabase.fileValue(file,self.tags['pixelData'])!='':
          newFiles.append(file)
        if slicer.dicomDatabase.fileValue(file,self.tags['sopClassUID'])=='1.2.840.10008.5.1.4.1.1.66.4':
          excludedLoadable = True
          logging.error('Please install Quantitative Reporting extension to enable loading of DICOM Segmentation objects')
        elif slicer.dicomDatabase.fileValue(file,self.tags['sopClassUID'])=='1.2.840.10008.5.1.4.1.1.481.3':
          excludedLoadable = True
          logging.error('Please install SlicerRT extension to enable loading of DICOM RT Structure Set objects')
      if len(newFiles) > 0 and not excludedLoadable:
        loadable.files = newFiles
        newLoadables.append(loadable)
      elif excludedLoadable:
        continue
      else:
        # here all files in have no pixel data, so they might be
        # secondary capture images which will read, so let's pass
        # them through with a warning and low confidence
        loadable.warning += "There is no pixel data attribute for the DICOM objects, but they might be readable as secondary capture images.  "
        loadable.confidence = 0.2
        newLoadables.append(loadable)
    loadables = newLoadables

    #
    # now for each series and subseries, sort the images
    # by position and check for consistency
    #
    for loadable in loadables:
      loadable.files, distances, loadable.warning = DICOMUtils.getSortedImageFiles(loadable.files, self.epsilon)

    return loadables
Example #5
0
    def examineFiles(self, files):
        """ Returns a list of DICOMLoadable instances
    corresponding to ways of interpreting the
    files parameter.
    """

        seriesUID = slicer.dicomDatabase.fileValue(files[0],
                                                   self.tags['seriesUID'])
        seriesName = self.defaultSeriesNodeName(seriesUID)

        # default loadable includes all files for series
        allFilesLoadable = DICOMLoadable()
        allFilesLoadable.files = files
        allFilesLoadable.name = self.cleanNodeName(seriesName)
        allFilesLoadable.tooltip = "%d files, first file: %s" % (len(
            allFilesLoadable.files), allFilesLoadable.files[0])
        allFilesLoadable.selected = True
        # add it to the list of loadables later, if pixel data is available in at least one file

        # make subseries volumes based on tag differences
        subseriesTags = [
            "seriesInstanceUID",
            "acquisitionNumber",
            # GE volume viewer and Siemens Axiom CBCT systems put an overview (localizer) slice and all the reconstructed slices
            # in one series, using two different image types. Splitting based on image type allows loading of these volumes
            # (loading the series without localizer).
            "imageType",
            "imageOrientationPatient",
            "diffusionGradientOrientation",
        ]

        if self.allowLoadingByTime():
            subseriesTags.append("contentTime")
            subseriesTags.append("triggerTime")

        # Values for these tags will only be enumerated (value itself will not be part of the loadable name)
        # because the vale itself is usually too long and complicated to be displayed to users
        subseriesTagsToEnumerateValues = [
            "seriesInstanceUID",
            "imageOrientationPatient",
            "diffusionGradientOrientation",
        ]

        #
        # first, look for subseries within this series
        # - build a list of files for each unique value
        #   of each tag
        #
        subseriesFiles = {}
        subseriesValues = {}
        for file in allFilesLoadable.files:
            # check for subseries values
            for tag in subseriesTags:
                value = slicer.dicomDatabase.fileValue(file, self.tags[tag])
                value = value.replace(
                    ",", "_")  # remove commas so it can be used as an index
                if tag not in subseriesValues:
                    subseriesValues[tag] = []
                if not subseriesValues[tag].__contains__(value):
                    subseriesValues[tag].append(value)
                if (tag, value) not in subseriesFiles:
                    subseriesFiles[tag, value] = []
                subseriesFiles[tag, value].append(file)

        loadables = []

        # Pixel data is available, so add the default loadable to the output
        loadables.append(allFilesLoadable)

        #
        # second, for any tags that have more than one value, create a new
        # virtual series
        #
        subseriesCount = 0
        # List of loadables that look like subseries that contain the full series except a single frame
        probableLocalizerFreeLoadables = []
        for tag in subseriesTags:
            if len(subseriesValues[tag]) > 1:
                subseriesCount += 1
                for valueIndex, value in enumerate(subseriesValues[tag]):
                    # default loadable includes all files for series
                    loadable = DICOMLoadable()
                    loadable.files = subseriesFiles[tag, value]
                    # value can be a long string (and it will be used for generating node name)
                    # therefore use just an index instead
                    if tag in subseriesTagsToEnumerateValues:
                        loadable.name = seriesName + " - %s %d" % (
                            tag, valueIndex + 1)
                    else:
                        loadable.name = seriesName + " - %s %s" % (tag, value)
                    loadable.name = self.cleanNodeName(loadable.name)
                    loadable.tooltip = "%d files, grouped by %s = %s. First file: %s. %s = %s" % (
                        len(loadable.files), tag, value, loadable.files[0],
                        tag, value)
                    loadable.selected = False
                    loadables.append(loadable)
                    if len(subseriesValues[tag]) == 2:
                        otherValue = subseriesValues[tag][1 - valueIndex]
                        if len(subseriesFiles[tag, value]) > 1 and len(
                                subseriesFiles[tag, otherValue]) == 1:
                            # this looks like a subseries without a localizer image
                            probableLocalizerFreeLoadables.append(loadable)

        # remove any files from loadables that don't have pixel data (no point sending them to ITK for reading)
        # also remove DICOM SEG, since it is not handled by ITK readers
        newLoadables = []
        for loadable in loadables:
            newFiles = []
            excludedLoadable = False
            for file in loadable.files:
                if slicer.dicomDatabase.fileValueExists(
                        file, self.tags['pixelData']):
                    newFiles.append(file)
                if slicer.dicomDatabase.fileValue(
                        file, self.tags['sopClassUID']
                ) == '1.2.840.10008.5.1.4.1.1.66.4':
                    excludedLoadable = True
                    if 'DICOMSegmentationPlugin' not in slicer.modules.dicomPlugins:
                        logging.warning(
                            'Please install Quantitative Reporting extension to enable loading of DICOM Segmentation objects'
                        )
                elif slicer.dicomDatabase.fileValue(
                        file, self.tags['sopClassUID']
                ) == '1.2.840.10008.5.1.4.1.1.481.3':
                    excludedLoadable = True
                    if 'DicomRtImportExportPlugin' not in slicer.modules.dicomPlugins:
                        logging.warning(
                            'Please install SlicerRT extension to enable loading of DICOM RT Structure Set objects'
                        )
            if len(newFiles) > 0 and not excludedLoadable:
                loadable.files = newFiles
                loadable.grayscale = (
                    'MONOCHROME' in slicer.dicomDatabase.fileValue(
                        newFiles[0], self.tags['photometricInterpretation']))
                newLoadables.append(loadable)
            elif excludedLoadable:
                continue
            else:
                # here all files in have no pixel data, so they might be
                # secondary capture images which will read, so let's pass
                # them through with a warning and low confidence
                loadable.warning += "There is no pixel data attribute for the DICOM objects, but they might be readable as secondary capture images.  "
                loadable.confidence = 0.2
                loadable.grayscale = (
                    'MONOCHROME' in slicer.dicomDatabase.fileValue(
                        loadable.files[0],
                        self.tags['photometricInterpretation']))
                newLoadables.append(loadable)
        loadables = newLoadables

        #
        # now for each series and subseries, sort the images
        # by position and check for consistency
        # then adjust confidence values based on warnings
        #
        for loadable in loadables:
            loadable.files, distances, loadable.warning = DICOMUtils.getSortedImageFiles(
                loadable.files, self.epsilon)

        loadablesBetterThanAllFiles = []
        if allFilesLoadable.warning != "":
            for probableLocalizerFreeLoadable in probableLocalizerFreeLoadables:
                if probableLocalizerFreeLoadable.warning == "":
                    # localizer-free loadables are better then all files, if they don't have warning
                    loadablesBetterThanAllFiles.append(
                        probableLocalizerFreeLoadable)
            if not loadablesBetterThanAllFiles and subseriesCount == 1:
                # there was a sorting warning and
                # only one kind of subseries, so it's probably correct
                # to have lower confidence in the default all-files version.
                for loadable in loadables:
                    if loadable != allFilesLoadable and loadable.warning == "":
                        loadablesBetterThanAllFiles.append(loadable)

        # if there are loadables that are clearly better then all files, then use those (otherwise use all files loadable)
        preferredLoadables = loadablesBetterThanAllFiles if loadablesBetterThanAllFiles else [
            allFilesLoadable
        ]
        # reduce confidence and deselect all non-preferred loadables
        for loadable in loadables:
            if loadable in preferredLoadables:
                loadable.selected = True
            else:
                loadable.selected = False
                if loadable.confidence > .45:
                    loadable.confidence = .45

        return loadables