From 389da53da4ffbae9166cf8bd454b4bf9b73674da Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 20 Nov 2025 15:55:29 +0000 Subject: [PATCH 1/3] Initial plan From 781097d14400901cff0f962c5138552a30483e8d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 20 Nov 2025 16:00:30 +0000 Subject: [PATCH 2/3] Add caching for referenced CT series UIDs to improve performance Co-authored-by: fedorov <313942+fedorov@users.noreply.github.com> --- .../SegmentationComparison.py | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/SegmentationComparison/SegmentationComparison.py b/SegmentationComparison/SegmentationComparison.py index 5d5b241..3663544 100644 --- a/SegmentationComparison/SegmentationComparison.py +++ b/SegmentationComparison/SegmentationComparison.py @@ -1414,6 +1414,8 @@ def __init__(self) -> None: """Called when the logic class is instantiated. Can be used for initializing member variables.""" ScriptedLoadableModuleLogic.__init__(self) self.segmentBoundingBoxes = {} + # Cache for referenced CT series UIDs to avoid repeated DICOM file reads + self._referencedSeriesCache = {} def setDefaultParameters(self, parameterNode): """ @@ -1748,24 +1750,42 @@ def getLayoutXML(self, viewNumber, threedCheckbox, twodCheckbox, layout, viewNam return layout_xml + def clearReferencedSeriesCache(self): + """ + Clears the cache of referenced CT series UIDs. + Should be called when the DICOM database is updated or modified. + """ + self._referencedSeriesCache.clear() + #Load all Segmentation files for chosen Volume def getReferencedCtSeries(self, segmentation_uid): """ Returns the SeriesInstanceUID of the referenced CT given a DICOM Seg File. + Uses caching to avoid repeated DICOM file reads for the same series. :param segmentation_uid: SeriesInstanceUID of a segmentation: :return String: SeriesInstanceUID of the referecned CT """ + # Check cache first + if segmentation_uid in self._referencedSeriesCache: + return self._referencedSeriesCache[segmentation_uid] + dicom_database = slicer.dicomDatabase series_files = dicom_database.filesForSeries(segmentation_uid) if not series_files: + self._referencedSeriesCache[segmentation_uid] = None return None try: ds = pydicom.dcmread(series_files[0], stop_before_pixels = True, specific_tags = ["ReferencedSeriesSequence"]) - return ds.ReferencedSeriesSequence[0].SeriesInstanceUID + referenced_series = ds.ReferencedSeriesSequence[0].SeriesInstanceUID + # Cache the result + self._referencedSeriesCache[segmentation_uid] = referenced_series + return referenced_series except Exception as e: print(e) + # Cache None for failed reads to avoid repeated failures + self._referencedSeriesCache[segmentation_uid] = None return None def getSegmentationSopInstanceUID(self, series_uid): From 49c721fa23b0d78b967c91e446b38d91f879f94a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 20 Nov 2025 16:05:01 +0000 Subject: [PATCH 3/3] Improve cache comment to clarify the mapping structure Co-authored-by: fedorov <313942+fedorov@users.noreply.github.com> --- SegmentationComparison/SegmentationComparison.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/SegmentationComparison/SegmentationComparison.py b/SegmentationComparison/SegmentationComparison.py index 3663544..d62108c 100644 --- a/SegmentationComparison/SegmentationComparison.py +++ b/SegmentationComparison/SegmentationComparison.py @@ -1414,7 +1414,8 @@ def __init__(self) -> None: """Called when the logic class is instantiated. Can be used for initializing member variables.""" ScriptedLoadableModuleLogic.__init__(self) self.segmentBoundingBoxes = {} - # Cache for referenced CT series UIDs to avoid repeated DICOM file reads + # Cache for referenced CT series UIDs to avoid repeated DICOM file reads. + # Maps segmentation series UID -> referenced CT series UID self._referencedSeriesCache = {} def setDefaultParameters(self, parameterNode):