From 8c72139bb33662befca7a504ac0a11941af1f38c Mon Sep 17 00:00:00 2001 From: Fereshteh Yousefirizi <84542058+qurit-frizi@users.noreply.github.com> Date: Fri, 31 Jan 2025 16:16:20 -0800 Subject: [PATCH 01/10] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 2b620c9..462fb93 100644 --- a/README.md +++ b/README.md @@ -160,6 +160,9 @@ The add_roi method of our RTStruct class has a multitude of optional parameters - nifti to rtstruct conversion has been added. - conversion from DICOM to NIFTI for PET and corresponding RT-struct file has been added as an example usage with no issues of shift or mistmatch between the masks. +## Examples +You can find the comparison between RT-utils and other conversion techniques in this public repository: https://github.com/qurit/dicom_nifti_conversion_project + ## Contributing We welcome contributions to this project! Please review our [CONTRIBUTING guidelines](./CONTRIBUTING.md) for more details. From 2e9c490d577cc1a5c0e7496f65fd8fed9fd74db0 Mon Sep 17 00:00:00 2001 From: Fereshteh Yousefirizi <84542058+qurit-frizi@users.noreply.github.com> Date: Fri, 31 Jan 2025 17:01:44 -0800 Subject: [PATCH 02/10] Update paper.md --- Paper/paper.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Paper/paper.md b/Paper/paper.md index 6eadcc1..4bdbc66 100644 --- a/Paper/paper.md +++ b/Paper/paper.md @@ -50,7 +50,7 @@ In the pursuit of automated and precise analysis of medical images using artific # Statement of need -The increasing adoption of AI-based methods for medical image analysis necessitates efficient tools for handling DICOM images and RT-Structures. While existing software packages provide basic functionalities for data conversion, they often lack the advanced features required for seamless integration into clinical workflows. The growing need for automated and robust analysis of medical images has driven the adoption of AI-based methods that often use DICOM images and RT structures as masks. However, the effectiveness of these AI approaches can vary due to differences in data sources and conversion techniques [@Whybra2023-en; @Yousefirizi2023-ax; @Rufenacht2023-as]. Despite the availability of tools for converting DICOM images and RT-Structures into other formats [@Anderson2021-fp; @Rufenacht2023-as], integrating auto-segmentation solutions using deep learning in clinical environments is rare due to the lack of open-source frameworks that handle DICOM RT-Structure sets effectively. Software packages like dcmrtstruct2nii, DicomRTTool [@Anderson2021-fp], and PyRaDiSe [@Rufenacht2023-as] provide necessary functionalities, while frameworks like TorchIO [@Perez-Garcia2021-jf] and MONAI [@Creators_The_MONAI_Consortium_undated-or] face limitations in processing DICOM RT-structure data. Research has shown that variations in mask-generation methods affect patient clustering and radiomic-based modeling in multi-center studies [@Whybra2023-en]. RT-utils addresses this gap by offering a specialized Python library that enhances the efficiency of manipulating RT-Structures. It is designed for researchers and clinicians who require advanced yet user-friendly tools to: i) Convert and manipulate RT-Struct data with precision. ii) Integrate AI-generated segmentation masks into clinical DICOM formats. iii) Streamline workflows by automating repetitive and complex tasks. iv) Ensure compatibility with clinical systems through meticulous DICOM header management. By providing these capabilities, RT-utils optimizes workflows in medical imaging analysis, facilitating the translation of AI models from research to clinical practice. RT-utils offers advanced techniques to convert expert-provided contours and AI tool output masks to RT-struct format, making them suitable for clinical workflows. +The increasing adoption of AI-based methods for medical image analysis necessitates efficient tools for handling DICOM images and RT-Structures. While existing software packages provide basic functionalities for data conversion, they often lack the advanced features required for seamless integration into clinical workflows. The growing need for automated and robust analysis of medical images has driven the adoption of AI-based methods that often use DICOM images and RT structures as masks. However, the effectiveness of these AI approaches can vary due to differences in data sources and conversion techniques [@Whybra2023-en; @Yousefirizi2023-ax; @Rufenacht2023-as]. Despite the availability of tools for converting DICOM images and RT-Structures into other formats [@Anderson2021-fp; @Rufenacht2023-as], integrating auto-segmentation solutions using deep learning in clinical environments is rare due to the lack of open-source frameworks that handle DICOM RT-Structure sets precisely. Software packages like dcmrtstruct2nii, DicomRTTool [@Anderson2021-fp], and PyRaDiSe [@Rufenacht2023-as] provide necessary functionalities with higher accuracy, while frameworks like TorchIO [@Perez-Garcia2021-jf] and MONAI [@Creators_The_MONAI_Consortium_undated-or] face limitations in processing DICOM RT-structure data. Research has shown that variations in mask-generation methods affect patient clustering and radiomic-based modeling in multi-center studies [@Whybra2023-en]. RT-utils addresses this gap by offering a specialized Python library that enhances the efficiency of manipulating RT-Structures. It is designed for researchers and clinicians who require advanced yet user-friendly tools to: i) Convert and manipulate RT-Struct data with precision. ii) Integrate AI-generated segmentation masks into clinical DICOM formats. iii) Streamline workflows by automating repetitive and complex tasks. iv) Ensure compatibility with clinical systems through meticulous DICOM header management. By providing these capabilities, RT-utils optimizes workflows in medical imaging analysis, facilitating the translation of AI models from research to clinical practice. RT-utils offers advanced techniques to convert expert-provided contours and AI tool output masks to RT-struct format, making them suitable for clinical workflows. # Overview of RT-utils From 2ccf9f632c0d77793a90dd1462fe529636dcab1e Mon Sep 17 00:00:00 2001 From: Fereshteh Yousefirizi <84542058+qurit-frizi@users.noreply.github.com> Date: Fri, 31 Jan 2025 17:07:01 -0800 Subject: [PATCH 03/10] Update paper.md --- Paper/paper.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Paper/paper.md b/Paper/paper.md index 4bdbc66..e2896e4 100644 --- a/Paper/paper.md +++ b/Paper/paper.md @@ -50,7 +50,7 @@ In the pursuit of automated and precise analysis of medical images using artific # Statement of need -The increasing adoption of AI-based methods for medical image analysis necessitates efficient tools for handling DICOM images and RT-Structures. While existing software packages provide basic functionalities for data conversion, they often lack the advanced features required for seamless integration into clinical workflows. The growing need for automated and robust analysis of medical images has driven the adoption of AI-based methods that often use DICOM images and RT structures as masks. However, the effectiveness of these AI approaches can vary due to differences in data sources and conversion techniques [@Whybra2023-en; @Yousefirizi2023-ax; @Rufenacht2023-as]. Despite the availability of tools for converting DICOM images and RT-Structures into other formats [@Anderson2021-fp; @Rufenacht2023-as], integrating auto-segmentation solutions using deep learning in clinical environments is rare due to the lack of open-source frameworks that handle DICOM RT-Structure sets precisely. Software packages like dcmrtstruct2nii, DicomRTTool [@Anderson2021-fp], and PyRaDiSe [@Rufenacht2023-as] provide necessary functionalities with higher accuracy, while frameworks like TorchIO [@Perez-Garcia2021-jf] and MONAI [@Creators_The_MONAI_Consortium_undated-or] face limitations in processing DICOM RT-structure data. Research has shown that variations in mask-generation methods affect patient clustering and radiomic-based modeling in multi-center studies [@Whybra2023-en]. RT-utils addresses this gap by offering a specialized Python library that enhances the efficiency of manipulating RT-Structures. It is designed for researchers and clinicians who require advanced yet user-friendly tools to: i) Convert and manipulate RT-Struct data with precision. ii) Integrate AI-generated segmentation masks into clinical DICOM formats. iii) Streamline workflows by automating repetitive and complex tasks. iv) Ensure compatibility with clinical systems through meticulous DICOM header management. By providing these capabilities, RT-utils optimizes workflows in medical imaging analysis, facilitating the translation of AI models from research to clinical practice. RT-utils offers advanced techniques to convert expert-provided contours and AI tool output masks to RT-struct format, making them suitable for clinical workflows. +The increasing adoption of AI-based methods for medical image analysis necessitates efficient tools for handling DICOM images and RT-Structures. While existing software packages provide basic functionalities for data conversion, they often lack the advanced features required for seamless integration into clinical workflows. The growing need for automated and robust analysis of medical images has driven the adoption of AI-based methods that often use DICOM images and RT structures as masks. However, the effectiveness of these AI approaches can vary due to differences in data sources and conversion techniques [@Whybra2023-en; @Yousefirizi2023-ax; @Rufenacht2023-as]. Despite the availability of tools for converting DICOM images and RT-Structures into other formats [@Anderson2021-fp; @Rufenacht2023-as], integrating auto-segmentation solutions using deep learning in clinical environments is rare due to the lack of open-source frameworks that handle DICOM RT-Structure sets precisely. Software packages like dcmrtstruct2nii, DicomRTTool [@Anderson2021-fp], and PyRaDiSe [@Rufenacht2023-as] provide necessary functionalities with higher accuracy, while frameworks like TorchIO [@Perez-Garcia2021-jf] and MONAI [@Creators_The_MONAI_Consortium_undated-or] face limitations in processing DICOM RT-structure data. Research has shown that variations in mask-generation methods affect patient clustering and radiomic-based modeling in multi-center studies [@Whybra2023-en]. RT-utils is an standard Python library that enhances the efficiency of manipulating RT-Structures. It is designed for researchers and clinicians who require advanced yet user-friendly tools to: i) Convert and manipulate RT-Struct data with precision. ii) Integrate AI-generated segmentation masks into clinical DICOM formats. iii) Streamline workflows by automating repetitive and complex tasks. iv) Ensure compatibility with clinical systems through meticulous DICOM header management. By providing these capabilities, RT-utils optimizes workflows in medical imaging analysis, facilitating the translation of AI models from research to clinical practice. RT-utils offers advanced techniques to convert expert-provided contours and AI tool output masks to RT-struct format, making them suitable for clinical workflows. # Overview of RT-utils From 337e0d0b40185746c92aa3db9d8bc531d9c240a7 Mon Sep 17 00:00:00 2001 From: Fereshteh Yousefirizi <84542058+qurit-frizi@users.noreply.github.com> Date: Fri, 31 Jan 2025 17:12:21 -0800 Subject: [PATCH 04/10] Update paper.bib --- Paper/paper.bib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Paper/paper.bib b/Paper/paper.bib index c1c7340..53e4c9a 100644 --- a/Paper/paper.bib +++ b/Paper/paper.bib @@ -14,7 +14,7 @@ @article{Anderson2021-fp @misc{Creators_The_MONAI_Consortium_undated-or, title = {Project {MONAI}}, - author = {{Creators The MONAI Consortium}}, + author = {Cardoso, M Jorge and Li, Wenqi and Brown, Richard and Ma, Nic and Kerfoot, Eric and Wang, Yiheng and Murrey, Benjamin and Myronenko, Andriy and Zhao, Can and Yang, Dong and others}, doi = {10.48550/arXiv.2211.02701}, year = {2022}, url = {https://arxiv.org/abs/2211.02701} From 18fa860fffcc504c7489ed662172149ae2a755dd Mon Sep 17 00:00:00 2001 From: Fereshteh Yousefirizi <84542058+qurit-frizi@users.noreply.github.com> Date: Fri, 31 Jan 2025 17:19:06 -0800 Subject: [PATCH 05/10] Update rtstruct.py --- rt_utils/rtstruct.py | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/rt_utils/rtstruct.py b/rt_utils/rtstruct.py index dfe82be..a2b89ac 100644 --- a/rt_utils/rtstruct.py +++ b/rt_utils/rtstruct.py @@ -41,6 +41,45 @@ def add_roi( Optionally input a color or name for the ROI If use_pin_hole is set to true, will cut a pinhole through ROI's with holes in them so that they are represented with one contour If approximate_contours is set to False, no approximation will be done when generating contour data, leading to much larger amount of contour data + This method updates the internal DICOM structure (RTStruct) by adding + a new ROIContourSequence, StructureSetROISequence, and + RTROIObservationsSequence entry corresponding to the provided mask. + + Parameters + ---------- + mask : np.ndarray + 3D boolean array indicating the ROI. Its shape must match + the underlying DICOM series in the third dimension. + color : str or list of int, optional + The color representation for the ROI. This can be a string (e.g., "red") + or a list of RGB values (e.g., [255, 0, 0]). Defaults to None. + name : str, optional + A name/label for this ROI. Defaults to None. + description : str, optional + Longer text describing this ROI. Defaults to an empty string. + use_pin_hole : bool, optional + If True, attempts to handle ROIs with holes by creating a pinhole + (a single continuous contour). Defaults to False. + approximate_contours : bool, optional + If False, no approximation is done during contour generation, + potentially resulting in very large amounts of contour data. + Defaults to True. + roi_generation_algorithm : str or int, optional + Identifier for the algorithm used to generate this ROI. This can be + a string describing the algorithm or an integer code. Defaults to 0. + + Raises + ------ + ROIException + - If the mask is not a 3D boolean array. + - If the mask's shape does not match the loaded DICOM series dimensions. + - If the mask is empty (no voxels set to True). + + Returns + ------- + None + This method does not return anything, but modifies the internal RTStruct. + """ """ # TODO test if name already exists From 4499f16c32972852463bea0767068a1b460368a7 Mon Sep 17 00:00:00 2001 From: Fereshteh Yousefirizi <84542058+qurit-frizi@users.noreply.github.com> Date: Thu, 6 Feb 2025 17:17:28 -0800 Subject: [PATCH 06/10] Update python-app.yml --- .github/workflows/python-app.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index 39aea77..82f1110 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [ "3.7", "3.8", "3.9", "3.10" ] + python-version: [ "3.8", "3.9", "3.10" ] steps: - uses: actions/checkout@v2 From 255ca0ebd52e5366c97cd0073437f0e2a6726eda Mon Sep 17 00:00:00 2001 From: Fereshteh Yousefirizi <84542058+qurit-frizi@users.noreply.github.com> Date: Thu, 6 Feb 2025 17:30:44 -0800 Subject: [PATCH 07/10] Update python-app.yml --- .github/workflows/python-app.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index 82f1110..a939d29 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -28,6 +28,7 @@ jobs: python -m pip install --upgrade pip pip install pytest if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + pip install -e . # Ensure local package installation - name: Test with pytest run: | pytest From e8b8302a80c4b88c0584b44b756ab6ebcd7a2a9b Mon Sep 17 00:00:00 2001 From: Fereshteh Yousefirizi <84542058+qurit-frizi@users.noreply.github.com> Date: Thu, 6 Feb 2025 17:43:58 -0800 Subject: [PATCH 08/10] Update rtstruct.py --- rt_utils/rtstruct.py | 71 +++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 40 deletions(-) diff --git a/rt_utils/rtstruct.py b/rt_utils/rtstruct.py index a2b89ac..c52d816 100644 --- a/rt_utils/rtstruct.py +++ b/rt_utils/rtstruct.py @@ -1,8 +1,6 @@ from typing import List, Union - import numpy as np from pydicom.dataset import FileDataset - from rt_utils.utils import ROIData from . import ds_helper, image_helper @@ -17,13 +15,12 @@ def __init__(self, series_data, ds: FileDataset, ROIGenerationAlgorithm=0): self.ds = ds self.frame_of_reference_uid = ds.ReferencedFrameOfReferenceSequence[ -1 - ].FrameOfReferenceUID # Use last strucitured set ROI + ].FrameOfReferenceUID # Use last structured set ROI def set_series_description(self, description: str): """ Set the series description for the RTStruct dataset """ - self.ds.SeriesDescription = description def add_roi( @@ -37,52 +34,49 @@ def add_roi( roi_generation_algorithm: Union[str, int] = 0, ): """ - Add a ROI to the rtstruct given a 3D binary mask for the ROI's at each slice - Optionally input a color or name for the ROI - If use_pin_hole is set to true, will cut a pinhole through ROI's with holes in them so that they are represented with one contour - If approximate_contours is set to False, no approximation will be done when generating contour data, leading to much larger amount of contour data - This method updates the internal DICOM structure (RTStruct) by adding - a new ROIContourSequence, StructureSetROISequence, and - RTROIObservationsSequence entry corresponding to the provided mask. - + Add a Region of Interest (ROI) to the RTStruct given a 3D binary mask for each slice. + + Optionally input a color or name for the ROI. + If `use_pin_hole` is set to True, attempts to handle ROIs with holes by creating a single continuous contour. + If `approximate_contours` is set to False, no approximation is done during contour generation, + potentially resulting in a large amount of contour data. + + This method updates the internal DICOM structure (RTStruct) by adding: + - ROIContourSequence + - StructureSetROISequence + - RTROIObservationsSequence + Parameters ---------- mask : np.ndarray 3D boolean array indicating the ROI. Its shape must match the underlying DICOM series in the third dimension. color : str or list of int, optional - The color representation for the ROI. This can be a string (e.g., "red") - or a list of RGB values (e.g., [255, 0, 0]). Defaults to None. + Color representation for the ROI (e.g., "red" or [255, 0, 0]). Defaults to None. name : str, optional - A name/label for this ROI. Defaults to None. + Name/label for the ROI. Defaults to None. description : str, optional - Longer text describing this ROI. Defaults to an empty string. + Longer description of the ROI. Defaults to an empty string. use_pin_hole : bool, optional - If True, attempts to handle ROIs with holes by creating a pinhole - (a single continuous contour). Defaults to False. + If True, attempts to create a single continuous contour for ROIs with holes. Defaults to False. approximate_contours : bool, optional - If False, no approximation is done during contour generation, - potentially resulting in very large amounts of contour data. - Defaults to True. + If False, skips approximation during contour generation, leading to larger contour data. Defaults to True. roi_generation_algorithm : str or int, optional - Identifier for the algorithm used to generate this ROI. This can be - a string describing the algorithm or an integer code. Defaults to 0. - + Identifier for the algorithm used to generate the ROI. Defaults to 0. + Raises ------ ROIException - If the mask is not a 3D boolean array. - If the mask's shape does not match the loaded DICOM series dimensions. - If the mask is empty (no voxels set to True). - + Returns ------- None - This method does not return anything, but modifies the internal RTStruct. - """ + Modifies the internal RTStruct. """ - - # TODO test if name already exists + # TODO: test if name already exists self.validate_mask(mask) roi_number = len(self.ds.StructureSetROISequence) + 1 roi_data = ROIData( @@ -110,7 +104,7 @@ def add_roi( def validate_mask(self, mask: np.ndarray) -> bool: if mask.dtype != bool: raise RTStruct.ROIException( - f"Mask data type must be boolean. Got {mask.dtype}" + f"Mask data type must be boolean, but got {mask.dtype}. Please ensure the mask is a 3D boolean array." ) if mask.ndim != 3: @@ -118,7 +112,7 @@ def validate_mask(self, mask: np.ndarray) -> bool: if len(self.series_data) != np.shape(mask)[2]: raise RTStruct.ROIException( - "Mask must have the save number of layers (In the 3rd dimension) as input series. " + "Mask must have the same number of layers (in the 3rd dimension) as the input series. " + f"Expected {len(self.series_data)}, got {np.shape(mask)[2]}" ) @@ -157,19 +151,17 @@ def get_roi_mask_by_name(self, name) -> np.ndarray: def save(self, file_path: str): """ - Saves the RTStruct with the specified name / location - Automatically adds '.dcm' as a suffix + Saves the RTStruct with the specified name / location. + Automatically adds '.dcm' as a suffix if necessary. """ - # Add .dcm if needed file_path = file_path if file_path.endswith(".dcm") else file_path + ".dcm" try: - file = open(file_path, "w") - # Opening worked, we should have a valid file_path - print("Writing file to", file_path) - self.ds.save_as(file_path) - file.close() + # Using 'with' to handle file opening and closing automatically + with open(file_path, "w") as file: + print("Writing file to", file_path) + self.ds.save_as(file_path) except OSError: raise Exception(f"Cannot write to file path '{file_path}'") @@ -177,5 +169,4 @@ class ROIException(Exception): """ Exception class for invalid ROI masks """ - pass From fcbc896279eb95eec1df0f2312bcf310854ce2b9 Mon Sep 17 00:00:00 2001 From: Fereshteh Yousefirizi <84542058+qurit-frizi@users.noreply.github.com> Date: Thu, 6 Feb 2025 17:45:25 -0800 Subject: [PATCH 09/10] Update python-app.yml --- .github/workflows/python-app.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index a939d29..9856f5a 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [ "3.8", "3.9", "3.10" ] + python-version: [ "3.7", "3.8", "3.9", "3.10" ] steps: - uses: actions/checkout@v2 From bfe3ef04c90c1ff2fcd5d03f6ce5bc84d3d33ada Mon Sep 17 00:00:00 2001 From: Fereshteh Yousefirizi <84542058+qurit-frizi@users.noreply.github.com> Date: Thu, 6 Feb 2025 17:46:16 -0800 Subject: [PATCH 10/10] Update python-app.yml --- .github/workflows/python-app.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index 9856f5a..a939d29 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [ "3.7", "3.8", "3.9", "3.10" ] + python-version: [ "3.8", "3.9", "3.10" ] steps: - uses: actions/checkout@v2