From 06fe9b7ce1e5efcd235d6da93b92244609e84ae4 Mon Sep 17 00:00:00 2001 From: Sean Doyle Date: Mon, 24 May 2021 22:44:40 -0400 Subject: [PATCH 1/4] Added image_library_entries to TID 1500 --- src/highdicom/sr/templates.py | 179 +++++++++++++++++----------------- 1 file changed, 91 insertions(+), 88 deletions(-) diff --git a/src/highdicom/sr/templates.py b/src/highdicom/sr/templates.py index 2e2e39d7..fca6acb0 100644 --- a/src/highdicom/sr/templates.py +++ b/src/highdicom/sr/templates.py @@ -2721,6 +2721,93 @@ def __init__( # TODO: how to do R-INFERRED FROM relationship? self.append(value_item) +class ImageLibraryEntry(Template): + + """`TID 1601 `_ + Image Library Entry""" # noqa: E501 + + def __init__( + self, + modality: Union[Code, CodedConcept], + frame_of_reference_uid: str, + pixel_data_rows: int, + pixel_data_columns: int, + descriptors: Sequence[ContentItem] + ) -> None: + """ + Parameters + ---------- + modality: Union[highdicom.sr.coding.CodedConcept, pydicom.sr.coding.Code] + Modality + frame_of_reference_uid: str + Frame of Reference UID + pixel_data_rows: int + Number of rows in pixel data frames + pixel_data_columns: int + Number of rows in pixel data frames + descriptors: Sequence[highdicom.sr.value_types.ContentItem], optional + Additional SR Content Items that should be included + + """ # noqa + super().__init__() + modality_item = CodeContentItem( + name=CodedConcept( + value='121139', + meaning='Modality', + scheme_designator='DCM' + ), + value=modality, + relationship_type=RelationshipTypeValues.HAS_ACQ_CONTENT + ) + self.append(modality_item) + frame_of_reference_uid_item = UIDRefContentItem( + name=CodedConcept( + value='112227', + meaning='Frame of Reference UID', + scheme_designator='DCM' + ), + value=frame_of_reference_uid, + relationship_type=RelationshipTypeValues.HAS_ACQ_CONTENT + ) + self.append(frame_of_reference_uid_item) + pixel_data_rows_item = NumContentItem( + name=CodedConcept( + value='110910', + meaning='Pixel Data Rows', + scheme_designator='DCM' + ), + value=pixel_data_rows, + relationship_type=RelationshipTypeValues.HAS_ACQ_CONTENT, + unit=CodedConcept( + value='{pixels}', + meaning='Pixels', + scheme_designator='UCUM' + ) + ) + self.append(pixel_data_rows_item) + pixel_data_cols_item = NumContentItem( + name=CodedConcept( + value='110911', + meaning='Pixel Data Columns', + scheme_designator='DCM' + ), + value=pixel_data_columns, + relationship_type=RelationshipTypeValues.HAS_ACQ_CONTENT, + unit=CodedConcept( + value='{pixels}', + meaning='Pixels', + scheme_designator='UCUM' + ) + ) + self.append(pixel_data_cols_item) + for item in descriptors: + if not isinstance(item, ContentItem): + raise TypeError( + 'Image Library Entry Descriptor must have type ContentItem.' + ) + item.RelationshipType = RelationshipTypeValues.HAS_ACQ_CONTENT.value + self.append(item) + class MeasurementReport(Template): @@ -2746,7 +2833,9 @@ def __init__( title: Optional[Union[CodedConcept, Code]] = None, language_of_content_item_and_descendants: Optional[ LanguageOfContentItemAndDescendants - ] = None + ] = None, + image_library_entries: Optional[Sequence[Sequence[ImageLibraryEntry]]] = None + ): """ @@ -2812,7 +2901,7 @@ def __init__( relationship_type=RelationshipTypeValues.HAS_CONCEPT_MOD ) item.ContentSequence.append(procedure_item) - image_library_item = ImageLibrary() + image_library_item = ImageLibrary(image_library_entries) item.ContentSequence.extend(image_library_item) num_arguments_provided = sum([ @@ -3293,92 +3382,6 @@ def get_image_measurments( return sequences -class ImageLibraryEntry(Template): - - """`TID 1601 `_ - Image Library Entry""" # noqa: E501 - - def __init__( - self, - modality: Union[Code, CodedConcept], - frame_of_reference_uid: str, - pixel_data_rows: int, - pixel_data_columns: int, - descriptors: Sequence[ContentItem] - ) -> None: - """ - Parameters - ---------- - modality: Union[highdicom.sr.coding.CodedConcept, pydicom.sr.coding.Code] - Modality - frame_of_reference_uid: str - Frame of Reference UID - pixel_data_rows: int - Number of rows in pixel data frames - pixel_data_columns: int - Number of rows in pixel data frames - descriptors: Sequence[highdicom.sr.value_types.ContentItem], optional - Additional SR Content Items that should be included - - """ # noqa - super().__init__() - modality_item = CodeContentItem( - name=CodedConcept( - value='121139', - meaning='Modality', - scheme_designator='DCM' - ), - value=modality, - relationship_type=RelationshipTypeValues.HAS_ACQ_CONTENT - ) - self.append(modality_item) - frame_of_reference_uid_item = UIDRefContentItem( - name=CodedConcept( - value='112227', - meaning='Frame of Reference UID', - scheme_designator='DCM' - ), - value=frame_of_reference_uid, - relationship_type=RelationshipTypeValues.HAS_ACQ_CONTENT - ) - self.append(frame_of_reference_uid_item) - pixel_data_rows_item = NumContentItem( - name=CodedConcept( - value='110910', - meaning='Pixel Data Rows', - scheme_designator='DCM' - ), - value=pixel_data_rows, - relationship_type=RelationshipTypeValues.HAS_ACQ_CONTENT, - unit=CodedConcept( - value='{pixels}', - meaning='Pixels', - scheme_designator='UCUM' - ) - ) - self.append(pixel_data_rows_item) - pixel_data_cols_item = NumContentItem( - name=CodedConcept( - value='110911', - meaning='Pixel Data Columns', - scheme_designator='DCM' - ), - value=pixel_data_columns, - relationship_type=RelationshipTypeValues.HAS_ACQ_CONTENT, - unit=CodedConcept( - value='{pixels}', - meaning='Pixels', - scheme_designator='UCUM' - ) - ) - self.append(pixel_data_cols_item) - for item in descriptors: - if not isinstance(item, ContentItem): - raise TypeError( - 'Image Library Entry Descriptor must have type ContentItem.' - ) - item.RelationshipType = RelationshipTypeValues.HAS_ACQ_CONTENT.value - self.append(item) class ImageLibrary(Template): From c54e54e5a46af5fd89aca783edbe4be8aebe4810 Mon Sep 17 00:00:00 2001 From: Sean Doyle Date: Tue, 1 Jun 2021 08:30:14 -0400 Subject: [PATCH 2/4] Fixed enum RelationshipType --- src/highdicom/sr/enum.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/highdicom/sr/enum.py b/src/highdicom/sr/enum.py index 7cf8e0c9..64768f42 100644 --- a/src/highdicom/sr/enum.py +++ b/src/highdicom/sr/enum.py @@ -64,7 +64,7 @@ class RelationshipTypeValues(Enum): """Enumerated values for attribute Relationship Type.""" CONTAINS = 'CONTAINS' - HAS_ACQ_CONTENT = 'HAS ACQ CONTENT' + HAS_ACQ_CONTEXT = 'HAS ACQ CONTEXT' HAS_CONCEPT_MOD = 'HAS CONCEPT MOD' HAS_OBS_CONTEXT = 'HAS OBS CONTEXT' HAS_PROPERTIES = 'HAS PROPERTIES' From 492c5c4983504617a78b9e41aa02b8b71a9b4131 Mon Sep 17 00:00:00 2001 From: Sean Doyle Date: Wed, 2 Jun 2021 14:23:59 -0400 Subject: [PATCH 3/4] Coding changes --- src/highdicom/sr/templates.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/highdicom/sr/templates.py b/src/highdicom/sr/templates.py index fca6acb0..3b85fbf1 100644 --- a/src/highdicom/sr/templates.py +++ b/src/highdicom/sr/templates.py @@ -2757,7 +2757,7 @@ def __init__( scheme_designator='DCM' ), value=modality, - relationship_type=RelationshipTypeValues.HAS_ACQ_CONTENT + relationship_type=RelationshipTypeValues.HAS_ACQ_CONTEXT ) self.append(modality_item) frame_of_reference_uid_item = UIDRefContentItem( @@ -2767,7 +2767,7 @@ def __init__( scheme_designator='DCM' ), value=frame_of_reference_uid, - relationship_type=RelationshipTypeValues.HAS_ACQ_CONTENT + relationship_type=RelationshipTypeValues.HAS_ACQ_CONTEXT ) self.append(frame_of_reference_uid_item) pixel_data_rows_item = NumContentItem( @@ -2777,7 +2777,7 @@ def __init__( scheme_designator='DCM' ), value=pixel_data_rows, - relationship_type=RelationshipTypeValues.HAS_ACQ_CONTENT, + relationship_type=RelationshipTypeValues.HAS_ACQ_CONTEXT, unit=CodedConcept( value='{pixels}', meaning='Pixels', @@ -2792,7 +2792,7 @@ def __init__( scheme_designator='DCM' ), value=pixel_data_columns, - relationship_type=RelationshipTypeValues.HAS_ACQ_CONTENT, + relationship_type=RelationshipTypeValues.HAS_ACQ_CONTEXT, unit=CodedConcept( value='{pixels}', meaning='Pixels', @@ -2805,7 +2805,7 @@ def __init__( raise TypeError( 'Image Library Entry Descriptor must have type ContentItem.' ) - item.RelationshipType = RelationshipTypeValues.HAS_ACQ_CONTENT.value + item.RelationshipType = RelationshipTypeValues.HAS_ACQ_CONTEXT.value self.append(item) @@ -3414,7 +3414,7 @@ def __init__( for group in entries: group_item = ContainerContentItem( name=CodedConcept( - value='26200', + value='126200', meaning='Image Library Group', scheme_designator='DCM' ), From 9d492a25aedbf0ec99c88754286b81913e4f11d4 Mon Sep 17 00:00:00 2001 From: Sean Doyle Date: Wed, 2 Jun 2021 17:35:12 -0400 Subject: [PATCH 4/4] Fixed flake8 and unit test issues --- src/highdicom/sr/__init__.py | 2 ++ src/highdicom/sr/templates.py | 11 +++++------ tests/test_sr.py | 4 ++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/highdicom/sr/__init__.py b/src/highdicom/sr/__init__.py index a5944ce2..b656903c 100644 --- a/src/highdicom/sr/__init__.py +++ b/src/highdicom/sr/__init__.py @@ -31,6 +31,7 @@ AlgorithmIdentification, DeviceObserverIdentifyingAttributes, ImageLibrary, + ImageLibraryEntry, LanguageOfContentItemAndDescendants, Measurement, MeasurementProperties, @@ -107,6 +108,7 @@ 'GraphicTypeValues3D', 'ImageContentItem', 'ImageLibrary', + 'ImageLibraryEntry', 'ImageRegion', 'ImageRegion3D', 'LanguageOfContentItemAndDescendants', diff --git a/src/highdicom/sr/templates.py b/src/highdicom/sr/templates.py index 3b85fbf1..9afe163d 100644 --- a/src/highdicom/sr/templates.py +++ b/src/highdicom/sr/templates.py @@ -1,7 +1,6 @@ """DICOM structured reporting templates.""" -from typing import Any, Dict, List, Optional, Sequence, Union +from typing import List, Optional, Sequence, Union -import numpy as np from pydicom.dataset import Dataset from pydicom.sr.coding import Code from pydicom.sr.codedict import codes @@ -2721,6 +2720,7 @@ def __init__( # TODO: how to do R-INFERRED FROM relationship? self.append(value_item) + class ImageLibraryEntry(Template): """`TID 1601 `_ @@ -2834,8 +2834,9 @@ def __init__( language_of_content_item_and_descendants: Optional[ LanguageOfContentItemAndDescendants ] = None, - image_library_entries: Optional[Sequence[Sequence[ImageLibraryEntry]]] = None - + image_library_entries: Optional[ + Sequence[Sequence[ImageLibraryEntry]] + ] = None ): """ @@ -3382,8 +3383,6 @@ def get_image_measurments( return sequences - - class ImageLibrary(Template): """`TID 1600 `_ diff --git a/tests/test_sr.py b/tests/test_sr.py index 68069b4e..8462689b 100644 --- a/tests/test_sr.py +++ b/tests/test_sr.py @@ -2972,12 +2972,12 @@ def test_construction(self): content_date_item = DateContentItem( name=codes.DCM.ContentDate, value=content_date, - relationship_type=RelationshipTypeValues.HAS_ACQ_CONTENT + relationship_type=RelationshipTypeValues.HAS_ACQ_CONTEXT ) content_time_item = TimeContentItem( name=codes.DCM.ContentTime, value=content_time, - relationship_type=RelationshipTypeValues.HAS_ACQ_CONTENT + relationship_type=RelationshipTypeValues.HAS_ACQ_CONTEXT ) entry = ImageLibraryEntry( modality=modality,