Skip to content

Commit

Permalink
refactor: remove use_media_storage and use base attributes instead of…
Browse files Browse the repository at this point in the history
… media header attributes
  • Loading branch information
asim-shrestha committed Jan 8, 2022
1 parent 113af4e commit d68d2cc
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 46 deletions.
49 changes: 19 additions & 30 deletions rt_utils/ds_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
"""


def create_rtstruct_dataset(series_data, use_media_storage: bool = True) -> FileDataset:
def create_rtstruct_dataset(series_data) -> FileDataset:
ds = generate_base_dataset()
add_study_and_series_information(ds, series_data)
add_patient_information(ds, series_data)
add_refd_frame_of_ref_sequence(ds, series_data, use_media_storage)
add_refd_frame_of_ref_sequence(ds, series_data)
return ds


Expand Down Expand Up @@ -94,21 +94,21 @@ def add_patient_information(ds: FileDataset, series_data):
ds.PatientWeight = getattr(reference_ds, 'PatientWeight', '')


def add_refd_frame_of_ref_sequence(ds: FileDataset, series_data, use_media_storage: bool = True):
def add_refd_frame_of_ref_sequence(ds: FileDataset, series_data):
refd_frame_of_ref = Dataset()
refd_frame_of_ref.FrameOfReferenceUID = generate_uid() # TODO Find out if random generation is ok
refd_frame_of_ref.RTReferencedStudySequence = create_frame_of_ref_study_sequence(series_data, use_media_storage)
refd_frame_of_ref.RTReferencedStudySequence = create_frame_of_ref_study_sequence(series_data)

# Add to sequence
ds.ReferencedFrameOfReferenceSequence = Sequence()
ds.ReferencedFrameOfReferenceSequence.append(refd_frame_of_ref)


def create_frame_of_ref_study_sequence(series_data, use_media_storage: bool = True) -> Sequence:
def create_frame_of_ref_study_sequence(series_data) -> Sequence:
reference_ds = series_data[0] # All elements in series should have the same data
rt_refd_series = Dataset()
rt_refd_series.SeriesInstanceUID = reference_ds.SeriesInstanceUID
rt_refd_series.ContourImageSequence = create_contour_image_sequence(series_data, use_media_storage)
rt_refd_series.ContourImageSequence = create_contour_image_sequence(series_data)

rt_refd_series_sequence = Sequence()
rt_refd_series_sequence.append(rt_refd_series)
Expand All @@ -123,22 +123,15 @@ def create_frame_of_ref_study_sequence(series_data, use_media_storage: bool = Tr
return rt_refd_study_sequence


def create_contour_image_sequence(series_data, use_media_storage: bool = True) -> Sequence:
def create_contour_image_sequence(series_data) -> Sequence:
contour_image_sequence = Sequence()

# Add each referenced image
if use_media_storage:
for series in series_data:
contour_image = Dataset()
contour_image.ReferencedSOPClassUID = series.file_meta.MediaStorageSOPClassUID
contour_image.ReferencedSOPInstanceUID = series.file_meta.MediaStorageSOPInstanceUID
contour_image_sequence.append(contour_image)
else:
for series in series_data:
contour_image = Dataset()
contour_image.ReferencedSOPClassUID = series.SOPClassUID
contour_image.ReferencedSOPInstanceUID = series.SOPInstanceUID
contour_image_sequence.append(contour_image)
for series in series_data:
contour_image = Dataset()
contour_image.ReferencedSOPClassUID = series.SOPClassUID
contour_image.ReferencedSOPInstanceUID = series.SOPInstanceUID
contour_image_sequence.append(contour_image)

return contour_image_sequence

Expand All @@ -154,15 +147,15 @@ def create_structure_set_roi(roi_data: ROIData) -> Dataset:
return structure_set_roi


def create_roi_contour(roi_data: ROIData, series_data, use_media_storage: bool = True) -> Dataset:
def create_roi_contour(roi_data: ROIData, series_data) -> Dataset:
roi_contour = Dataset()
roi_contour.ROIDisplayColor = roi_data.color
roi_contour.ContourSequence = create_contour_sequence(roi_data, series_data, use_media_storage)
roi_contour.ContourSequence = create_contour_sequence(roi_data, series_data)
roi_contour.ReferencedROINumber = str(roi_data.number)
return roi_contour


def create_contour_sequence(roi_data: ROIData, series_data, use_media_storage: bool = True) -> Sequence:
def create_contour_sequence(roi_data: ROIData, series_data) -> Sequence:
"""
Iterate through each slice of the mask
For each connected segment within a slice, create a contour
Expand All @@ -174,20 +167,16 @@ def create_contour_sequence(roi_data: ROIData, series_data, use_media_storage: b

for series_slice, slice_contours in zip(series_data, contours_coords):
for contour_data in slice_contours:
contour = create_contour(series_slice, contour_data, use_media_storage)
contour = create_contour(series_slice, contour_data)
contour_sequence.append(contour)

return contour_sequence


def create_contour(series_slice: Dataset, contour_data: np.ndarray, use_media_storage: bool = True) -> Dataset:
def create_contour(series_slice: Dataset, contour_data: np.ndarray) -> Dataset:
contour_image = Dataset()
if use_media_storage:
contour_image.ReferencedSOPClassUID = series_slice.file_meta.MediaStorageSOPClassUID
contour_image.ReferencedSOPInstanceUID = series_slice.file_meta.MediaStorageSOPInstanceUID
else:
contour_image.ReferencedSOPClassUID = series_slice.SOPClassUID
contour_image.ReferencedSOPInstanceUID = series_slice.SOPInstanceUID
contour_image.ReferencedSOPClassUID = series_slice.SOPClassUID
contour_image.ReferencedSOPInstanceUID = series_slice.SOPInstanceUID

# Contour Image Sequence
contour_image_sequence = Sequence()
Expand Down
4 changes: 2 additions & 2 deletions rt_utils/rtstruct.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def add_roi(
use_pin_hole: bool = False,
approximate_contours: bool = True,
roi_generation_algorithm: Union[str, int] = 0,
use_media_storage: bool = True):
):
"""
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
Expand All @@ -57,7 +57,7 @@ def add_roi(
roi_generation_algorithm
)

self.ds.ROIContourSequence.append(ds_helper.create_roi_contour(roi_data, self.series_data, use_media_storage))
self.ds.ROIContourSequence.append(ds_helper.create_roi_contour(roi_data, self.series_data))
self.ds.StructureSetROISequence.append(ds_helper.create_structure_set_roi(roi_data))
self.ds.RTROIObservationsSequence.append(ds_helper.create_rtroi_observation(roi_data))

Expand Down
22 changes: 8 additions & 14 deletions rt_utils/rtstruct_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ def create_new(dicom_series_path: str) -> RTStruct:
return RTStruct(series_data, ds)

@staticmethod
def create_from(dicom_series_path: str, rt_struct_path: str, use_media_storage: bool = True) -> RTStruct:
def create_from(dicom_series_path: str, rt_struct_path: str) -> RTStruct:
"""
Method to load an existing rt struct, given related DICOM series and existing rt struct
"""

series_data = image_helper.load_sorted_image_series(dicom_series_path)
ds = dcmread(rt_struct_path)
RTStructBuilder.validate_rtstruct(ds)
RTStructBuilder.validate_rtstruct_series_references(ds, series_data, use_media_storage)
RTStructBuilder.validate_rtstruct_series_references(ds, series_data)

# TODO create new frame of reference? Right now we assume the last frame of reference created is suitable
return RTStruct(series_data, ds)
Expand All @@ -49,7 +49,7 @@ def validate_rtstruct(ds: Dataset):
raise Exception("Please check that the existing RTStruct is valid")

@staticmethod
def validate_rtstruct_series_references(ds: Dataset, series_data: List[Dataset], use_media_storage: bool = True):
def validate_rtstruct_series_references(ds: Dataset, series_data: List[Dataset]):
"""
Method to validate RTStruct only references dicom images found within the input series_data
"""
Expand All @@ -58,22 +58,16 @@ def validate_rtstruct_series_references(ds: Dataset, series_data: List[Dataset],
for rt_refd_series in rt_refd_study.RTReferencedSeriesSequence:
for contour_image in rt_refd_series.ContourImageSequence:
RTStructBuilder.validate_contour_image_in_series_data(
contour_image, series_data, use_media_storage)
contour_image, series_data)

@staticmethod
def validate_contour_image_in_series_data(contour_image: Dataset, series_data: List[Dataset],
use_media_storage: bool = True):
def validate_contour_image_in_series_data(contour_image: Dataset, series_data: List[Dataset]):
"""
Method to validate that the ReferencedSOPInstanceUID of a given contour image exists within the series data
"""
if use_media_storage:
for series in series_data:
if contour_image.ReferencedSOPInstanceUID == series.file_meta.MediaStorageSOPInstanceUID:
return
else:
for series in series_data:
if contour_image.ReferencedSOPInstanceUID == series.SOPInstanceUID:
return
for series in series_data:
if contour_image.ReferencedSOPInstanceUID == series.SOPInstanceUID:
return

# ReferencedSOPInstanceUID is NOT available
raise Exception(
Expand Down

0 comments on commit d68d2cc

Please sign in to comment.