Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add properties and methods to SR content items and templates #69

Closed
wants to merge 114 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
114 commits
Select commit Hold shift + click to select a range
d9784a7
Fix recording of evidence in structured reports
hackermd Apr 29, 2021
f2e8ddf
Increase package version
hackermd Apr 29, 2021
c91d00b
Assert that evidence is provided for references
hackermd May 1, 2021
8e6ad62
Use sets for comparison and avoid duplicates
hackermd May 2, 2021
58351d6
Fix mypy errors
hackermd May 2, 2021
dbe4c77
Add test for report referencing multiple studies
hackermd May 2, 2021
7284f0c
Remove import statement for unused variable
hackermd May 2, 2021
c24d0e0
Add properties to content items
hackermd May 7, 2021
466819c
Fix recording of evidence in structured reports
hackermd Apr 29, 2021
68af856
Use sets for comparison and avoid duplicates
hackermd May 2, 2021
0665672
Fix mypy errors
hackermd May 2, 2021
1e0bb4f
Add test for report referencing multiple studies
hackermd May 2, 2021
9205175
Add properties to content items
hackermd May 7, 2021
da95df2
Merge branch 'feat/sr-content-decoding' of github:mghcomputationalpat…
hackermd May 7, 2021
97622c7
Use datetime workaround for python 3.6 support
hackermd May 7, 2021
0bb3660
Incomplete implementation of image library
hackermd May 9, 2021
0be93c3
Add proporties and methods on SR templates
hackermd May 11, 2021
d3b1fde
Update type of content item property return value
hackermd May 11, 2021
ce92631
Fix alternative construction of sr documents
hackermd May 15, 2021
7ac37ab
Typo in exception message
May 19, 2021
82f8520
Fix recording of evidence in structured reports
hackermd Apr 29, 2021
7340f25
Use sets for comparison and avoid duplicates
hackermd May 2, 2021
e67a7a0
Fix mypy errors
hackermd May 2, 2021
503118c
Add test for report referencing multiple studies
hackermd May 2, 2021
76eb2e8
Add properties to content items
hackermd May 7, 2021
cda1d75
Fix recording of evidence in structured reports
hackermd Apr 29, 2021
0344ea2
Use sets for comparison and avoid duplicates
hackermd May 2, 2021
56b674e
Fix mypy errors
hackermd May 2, 2021
9986b3e
Add test for report referencing multiple studies
hackermd May 2, 2021
ea1aacc
Use datetime workaround for python 3.6 support
hackermd May 7, 2021
8ad116f
Incomplete implementation of image library
hackermd May 9, 2021
625d08b
Add proporties and methods on SR templates
hackermd May 11, 2021
284882d
Update type of content item property return value
hackermd May 11, 2021
682fa4e
Fix alternative construction of sr documents
hackermd May 15, 2021
dd2ce5d
Update package version
hackermd May 19, 2021
8187f5f
Merge branch 'feat/sr-content-decoding' of github:mghcomputationalpat…
hackermd May 19, 2021
a8158ff
Feat/image library entries (#77)
seandoyle Jun 2, 2021
c722722
Fix handling of library entry descriptors
hackermd Jun 3, 2021
81e3cb7
Fix default value for Pixel Origin Intepretation
hackermd Jun 4, 2021
b607a3b
Rename methods for parsing measurement groups
hackermd Jul 1, 2021
da9f066
Fix implementation of content property on SR documents
hackermd Jul 1, 2021
28f804a
Update src/highdicom/sr/templates.py
hackermd Jul 2, 2021
fbcd5d0
Update src/highdicom/sr/templates.py
hackermd Jul 2, 2021
fb502ac
Update src/highdicom/sr/templates.py
hackermd Jul 2, 2021
a6ba143
Update src/highdicom/sr/templates.py
hackermd Jul 2, 2021
1ff4dc8
Update src/highdicom/sr/templates.py
hackermd Jul 2, 2021
abf591f
Update src/highdicom/sr/value_types.py
hackermd Jul 2, 2021
909dc49
Update src/highdicom/sr/value_types.py
hackermd Jul 2, 2021
65494fe
Update src/highdicom/sr/templates.py
hackermd Jul 2, 2021
eac61df
Update src/highdicom/sr/templates.py
hackermd Jul 2, 2021
9f58e0f
Update src/highdicom/sr/templates.py
hackermd Jul 2, 2021
a822a2f
Update src/highdicom/sr/templates.py
hackermd Jul 2, 2021
c7b2a95
Update src/highdicom/sr/templates.py
hackermd Jul 2, 2021
dc641b4
Update src/highdicom/sr/value_types.py
hackermd Jul 2, 2021
52f63ac
Update src/highdicom/sr/value_types.py
hackermd Jul 2, 2021
1c65b8e
Update src/highdicom/sr/templates.py
hackermd Jul 2, 2021
d59788b
Fix typo in method name
hackermd Jul 2, 2021
453660c
Merge branch 'feat/sr-content-decoding' of github:mghcomputationalpat…
hackermd Jul 2, 2021
8b6a3c6
Update src/highdicom/sr/templates.py
hackermd Jul 2, 2021
473cd54
Update src/highdicom/sr/templates.py
hackermd Jul 2, 2021
12e1e8f
Update src/highdicom/sr/templates.py
hackermd Jul 2, 2021
aaef0a5
Update tests/test_content.py
hackermd Jul 2, 2021
06d0570
Update src/highdicom/sr/templates.py
hackermd Jul 2, 2021
bd53fb5
Update src/highdicom/sr/templates.py
hackermd Jul 2, 2021
3b930aa
Update src/highdicom/sr/templates.py
hackermd Jul 2, 2021
e2777fd
Update src/highdicom/sr/templates.py
hackermd Jul 2, 2021
1fa5b8a
Update src/highdicom/sr/templates.py
hackermd Jul 2, 2021
c40b58f
Update src/highdicom/sr/value_types.py
hackermd Jul 2, 2021
af97b2c
Update src/highdicom/sr/value_types.py
hackermd Jul 2, 2021
20e56ff
Update src/highdicom/sr/value_types.py
hackermd Jul 2, 2021
359f440
Update src/highdicom/sr/value_types.py
hackermd Jul 2, 2021
57c8b77
Update src/highdicom/sr/value_types.py
hackermd Jul 2, 2021
1415660
Update src/highdicom/sr/value_types.py
hackermd Jul 2, 2021
02d455f
Update src/highdicom/sr/templates.py
hackermd Jul 2, 2021
70a7912
Use constant for code missing in pydicom
hackermd Jul 2, 2021
bdd39ba
Update src/highdicom/sr/templates.py
hackermd Jul 2, 2021
be5c830
Use constant for code missing in pydicom
hackermd Jul 2, 2021
2d448c2
Fix alternative construction of template instances
hackermd Jul 2, 2021
f615e4e
Merge branch 'feat/sr-content-decoding' of github:mghcomputationalpat…
hackermd Jul 2, 2021
f34cfc1
Make value and unit required for NUM content items
hackermd Jul 2, 2021
19dad8f
Update tests for NUM content items
hackermd Jul 2, 2021
8c96ec9
Fix return value type of properties of NUM content item
hackermd Jul 2, 2021
22a54b7
Add qualifier property to NUM content item
hackermd Jul 2, 2021
005fc3d
Return uids of type UID instead of str
hackermd Jul 2, 2021
e8d50a4
Clarify array dimensions in property docstring
hackermd Jul 2, 2021
b5b3f7e
Simplify reshaping of graphic data array
hackermd Jul 2, 2021
d5438cc
Merge branch 'master' into feat/sr-content-decoding
hackermd Jul 2, 2021
bb9fd8e
Add is_root parameter to alternative constructor
hackermd Jul 2, 2021
e1f7caa
Fix unit tests
hackermd Jul 2, 2021
cad8120
Reuse CodedConcept.from_dataset method
hackermd Jul 2, 2021
9297638
Allow constructor of UID to accept a value
hackermd Jul 2, 2021
979e3ae
Return UID instead of str instances
hackermd Jul 2, 2021
7f9f7f4
Return empty list instead of None
hackermd Jul 2, 2021
ed4383b
Fix filtering logic of template methods
hackermd Jul 2, 2021
2ee628b
Refactor detection of measurement groups
hackermd Jul 6, 2021
8ca64c6
Apply suggestions from code review
hackermd Jul 6, 2021
4475f05
Log warning if wrong number of content items
hackermd Jul 6, 2021
ee8baee
Merge branch 'feat/sr-content-decoding' of github:mghcomputationalpat…
hackermd Jul 6, 2021
4824abb
Fix construction of content item from dataset
hackermd Jul 6, 2021
4ff586e
Fix construction of code content item from dataset
hackermd Jul 6, 2021
7c2981f
Add property for temporal range type
hackermd Jul 6, 2021
fc6c95c
Update src/highdicom/sr/templates.py
hackermd Jul 6, 2021
6adbf6a
Use image pixel description instead of pixel data
hackermd Jul 6, 2021
505ea88
Update summary in docstrings
hackermd Jul 8, 2021
9a78df3
Apply suggestions from code review
hackermd Jul 8, 2021
5217b32
Improve docstring of methods
hackermd Jul 8, 2021
0b5ae3d
Move QualitativeEvaluation from content to templates
hackermd Jul 12, 2021
e1c07cd
Fix type of return value of template methods
hackermd Jul 12, 2021
5d5b435
Handle measurements without child items
hackermd Jul 14, 2021
e3f86ad
Remove print statement
hackermd Jul 14, 2021
36a3f70
Add query filters for report methods
hackermd Jul 15, 2021
c9fd35b
Add unit tests for measurement group queries
hackermd Jul 15, 2021
d0ca793
Fix parsing of sr documents
hackermd Jul 15, 2021
3133e70
Remove code for special frame decoding
hackermd Jul 19, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified data/test_files/sr_document.dcm
Binary file not shown.
35 changes: 1 addition & 34 deletions src/highdicom/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ def __init__(
required by the corresponding Information Object Definition (IOD).
Additional optional attributes can subsequently be added to the dataset.

""" # noqa
""" # noqa: E501
super().__init__()
if transfer_syntax_uid is None:
transfer_syntax_uid = ImplicitVRLittleEndian
Expand Down Expand Up @@ -279,36 +279,3 @@ def copy_specimen_information(self, dataset: Dataset) -> None:

"""
self._copy_root_attributes_of_module(dataset, 'Image', 'Specimen')

@classmethod
def from_dataset(cls, dataset: Dataset) -> 'SOPClass':
try:
inst = cls(
study_instance_uid=dataset.StudyInstanceUID,
series_instance_uid=dataset.SeriesInstanceUID,
series_number=dataset.SeriesNumber,
sop_instance_uid=dataset.SOPInstanceUID,
sop_class_uid=dataset.SOPClassUID,
instance_number=dataset.InstanceNumber,
manufacturer=dataset.Manufacturer,
modality=dataset.Modality,
transfer_syntax_uid=dataset.file_meta.TransferSyntaxUID,
patient_id=dataset.PatientID,
patient_name=dataset.PatientName,
patient_birth_date=dataset.PatientBirthDate,
patient_sex=dataset.PatientSex,
accession_number=dataset.AccessionNumber,
study_id=dataset.StudyID,
study_date=dataset.StudyDate,
study_time=dataset.StudyTime,
referring_physician_name=dataset.ReferringPhysicianName
)
except AttributeError as error:
raise AttributeError(
'Required attribute missing: {}'.format(error)
)
if inst.SOPClassUID != dataset.SOPClassUID:
raise AttributeError(
'Incorrect SOP Class UID for type "{}".'.format(cls.__name__)
)
return inst
2 changes: 1 addition & 1 deletion src/highdicom/coding_schemes.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def __init__(
resources: Sequence[pydicom.sr.coding.CodingSchemeResourceItem], optional
one or more resources related to the scheme

""" # noqa
""" # noqa: E501
super().__init__()
self.CodingSchemeDesignator = str(designator)
if name is not None:
Expand Down
14 changes: 7 additions & 7 deletions src/highdicom/content.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def __init__(
Name and actual value of the parameters with which the algorithm
was invoked

""" # noqa
""" # noqa: E501
super().__init__()
item = Dataset()
item.AlgorithmName = name
Expand Down Expand Up @@ -313,7 +313,7 @@ def __init__(
Type of identifier of the entity that created the examined specimen
(required if `issuer_of_specimen_id` is a Unique Entity ID)

""" # noqa
""" # noqa: E501
super().__init__()
if issuer_of_identifier_type is None:
self.LocalNamespaceEntityID = issuer_of_identifier
Expand Down Expand Up @@ -341,7 +341,7 @@ def __init__(
procedure: Union[pydicom.sr.coding.Code, highdicom.sr.CodedConcept]
Procedure used to collect the examined specimen

""" # noqa
""" # noqa: E501
super().__init__()
item = CodeContentItem(
name=codes.SCT.SpecimenCollection,
Expand Down Expand Up @@ -377,7 +377,7 @@ def __init__(
issuer_of_parent_specimen_id: highdicom.IssuerOfIdentifier, optional
Issuer who created the parent specimen

""" # noqa
""" # noqa: E501
super().__init__()
# CID 8110
method_item = CodeContentItem(
Expand Down Expand Up @@ -426,7 +426,7 @@ def __init__(
substances: Sequence[Union[pydicom.sr.coding.Code, highdicom.sr.CodedConcept]]
Substances used to stain examined specimen(s)

""" # noqa
""" # noqa: E501
super().__init__()
# CID 8112
for s in substances:
Expand Down Expand Up @@ -481,7 +481,7 @@ def __init__(
embedding_medium: Union[pydicom.sr.coding.Code, highdicom.sr.CodedConcept], optional
Embedding medium used during processing

""" # noqa
""" # noqa: E501
super().__init__()
specimen_identifier_item = TextContentItem(
name=codes.DCM.SpecimenIdentifier,
Expand Down Expand Up @@ -572,7 +572,7 @@ def __init__(
issuer_of_specimen_id: highdicom.IssuerOfIdentifier, optional
Description of the issuer of the specimen identifier

""" # noqa
""" # noqa: E501
super().__init__()
self.SpecimenIdentifier = specimen_id
self.SpecimenUID = specimen_uid
Expand Down
23 changes: 1 addition & 22 deletions src/highdicom/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -323,28 +323,7 @@ def decode_frame(
ds.HighBit = bits_stored - 1

if UID(file_meta.TransferSyntaxUID).is_encapsulated:
if (transfer_syntax_uid == JPEGBaseline and
photometric_interpretation == 'RGB'):
# RGB color images, which were not transformed into YCbCr color
# space upon JPEG compression, need to be handled separately.
# Pillow assumes that images were transformed into YCbCr color
# space prior to JPEG compression. However, with photometric
# interpretation RGB, no color transformation was performed.
# Setting the value of "mode" to YCbCr signals Pillow to not
# apply any color transformation upon decompression.
image = Image.open(BytesIO(value))
color_mode = 'YCbCr'
image.tile = [(
'jpeg',
image.tile[0][1],
image.tile[0][2],
(color_mode, ''),
)]
image.mode = color_mode
image.rawmode = color_mode
return np.asarray(image)
else:
ds.PixelData = encapsulate(frames=[value])
ds.PixelData = encapsulate(frames=[value])
else:
ds.PixelData = value

Expand Down
2 changes: 1 addition & 1 deletion src/highdicom/sc/sop.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ def __init__(
Additional keyword arguments that will be passed to the constructor
of `highdicom.base.SOPClass`

""" # noqa
""" # noqa: E501
supported_transfer_syntaxes = {
ImplicitVRLittleEndian,
ExplicitVRLittleEndian,
Expand Down
4 changes: 2 additions & 2 deletions src/highdicom/seg/content.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def __init__(
must have consecutive segment numbers, starting at 1 for the first
segment added.

""" # noqa
""" # noqa: E501
super().__init__()
if segment_number < 1:
raise ValueError("Segment number must be a positive integer")
Expand Down Expand Up @@ -291,7 +291,7 @@ def __init__(

else:
raise ValueError(
f'Unknown coordinate system "{self._coordinat_system}"'
f'Unknown coordinate system "{self._coordinate_system}"'
)

def get_plane_positions_of_image(
Expand Down
4 changes: 2 additions & 2 deletions src/highdicom/seg/sop.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ def __init__(
the same frame of reference as `source_images`.


""" # noqa
""" # noqa: E501
if len(source_images) == 0:
raise ValueError('At least one source image is required.')
self._source_images = source_images
Expand Down Expand Up @@ -535,7 +535,7 @@ def add_segments(
one segment can be encoded by `pixel_array` and hence only one item is
permitted in `segment_descriptions`.

""" # noqa
""" # noqa: E501
if pixel_array.ndim == 2:
pixel_array = pixel_array[np.newaxis, ...]
if pixel_array.ndim != 3:
Expand Down
2 changes: 1 addition & 1 deletion src/highdicom/seg/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def iter_segments(dataset: Dataset) -> Iterator:
AttributeError
When data set does not contain Content Sequence attribute.

""" # noqa
""" # noqa: E501
if not hasattr(dataset, 'PixelData'):
raise AttributeError(
'Data set does not contain a Pixel Data attribute.'
Expand Down
2 changes: 0 additions & 2 deletions src/highdicom/spatial.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,9 @@ class ImageToReferenceTransformer(object):
>>> image_orientation=[1.0, 0.0, 0.0, 0.0, 1.0, 0.0],
>>> pixel_spacing=[0.5, 0.5]
>>> )
>>>
>>> # Use the transformer to convert coordinates
>>> image_coords = np.array([[0.0, 10.0], [5.0, 5.0]])
>>> ref_coords = transformer(image_coords)
>>>
>>> print(ref_coords)
>>> # [[56. 39.2 1. ]
>>> # [58.5 36.7 1. ]]
Expand Down
8 changes: 7 additions & 1 deletion src/highdicom/sr/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
SourceImageForSegmentation,
SourceImageForRegion,
SourceSeriesForSegmentation,
QualitativeEvaluation,
RealWorldValueMap,
ReferencedSegment,
ReferencedSegmentationFrame,
Expand All @@ -18,10 +17,12 @@
from highdicom.sr.enum import (
GraphicTypeValues,
GraphicTypeValues3D,
PlanarROITypes,
PixelOriginInterpretationValues,
RelationshipTypeValues,
TemporalRangeTypeValues,
ValueTypeValues,
VolumetricROITypes,
)
from highdicom.sr.sop import (
EnhancedSR,
Expand All @@ -32,6 +33,7 @@
AlgorithmIdentification,
DeviceObserverIdentifyingAttributes,
ImageLibrary,
ImageLibraryEntryDescriptors,
LanguageOfContentItemAndDescendants,
Measurement,
MeasurementProperties,
Expand All @@ -44,6 +46,7 @@
ObservationContext,
PersonObserverIdentifyingAttributes,
PlanarROIMeasurementsAndQualitativeEvaluations,
QualitativeEvaluation,
SubjectContext,
SubjectContextDevice,
SubjectContextFetus,
Expand Down Expand Up @@ -108,6 +111,7 @@
'GraphicTypeValues3D',
'ImageContentItem',
'ImageLibrary',
'ImageLibraryEntryDescriptors',
'ImageRegion',
'ImageRegion3D',
'LanguageOfContentItemAndDescendants',
Expand All @@ -124,6 +128,7 @@
'ObservationContext',
'PersonObserverIdentifyingAttributes',
'PlanarROIMeasurementsAndQualitativeEvaluations',
'PlanarROITypes',
'PixelOriginInterpretationValues',
'PnameContentItem',
'QualitativeEvaluation',
Expand Down Expand Up @@ -152,4 +157,5 @@
'ValueTypeValues',
'VolumeSurface',
'VolumetricROIMeasurementsAndQualitativeEvaluations',
'VolumetricROITypes',
]
43 changes: 43 additions & 0 deletions src/highdicom/sr/coding.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ def __init__(
self.CodingSchemeVersion = str(scheme_version)
# TODO: Enhanced Code Sequence Macro Attributes

def __hash__(self) -> int:
return hash(self.scheme_designator + self.value)

def __eq__(self, other: Any) -> bool:
"""Compares `self` and `other` for equality.

Expand Down Expand Up @@ -109,3 +112,43 @@ def scheme_designator(self) -> str:
def scheme_version(self) -> str:
"""Union[str, None]: version of the coding scheme (if specified)"""
return getattr(self, 'CodingSchemeVersion', None)

@classmethod
def from_dataset(cls, dataset: Dataset) -> 'CodedConcept':
"""Construct a CodedConcept from an existing dataset.

Parameters
----------
dataset: pydicom.dataset.Dataset
Dataset representing a coded concept.

Returns
-------
highdicom.sr.coding.CodedConcept:
Coded concept representation of the dataset.

Raises
------
TypeError:
If the passed dataset is not a pydicom dataset.
AttributeError:
If the dataset does not contain the required elements for a
coded concept.

"""
if not isinstance(dataset, Dataset):
raise TypeError(
'Dataset must be a pydicom.dataset.Dataset.'
)
for kw in ['CodeValue', 'CodeMeaning', 'CodingSchemeDesignator']:
if not hasattr(dataset, kw):
raise AttributeError(
'Dataset does not contain the following attribute '
f'required for coded concepts: {kw}.'
)
return cls(
value=dataset.CodeValue,
scheme_designator=dataset.CodingSchemeDesignator,
meaning=dataset.CodeMeaning,
scheme_version=getattr(dataset, 'CodingSchemeVersion', None)
)
Loading