123/z3.rtss.py
2025-02-01 15:57:22 +08:00

199 lines
7.7 KiB
Python
Executable file

import os
from typing import Optional
import pyradise.data as ps_data
import pyradise.fileio as ps_io
class ExampleModalityExtractor(ps_io.ModalityExtractor):
def extract_from_dicom(self,
path: str
) -> Optional[ps_data.Modality]:
# Extract the necessary attributes from the DICOM file
tags = (ps_io.Tag((0x0008, 0x0060)), # Modality
ps_io.Tag((0x0008, 0x103e))) # Series Description
dataset_dict = self._load_dicom_attributes(tags, path)
# Identify the modality rule-based
modality = dataset_dict.get('Modality', {}).get('value', None)
series_desc = dataset_dict.get('Series Description', {}).get('value', '')
if modality == 'MR':
if 't1' in series_desc.lower():
return ps_data.Modality('T1')
elif 't2' in series_desc.lower():
return ps_data.Modality('T2')
else:
return None
else:
return None
def extract_from_path(self,
path: str
) -> Optional[ps_data.Modality]:
# Identify the discrete image file's modality rule-based
filename = os.path.basename(path)
# Check if the image contains an img prefix
# (i.e., it is a intensity image)
if not filename.startswith('img'):
return None
# Check if the image contains a modality search string
if 'T1' in filename:
return ps_data.Modality('T1')
elif 'T2' in filename:
return ps_data.Modality('T2')
else:
return None
class ExampleOrganExtractor(ps_io.OrganExtractor):
def extract(self,
path: str
) -> Optional[ps_data.Organ]:
# Identify the discrete image file's organ rule-based
filename = os.path.basename(path)
# Check if the image contains a seg prefix
# (i.e., it is a segmentation)
if not filename.startswith('seg'):
return None
# Split the filename for extracting the organ name
organ_name = filename.split('_')[-1].split('.')[0]
return ps_data.Organ(organ_name)
class ExampleAnnotatorExtractor(ps_io.AnnotatorExtractor):
def extract(self,
path: str
) -> Optional[ps_data.Annotator]:
# Identify the discrete image file's annotator rule-based
filename = os.path.basename(path)
# Check if the image contains a seg prefix
# (i.e., it is a segmentation)
if not filename.startswith('seg'):
return None
# Split the filename for extracting the annotator name
annotator_name = filename.split('_')[2]
return ps_data.Annotator(annotator_name)
def convert_subject_to_dicom_rtss(input_dir_path: str,
output_dir_path: str,
dicom_image_dir_path: str,
use_3d_conversion: bool = True
) -> None:
# Specify a reference modalities
# This is the modality of the DICOM image series that will be
# referenced in the DICOM-RTSS.
reference_modality = 'T1'
# Create the loader
loader = ps_io.SubjectLoader()
# Create the writer and specify the output file name of the
# DICOM-RTSS files
writer = ps_io.DicomSeriesSubjectWriter()
rtss_filename = 'rtss.dcm'
# (optional)
# Instantiate a new selection to exclude the original DICOM-RTSS SeriesInfo
# Note: If this is omitted the original DICOM-RTSS will be copied to the
# corresponding output directory.
selection = ps_io.NoRTSSInfoSelector()
# Create the file crawler for the discrete image files and
# loop through the subjects
crawler = ps_io.DatasetFileCrawler(input_dir_path,
extension='.nii.gz',
modality_extractor=ExampleModalityExtractor(),
organ_extractor=ExampleOrganExtractor(),
annotator_extractor=ExampleAnnotatorExtractor())
for series_info in crawler:
# Load the subject
subject = loader.load(series_info)
# Print the progress
print(f'Converting subject {subject.get_name()}...')
# Construct the path to the subject's DICOM images
dicom_subject_path = os.path.join(dicom_image_dir_path, subject.get_name())
# Construct a DICOM crawler to retrieve the reference
# DICOM image series info
dcm_crawler = ps_io.SubjectDicomCrawler(dicom_subject_path,
modality_extractor=ExampleModalityExtractor())
dicom_series_info = dcm_crawler.execute()
# (optional)
# Keep all SeriesInfo entries that do not describe a DICOM-RTSS for loading
dicom_series_info = selection.execute(dicom_series_info)
# (optional)
# Define the metadata for the DICOM-RTSS
# Note: For some attributes, the value must follow the value
# representation of the DICOM standard.
meta_data = ps_io.RTSSMetaData(patient_size='180',
patient_weight='80',
patient_age='050Y',
series_description='Converted from NIfTI')
# Convert the segmentations to a DICOM-RTSS with standard smoothing settings.
# For the conversion we can either use a 2D or a 3D algorithm (see API reference
# for details).
# Note: Inappropriate smoothing leads to corrupted structures if their size
# is too small
if use_3d_conversion:
conv_conf = ps_io.RTSSConverter3DConfiguration()
else:
conv_conf = ps_io.RTSSConverter2DConfiguration()
converter = ps_io.SubjectToRTSSConverter(subject,
dicom_series_info,
reference_modality,
conv_conf,
meta_data)
rtss = converter.convert()
# Combine the DICOM-RTSS with its output file name
rtss_combination = ((rtss_filename, rtss),)
# Write the DICOM-RTSS to a separate subject directory
# and include the DICOM files crawled before
# Note: If you want to output just a subset of the
# original DICOM files you may use additional selectors
writer.write(rtss_combination, output_dir_path,
subject.get_name(), dicom_series_info)
# The indicator if the 2D or the 3D conversion algorithm should
# be used.
use_3d_algorithm = True
# The input path pointing to the top-level directory containing the
# NIfTI subject directories
input_dataset_path = '//YOUR/PATH/TO/THE/EXAMPLE/DATA/nifti_data'
input_dataset_path = '/nn/3378417/20241112/output/7_AX_3D_fl3d_mt_FS_+_c_20241112142646.nii.gz'
input_dataset_path = '/nn/3378417/20241112/output'
# The input path pointing to the top-level directory containing the
# DICOM subject directories that will get referenced in the output
# DICOM-RTSS files
dicom_dataset_path = '//YOUR/PATH/TO/THE/EXAMPLE/DATA/dicom_data'
dicom_dataset_path = '/nn/3378417/20241112/CT/8'
# The output path pointing to an empty directory where the output
# will be saved
output_dataset_path = '//YOUR/PATH/TO/THE/OUTPUT/DIRECTORY/'
output_dataset_path = '0'
# Execution of the conversion procedure
convert_subject_to_dicom_rtss(input_dataset_path,
output_dataset_path,
dicom_dataset_path,
use_3d_algorithm)