Skip to content

Commit

Permalink
Merge branch 'master' into measurement-import
Browse files Browse the repository at this point in the history
  • Loading branch information
pieper authored May 20, 2020
2 parents 0d2af75 + b3f6cf2 commit 9dc1be7
Show file tree
Hide file tree
Showing 14 changed files with 117 additions and 102 deletions.
2 changes: 1 addition & 1 deletion DICOMPlugins/DICOMParametricMapPlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ def load(self,loadable):
self.cleanup()
return False

(_,pmNode) = slicer.util.loadVolume(os.path.join(self.tempDir,"pmap.nrrd"), returnNode=True)
pmNode = slicer.util.loadVolume(os.path.join(self.tempDir,"pmap.nrrd"))

# load the metadata JSON to retrieve volume semantics (quantity stored and units)
with open(os.path.join(self.tempDir,"meta.json")) as metafile:
Expand Down
59 changes: 37 additions & 22 deletions DICOMPlugins/DICOMSegmentationPlugin.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from __future__ import absolute_import
import glob
import os
import json
Expand All @@ -12,6 +13,7 @@

from SlicerDevelopmentToolboxUtils.mixins import ModuleLogicMixin
from SlicerDevelopmentToolboxUtils.constants import DICOMTAGS
from six.moves import range


#
Expand Down Expand Up @@ -48,15 +50,12 @@ def examineFiles(self,files):
if isDicomSeg:
loadable = DICOMLoadable()
loadable.files = [cFile]
loadable.name = desc + ' - as a DICOM SEG object'
loadable.tooltip = loadable.name
loadable.name = desc
loadable.tooltip = loadable.name + ' - as a DICOM SEG object'
loadable.selected = True
loadable.confidence = 0.95
loadable.uid = uid
self.addReferences(loadable)
refName = self.referencedSeriesName(loadable)
if refName != "":
loadable.name = refName + " " + desc + " - Segmentations"

loadables.append(loadable)

Expand Down Expand Up @@ -145,13 +144,13 @@ def load(self,loadable):
for segment in segmentAttributes:
try:
rgb255 = segment["recommendedDisplayRGBValue"]
rgb = map(lambda c: float(c) / 255., rgb255)
rgb = [float(c) / 255. for c in rgb255]
except KeyError:
rgb = (0., 0., 0.)

segmentId = segment["labelID"]

defaults = ['T-D0050', 'Tissue', 'SRT']
defaults = ['85756007', 'Tissue', 'SCT']
categoryCode, categoryCodingScheme, categoryCodeMeaning = \
self.getValuesFromCodeSequence(segment, "SegmentedPropertyCategoryCodeSequence", defaults)

Expand All @@ -161,7 +160,7 @@ def load(self,loadable):
typeModCode, typeModCodingScheme, typeModCodeMeaning = \
self.getValuesFromCodeSequence(segment, "SegmentedPropertyTypeModifierCodeSequence")

anatomicRegionDefaults = ['T-D0010', 'SRT', 'Entire Body']
anatomicRegionDefaults = ['38266002', 'SCT', 'Entire Body']
regionCode, regionCodingScheme, regionCodeMeaning = \
self.getValuesFromCodeSequence(segment, "AnatomicRegionSequence", anatomicRegionDefaults)

Expand All @@ -183,11 +182,12 @@ def load(self,loadable):

# load the segmentation volume file and name it for the reference series and segment color
labelFileName = os.path.join(self.tempDir, str(segmentId) + ".nrrd")
segmentName = seriesName + "-" + typeCodeMeaning + "-label"
success, labelNode = slicer.util.loadLabelVolume(labelFileName,properties={'name': segmentName},
returnNode=True)
if not success:
raise ValueError("{} could not be loaded into Slicer!".format(labelFileName))
if segment["SegmentDescription"] is None:
segmentName = seriesName + "-" + typeCodeMeaning + "-label"
else:
segmentName = segment["SegmentDescription"]

labelNode = slicer.util.loadLabelVolume(labelFileName,properties={'name': segmentName})

# Set terminology properties as attributes to the label node (which is a temporary node)
#TODO: This is a quick solution, maybe there is a better one
Expand Down Expand Up @@ -248,7 +248,7 @@ def _removeLabelNode(self, labelNode):

