From 24c3271b8904608df7fc057ca32e85626d101319 Mon Sep 17 00:00:00 2001 From: Jose Raniery Date: Mon, 1 Apr 2024 16:22:56 -0300 Subject: [PATCH 01/10] Add tag model to the dict label_info in the function onSaveLabel Signed-off-by: Jose Raniery --- plugins/slicer/MONAILabel/MONAILabel.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plugins/slicer/MONAILabel/MONAILabel.py b/plugins/slicer/MONAILabel/MONAILabel.py index 30db0dbcd..dcb395dce 100644 --- a/plugins/slicer/MONAILabel/MONAILabel.py +++ b/plugins/slicer/MONAILabel/MONAILabel.py @@ -1485,7 +1485,11 @@ def onSaveLabel(self): self.reportProgress(30) self.updateServerSettings() - result = self.logic.save_label(self.current_sample["id"], label_in, {"label_info": label_info}) + result = self.logic.save_label( + self.current_sample["id"], + label_in, + {"label_info": label_info, "model": model}, + ) self.fetchInfo() if slicer.util.settingsValue("MONAILabel/autoUpdateModelV2", False, converter=slicer.util.toBool): From 5a06722045e03e3fd75fca17e5296d9ea54c5c0b Mon Sep 17 00:00:00 2001 From: Jose Raniery Date: Mon, 1 Apr 2024 17:03:26 -0300 Subject: [PATCH 02/10] Add checkbox includeDicomFilesCheckBox in settings Signed-off-by: Jose Raniery --- plugins/slicer/MONAILabel/MONAILabel.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/plugins/slicer/MONAILabel/MONAILabel.py b/plugins/slicer/MONAILabel/MONAILabel.py index dcb395dce..239145ceb 100644 --- a/plugins/slicer/MONAILabel/MONAILabel.py +++ b/plugins/slicer/MONAILabel/MONAILabel.py @@ -190,6 +190,17 @@ def __init__(self, parent): str(qt.SIGNAL("valueAsIntChanged(int)")), ) + includeDicomFilesCheckBox = qt.QCheckBox() + includeDicomFilesCheckBox.checked = False + includeDicomFilesCheckBox.toolTip = _("Enable this option to include dicom files in server-client data exchange") + groupLayout.addRow(_("Include DICOM files:"), includeDicomFilesCheckBox) + parent.registerProperty( + "MONAILabel/includeDicomFiles", + ctk.ctkBooleanMapper(includeDicomFilesCheckBox, "checked", str(qt.SIGNAL("toggled(bool)"))), + "valueAsInt", + str(qt.SIGNAL("valueAsIntChanged(int)")), + ) + vBoxLayout.addWidget(groupBox) vBoxLayout.addStretch(1) From ce0b19021ccecbcd7097728508e019e99883051d Mon Sep 17 00:00:00 2001 From: Jose Raniery Date: Mon, 1 Apr 2024 17:11:10 -0300 Subject: [PATCH 03/10] Add dicom files in the tmpdir Signed-off-by: Jose Raniery --- plugins/slicer/MONAILabel/MONAILabel.py | 41 ++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/plugins/slicer/MONAILabel/MONAILabel.py b/plugins/slicer/MONAILabel/MONAILabel.py index 239145ceb..e25d505fc 100644 --- a/plugins/slicer/MONAILabel/MONAILabel.py +++ b/plugins/slicer/MONAILabel/MONAILabel.py @@ -20,6 +20,7 @@ from urllib.parse import quote_plus import ctk +import DICOMScalarVolumePlugin import qt import SampleData import SimpleITK as sitk @@ -1380,6 +1381,14 @@ def getPermissionForImageDataUpload(self): dontShowAgainSettingsKey="MONAILabel/showImageDataSendWarning", ) + def get_dicom_files(self): + dicom_files = [] + for path, _, files in os.walk(self.tmpdir): + for file in files: + if file[-3:] == "dcm": + dicom_files.append(os.path.join(path, file)) + return dicom_files + def onUploadImage(self, init_sample=True, session=False): volumeNode = slicer.mrmlScene.GetFirstNodeByClass("vtkMRMLScalarVolumeNode") image_id = volumeNode.GetName() @@ -1395,12 +1404,42 @@ def onUploadImage(self, init_sample=True, session=False): start = time.time() slicer.util.saveNode(volumeNode, in_file) logging.info(f"Saved Input Node into {in_file} in {time.time() - start:3.1f}s") - self.reportProgress(30) + last_report_progress = 30 + self.reportProgress(last_report_progress) + + # if includeDicomFilesCheckBox is marked, save original dicom files on the server + if slicer.util.settingsValue("MONAILabel/includeDicomFiles", False, converter=slicer.util.toBool): + start = time.time() + shNode = slicer.vtkMRMLSubjectHierarchyNode.GetSubjectHierarchyNode(slicer.mrmlScene) + volumeShItemID = shNode.GetItemByDataNode(volumeNode) + + exporter = DICOMScalarVolumePlugin.DICOMScalarVolumePluginClass() + exportables = exporter.examineForExport(volumeShItemID) + for exp in exportables: + exp.directory = self.tmpdir + exporter.export(exportables) + logging.info(f"Saved dicom files in {time.time() - start:3.1f}s") + last_report_progress = 50 + self.reportProgress(last_report_progress) if session: self.current_sample["session_id"] = self.logic.create_session(in_file)["session_id"] else: self.logic.upload_image(in_file, image_id) + + # if includeDicomFilesCheckBox is marked, save original dicom files on the client + if slicer.util.settingsValue("MONAILabel/includeDicomFiles", False, converter=slicer.util.toBool): + dcm_filenames = self.get_dicom_files() + report_progress_increment = round( + last_report_progress / len(dcm_filenames), 1 + ) + for dcm_fullpath in dcm_filenames: + dcm_filename = dcm_fullpath.split("/")[-1] + dcm_filename = ".".join(dcm_filename.split(".")[:-1]) + self.logic.upload_image(dcm_fullpath, dcm_filename) + last_report_progress += report_progress_increment + self.reportProgress(last_report_progress) + self.current_sample["session"] = False self.reportProgress(100) From 521d986e9d8e3810be74e8ece49a3da52c5a997c Mon Sep 17 00:00:00 2001 From: Jose Raniery Date: Mon, 1 Apr 2024 17:13:36 -0300 Subject: [PATCH 04/10] Add call of function onUploadImage in the function onClickSegmentation to include dicom files, if marked in settings, prior segmentation Signed-off-by: Jose Raniery --- plugins/slicer/MONAILabel/MONAILabel.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/slicer/MONAILabel/MONAILabel.py b/plugins/slicer/MONAILabel/MONAILabel.py index e25d505fc..90d7eedb5 100644 --- a/plugins/slicer/MONAILabel/MONAILabel.py +++ b/plugins/slicer/MONAILabel/MONAILabel.py @@ -1585,6 +1585,10 @@ def onClickSegmentation(self): if not self.current_sample: return + if self.current_sample.get("session"): + if not self.onUploadImage(init_sample=False): + return + start = time.time() result_file = None try: From a53467efe65a0bb8570d7d381429630ad21538b9 Mon Sep 17 00:00:00 2001 From: Jose Raniery Date: Mon, 1 Apr 2024 17:37:40 -0300 Subject: [PATCH 05/10] Rename loop variable in function get_dicom_files according to flake8 F402 error Signed-off-by: Jose Raniery --- plugins/slicer/MONAILabel/MONAILabel.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/slicer/MONAILabel/MONAILabel.py b/plugins/slicer/MONAILabel/MONAILabel.py index 90d7eedb5..1c7c088ee 100644 --- a/plugins/slicer/MONAILabel/MONAILabel.py +++ b/plugins/slicer/MONAILabel/MONAILabel.py @@ -193,7 +193,9 @@ def __init__(self, parent): includeDicomFilesCheckBox = qt.QCheckBox() includeDicomFilesCheckBox.checked = False - includeDicomFilesCheckBox.toolTip = _("Enable this option to include dicom files in server-client data exchange") + includeDicomFilesCheckBox.toolTip = _( + "Enable this option to include dicom files in server-client data exchange" + ) groupLayout.addRow(_("Include DICOM files:"), includeDicomFilesCheckBox) parent.registerProperty( "MONAILabel/includeDicomFiles", @@ -1383,7 +1385,7 @@ def getPermissionForImageDataUpload(self): def get_dicom_files(self): dicom_files = [] - for path, _, files in os.walk(self.tmpdir): + for path, subdir, files in os.walk(self.tmpdir): for file in files: if file[-3:] == "dcm": dicom_files.append(os.path.join(path, file)) @@ -1430,9 +1432,7 @@ def onUploadImage(self, init_sample=True, session=False): # if includeDicomFilesCheckBox is marked, save original dicom files on the client if slicer.util.settingsValue("MONAILabel/includeDicomFiles", False, converter=slicer.util.toBool): dcm_filenames = self.get_dicom_files() - report_progress_increment = round( - last_report_progress / len(dcm_filenames), 1 - ) + report_progress_increment = round(last_report_progress / len(dcm_filenames), 1) for dcm_fullpath in dcm_filenames: dcm_filename = dcm_fullpath.split("/")[-1] dcm_filename = ".".join(dcm_filename.split(".")[:-1]) @@ -1588,7 +1588,7 @@ def onClickSegmentation(self): if self.current_sample.get("session"): if not self.onUploadImage(init_sample=False): return - + start = time.time() result_file = None try: From 77812dffa87cd5c5a9b74cac8b001de7133d9024 Mon Sep 17 00:00:00 2001 From: Jose Raniery Date: Mon, 1 Apr 2024 17:52:54 -0300 Subject: [PATCH 06/10] Refactor transforms after PR check Signed-off-by: Jose Raniery --- sample-apps/radiology/lib/transforms/transforms.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/sample-apps/radiology/lib/transforms/transforms.py b/sample-apps/radiology/lib/transforms/transforms.py index 9dcb44b3f..3732112a6 100644 --- a/sample-apps/radiology/lib/transforms/transforms.py +++ b/sample-apps/radiology/lib/transforms/transforms.py @@ -384,11 +384,7 @@ def __call__(self, data): ########### d["current_label"] = list(d["centroids"][0].values())[0][-4] - ( - x, - y, - z, - ) = ( + (x, y, z,) = ( list(d["centroids"][0].values())[0][-3], list(d["centroids"][0].values())[0][-2], list(d["centroids"][0].values())[0][-1], From eafe23f316e1aee16f64ba8fa5e46a8f20ccee3e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 1 Apr 2024 21:01:51 +0000 Subject: [PATCH 07/10] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- sample-apps/radiology/lib/transforms/transforms.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sample-apps/radiology/lib/transforms/transforms.py b/sample-apps/radiology/lib/transforms/transforms.py index 3732112a6..9dcb44b3f 100644 --- a/sample-apps/radiology/lib/transforms/transforms.py +++ b/sample-apps/radiology/lib/transforms/transforms.py @@ -384,7 +384,11 @@ def __call__(self, data): ########### d["current_label"] = list(d["centroids"][0].values())[0][-4] - (x, y, z,) = ( + ( + x, + y, + z, + ) = ( list(d["centroids"][0].values())[0][-3], list(d["centroids"][0].values())[0][-2], list(d["centroids"][0].values())[0][-1], From 01e0a8f77d86caa66e6533340e0795a8e232d7ce Mon Sep 17 00:00:00 2001 From: Jose Raniery Date: Mon, 8 Jul 2024 16:07:06 -0300 Subject: [PATCH 08/10] fix dicom header with the original study and series uids Signed-off-by: Jose Raniery --- plugins/slicer/MONAILabel/MONAILabel.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/plugins/slicer/MONAILabel/MONAILabel.py b/plugins/slicer/MONAILabel/MONAILabel.py index 1c7c088ee..d3030751c 100644 --- a/plugins/slicer/MONAILabel/MONAILabel.py +++ b/plugins/slicer/MONAILabel/MONAILabel.py @@ -29,6 +29,7 @@ import vtk import vtkSegmentationCore from MONAILabelLib import GenericAnatomyColors, MONAILabelClient +from pydicom import dcmread from slicer.i18n import tr as _ from slicer.i18n import translate from slicer.ScriptedLoadableModule import * @@ -1414,6 +1415,10 @@ def onUploadImage(self, init_sample=True, session=False): start = time.time() shNode = slicer.vtkMRMLSubjectHierarchyNode.GetSubjectHierarchyNode(slicer.mrmlScene) volumeShItemID = shNode.GetItemByDataNode(volumeNode) + + seriesInstanceUID = shNode.GetItemUID(volumeShItemID, 'DICOM') + instUids = slicer.dicomDatabase.instancesForSeries(seriesInstanceUID) + studyInstanceUID = slicer.dicomDatabase.instanceValue(instUids[0], "0020,000D") exporter = DICOMScalarVolumePlugin.DICOMScalarVolumePluginClass() exportables = exporter.examineForExport(volumeShItemID) @@ -1434,6 +1439,12 @@ def onUploadImage(self, init_sample=True, session=False): dcm_filenames = self.get_dicom_files() report_progress_increment = round(last_report_progress / len(dcm_filenames), 1) for dcm_fullpath in dcm_filenames: + # set original study and series UIDs + dcm = dcmread(dcm_fullpath) + dcm.StudyInstanceUID = studyInstanceUID + dcm.SeriesInstanceUID = seriesInstanceUID + dcm.save_as(dcm_fullpath) + dcm_filename = dcm_fullpath.split("/")[-1] dcm_filename = ".".join(dcm_filename.split(".")[:-1]) self.logic.upload_image(dcm_fullpath, dcm_filename) From 012c2ddb2e6e81dffdf3c935105c5d86221e097d Mon Sep 17 00:00:00 2001 From: Jose Raniery Date: Mon, 8 Jul 2024 16:08:50 -0300 Subject: [PATCH 09/10] update dicom transfer method by sending only the first slice due to overhead Signed-off-by: Jose Raniery --- plugins/slicer/MONAILabel/MONAILabel.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plugins/slicer/MONAILabel/MONAILabel.py b/plugins/slicer/MONAILabel/MONAILabel.py index d3030751c..78921e5dd 100644 --- a/plugins/slicer/MONAILabel/MONAILabel.py +++ b/plugins/slicer/MONAILabel/MONAILabel.py @@ -1437,6 +1437,11 @@ def onUploadImage(self, init_sample=True, session=False): # if includeDicomFilesCheckBox is marked, save original dicom files on the client if slicer.util.settingsValue("MONAILabel/includeDicomFiles", False, converter=slicer.util.toBool): dcm_filenames = self.get_dicom_files() + + # send to server only the first slice due to transfer overhead + dcm_filenames.sort() + dcm_filenames = dcm_filenames[:1] + report_progress_increment = round(last_report_progress / len(dcm_filenames), 1) for dcm_fullpath in dcm_filenames: # set original study and series UIDs From 27c2dc49aa3dadd56caf400f4822d7606e0dcdc3 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 8 Jul 2024 19:09:23 +0000 Subject: [PATCH 10/10] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci Signed-off-by: Jose Raniery --- plugins/slicer/MONAILabel/MONAILabel.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/slicer/MONAILabel/MONAILabel.py b/plugins/slicer/MONAILabel/MONAILabel.py index 78921e5dd..5ca32f31d 100644 --- a/plugins/slicer/MONAILabel/MONAILabel.py +++ b/plugins/slicer/MONAILabel/MONAILabel.py @@ -1415,8 +1415,8 @@ def onUploadImage(self, init_sample=True, session=False): start = time.time() shNode = slicer.vtkMRMLSubjectHierarchyNode.GetSubjectHierarchyNode(slicer.mrmlScene) volumeShItemID = shNode.GetItemByDataNode(volumeNode) - - seriesInstanceUID = shNode.GetItemUID(volumeShItemID, 'DICOM') + + seriesInstanceUID = shNode.GetItemUID(volumeShItemID, "DICOM") instUids = slicer.dicomDatabase.instancesForSeries(seriesInstanceUID) studyInstanceUID = slicer.dicomDatabase.instanceValue(instUids[0], "0020,000D") @@ -1437,19 +1437,19 @@ def onUploadImage(self, init_sample=True, session=False): # if includeDicomFilesCheckBox is marked, save original dicom files on the client if slicer.util.settingsValue("MONAILabel/includeDicomFiles", False, converter=slicer.util.toBool): dcm_filenames = self.get_dicom_files() - + # send to server only the first slice due to transfer overhead dcm_filenames.sort() dcm_filenames = dcm_filenames[:1] - + report_progress_increment = round(last_report_progress / len(dcm_filenames), 1) for dcm_fullpath in dcm_filenames: - # set original study and series UIDs + # set original study and series UIDs dcm = dcmread(dcm_fullpath) dcm.StudyInstanceUID = studyInstanceUID dcm.SeriesInstanceUID = seriesInstanceUID dcm.save_as(dcm_fullpath) - + dcm_filename = dcm_fullpath.split("/")[-1] dcm_filename = ".".join(dcm_filename.split(".")[:-1]) self.logic.upload_image(dcm_fullpath, dcm_filename)