def _initializeSegmentation(self, loadable):
segmentationNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLSegmentationNode")
segmentationNode.SetName(self.referencedSeriesName(loadable))
segmentationNode.SetName(loadable.name)

segmentationDisplayNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLSegmentationDisplayNode")
segmentationNode.SetAndObserveDisplayNodeID(segmentationDisplayNode.GetID())
Expand Down Expand Up @@ -315,7 +315,7 @@ def _setupExportable(self, exportable, subjectHierarchyItemID):
exportable.subjectHierarchyItemID = subjectHierarchyItemID
exportable.pluginClass = self.__module__
# Define common required tags and default values
exportable.setTag('SeriesDescription', 'No series description')
exportable.setTag('SeriesDescription', 'Segmentation')
exportable.setTag('SeriesNumber', '1')
return [exportable]

Expand All @@ -337,14 +337,20 @@ def export(self, exportables):

exporter = DICOMSegmentationExporter(segmentationNode)

metadata = {}
for attr in ["SeriesDescription", "ContentCreatorName", "ClinicalTrialSeriesID", "ClinicalTrialTimePointID",
"ClinicalTrialCoordinatingCenterName"]:
if exportable.tag(attr) != "":
metadata[attr] = exportable.tag(attr)

try:
segFileName = "subject_hierarchy_export.SEG" + exporter.currentDateTime + ".dcm"
segFilePath = os.path.join(exportable.directory, segFileName)
try:
exporter.export(exportable.directory, segFileName)
exporter.export(exportable.directory, segFileName, metadata)
except DICOMSegmentationExporter.EmptySegmentsFoundError as exc:
if slicer.util.confirmYesNoDisplay(exc.message):
exporter.export(exportable.directory, segFileName, skipEmpty=True)
exporter.export(exportable.directory, segFileName, metadata, skipEmpty=True)
else:
raise ValueError("Export canceled")
slicer.dicomDatabase.insert(segFilePath)
Expand Down Expand Up @@ -448,12 +454,21 @@ def export(self, outputDirectory, segFileName, metadata, segmentIDs=None, skipEm
data = self.getSeriesAttributes()
data.update(metadata)

try:
for attr in ["SeriesDescription", "ContentCreatorName", "ClinicalTrialSeriesID", "ClinicalTrialTimePointID",
metadataDefaults = {}
metadataDefaults["SeriesDescription"] = "Segmentation"
metadataDefaults["ContentCreatorName"] = self.contentCreatorName
metadataDefaults["ClinicalTrialSeriesID"] = "1"
metadataDefaults["ClinicalTrialTimePointID"] = "1"
metadataDefaults["ClinicalTrialCoordinatingCenterName"] = "QIICR"

for attr in ["SeriesDescription", "ContentCreatorName", "ClinicalTrialSeriesID", "ClinicalTrialTimePointID",
"ClinicalTrialCoordinatingCenterName"]:
data[attr]
except KeyError as exc:
raise self.MissingAttributeError(str(exc))
try:
if data[attr] == "":
data[attr] = metadataDefaults[attr]

except KeyError as exc:
data[attr] = metadataDefaults[attr]

self.formatMetaDataDICOMConform(data)

Expand Down
24 changes: 15 additions & 9 deletions DICOMPlugins/DICOMTID1500Plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
import vtk
import datetime
from collections import Counter
import dicom

import numpy
import random
import pydicom


import slicer
from DICOMLib import DICOMLoadable
Expand Down Expand Up @@ -41,7 +43,7 @@ def examineFiles(self, files):
loadables = []

for cFile in files:
dataset = dicom.read_file(cFile)
dataset = pydicom.read_file(cFile)

uid = self.getDICOMValue(dataset, "SOPInstanceUID")
if uid == "":
Expand Down Expand Up @@ -140,20 +142,20 @@ def sortReportsByDateTime(self, uids):

def getDateTime(self, uid):
filename = slicer.dicomDatabase.fileForInstance(uid)
dataset = dicom.read_file(filename)
dataset = pydicom.read_file(filename)
if hasattr(dataset, 'SeriesDate') and hasattr(dataset, "SeriesTime"):
date = dataset.SeriesDate
time = dataset.SeriesTime
elif hasattr(dataset, 'StudyDate') and hasattr(dataset, "StudyTime"):
date = dataset.StudyDate
time = dataset.StudyDate
else:
date = "19630524"
time = "000000"
date = ""
time = ""
try:
dateTime = datetime.datetime.strptime(date+time, '%Y%m%d%H%M%S')
except ValueError:
dateTime = "19630524000000"
dateTime = ""
return dateTime

def load(self, loadable):
Expand Down Expand Up @@ -216,6 +218,10 @@ def load(self, loadable):

table = self.metadata2vtkTableNode(outputFile)
if table:
with open(outputFile, 'r') as srMetadataFile:
srMetadataJSON = json.loads(srMetadataFile.read())
table.SetName(srMetadataJSON["SeriesDescription"])

# TODO: think about the following...
if len(slicer.util.getNodesByClass('vtkMRMLSegmentationNode')) > 0:
segmentationNode = slicer.util.getNodesByClass('vtkMRMLSegmentationNode')[-1]
Expand Down Expand Up @@ -268,7 +274,7 @@ def determineAndApplyRWVMToReferencedSeries(self, loadable, segLoadable):
rwvmPlugin = slicer.modules.dicomPlugins["DICOMRWVMPlugin"]()
rwvmFile = rwvmFiles[0]
logging.debug("Reading RWVM from " + rwvmFile)
rwvmDataset = dicom.read_file(rwvmFile)
rwvmDataset = pydicom.read_file(rwvmFile)
if hasattr(rwvmDataset, "ReferencedSeriesSequence"):
if hasattr(rwvmDataset.ReferencedSeriesSequence[0], "SeriesInstanceUID"):
if rwvmDataset.ReferencedSeriesSequence[0].SeriesInstanceUID == segLoadable.referencedSeriesUID:
Expand Down Expand Up @@ -445,7 +451,7 @@ def examineFiles(self, files):
loadables = []

for cFile in files:
dataset = dicom.read_file(cFile)
dataset = pydicom.read_file(cFile)

uid = self.getDICOMValue(dataset, "SOPInstanceUID")
if uid == "":
Expand Down Expand Up @@ -485,7 +491,7 @@ def getRelatedSRs(self, dataset):
foundSRs = []
for s in series:
srFile = self.fileForSeries(s)
tempDCM = dicom.read_file(srFile)
tempDCM = pydicom.read_file(srFile)
if self.isDICOMTID1500(tempDCM):
foundSRs.append(srFile)
otherSRDatasets.append(tempDCM)
Expand Down
8 changes: 4 additions & 4 deletions DICOMPlugins/base/DICOMPluginBase.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import slicer
import dicom
import pydicom
import logging
from datetime import datetime
from DICOMLib import DICOMPlugin
Expand Down Expand Up @@ -59,7 +59,7 @@ def examineForImport(self, fileLists):
def addReferences(self, loadable):
"""Puts a list of the referenced UID into the loadable for use
in the node if this is loaded."""
dcm = dicom.read_file(loadable.files[0])
dcm = pydicom.read_file(loadable.files[0])
loadable.referencedInstanceUIDs = []
self._addReferencedSeries(loadable, dcm)
self._addReferencedImages(loadable, dcm)
Expand All @@ -69,7 +69,7 @@ def _addReferencedSeries(self, loadable, dcm):
if hasattr(dcm, "ReferencedSeriesSequence"):
if hasattr(dcm.ReferencedSeriesSequence[0], "SeriesInstanceUID"):
for f in slicer.dicomDatabase.filesForSeries(dcm.ReferencedSeriesSequence[0].SeriesInstanceUID):
refDCM = dicom.read_file(f)
refDCM = pydicom.read_file(f)
loadable.referencedInstanceUIDs.append(refDCM.SOPInstanceUID)
loadable.referencedSeriesUID = dcm.ReferencedSeriesSequence[0].SeriesInstanceUID

Expand All @@ -79,4 +79,4 @@ def _addReferencedImages(self, loadable, dcm):
if hasattr(item, "ReferencedSOPInstanceUID"):
loadable.referencedInstanceUIDs.append(item.ReferencedSOPInstanceUID)
# TODO: what to do with the SeriesInstanceUID?
# refDCM = dicom.read_file(slicer.dicomDatabase.fileForInstance(item.ReferencedSOPInstanceUID))
# refDCM = pydicom.read_file(slicer.dicomDatabase.fileForInstance(item.ReferencedSOPInstanceUID))
1 change: 0 additions & 1 deletion QuantitativeReporting/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

set(MODULE_PYTHON_SCRIPTS
QRCustomizations/__init__.py
QRCustomizations/CustomDICOMDetailsWidget.py
QRCustomizations/CustomSegmentEditor.py
QRCustomizations/CustomSegmentStatistics.py
QRCustomizations/SegmentEditorAlgorithmTracker.py
Expand Down
18 changes: 0 additions & 18 deletions QuantitativeReporting/QRCustomizations/CustomDICOMDetailsWidget.py

This file was deleted.

14 changes: 11 additions & 3 deletions QuantitativeReporting/QRCustomizations/CustomSegmentEditor.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from __future__ import absolute_import
import qt
import slicer
import vtk
import os


from QRCustomizations.CustomSegmentStatistics import CustomSegmentStatisticsLogic
Expand All @@ -11,6 +13,7 @@
from SegmentEditor import SegmentEditorWidget

import vtkSegmentationCorePython as vtkSegmentationCore
from six.moves import range


class CustomSegmentEditorWidget(SegmentEditorWidget, ModuleWidgetMixin):
Expand Down Expand Up @@ -46,14 +49,19 @@ def __init__(self, parent):
SegmentEditorWidget.__init__(self, parent)
self.logic = CustomSegmentEditorLogic()

def resourcePath(self, filename):
scriptedModulesPath = os.path.dirname(slicer.util.modulePath("QuantitativeReporting"))
return os.path.join(scriptedModulesPath, 'Resources', filename)

def setup(self):
super(CustomSegmentEditorWidget, self).setup()
if self.developerMode:
self.reloadCollapsibleButton.hide()
self.editor.switchToSegmentationsButtonVisible = False
self.editor.segmentationNodeSelectorVisible = False
self.editor.setEffectButtonStyle(qt.Qt.ToolButtonIconOnly)
self.clearSegmentationEditorSelectors()

def setupDeveloperSection(self):
return

def onSegmentSelected(self, selectedRow):
try:
Expand Down Expand Up @@ -182,4 +190,4 @@ def calculateSegmentStatistics(self, segNode, grayscaleNode, visibleSegmentsOnly
self.segmentStatisticsLogic.getParameterNode().UnsetParameter("ScalarVolume")
self.segmentStatisticsLogic.computeStatistics()
tableNode = self.segmentStatisticsLogic.exportToTable(tableNode)
return tableNode
return tableNode
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from __future__ import absolute_import
import logging
import slicer
import qt
Expand Down Expand Up @@ -121,7 +122,7 @@ def generateJSON4DcmSR(self, dcmSegmentationFile, sourceVolumeNode):

data["Finding"] = self.createJSONFromTerminologyContext(terminologyEntry)["SegmentedPropertyTypeCodeSequence"]
anatomicContext = self.createJSONFromAnatomicContext(terminologyEntry)
if anatomicContext.has_key("AnatomicRegionSequence"):
if "AnatomicRegionSequence" in anatomicContext:
data["FindingSite"] = anatomicContext["AnatomicRegionSequence"]
data["measurementItems"] = self.createMeasurementItemsForLabelValue(segmentID)
measurements.append(data)
Expand All @@ -137,7 +138,7 @@ def createMeasurementItemsForLabelValue(self, segmentValue):
item["value"] = str(self.statistics[segmentValue, key])
item["quantity"] = self._createCodeSequence(measurementInfo["DICOM.QuantityCode"])
item["units"] = self._createCodeSequence(measurementInfo["DICOM.UnitsCode"])
if measurementInfo.has_key("DICOM.DerivationCode"):
if "DICOM.DerivationCode" in measurementInfo:
item["derivationModifier"] = self._createCodeSequence(measurementInfo["DICOM.DerivationCode"])
measurementItems.append(item)
return measurementItems
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from __future__ import absolute_import
import slicer
import vtk
import vtkSegmentationCorePython as vtkSegmentationCore
from six.moves import range


class SegmentEditorAlgorithmTracker(object):
Expand Down
Loading

0 comments on commit 9dc1be7

Please sign in to comment.