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

WIP: Volumetric Segmentations #277

Draft
wants to merge 101 commits into
base: v0.24.0dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
101 commits
Select commit Hold shift + click to select a range
d0aac71
Generalize multifframe database manager
CPBridge Feb 1, 2024
32703b0
Add multiframe tests
CPBridge Feb 1, 2024
4ba09b5
Automatically populate the 3D tag
CPBridge Feb 1, 2024
ec26339
Add ability to determine whether a segmentation is a volume
CPBridge Feb 2, 2024
f598555
Fix plane ordering bug; split spatial functions
CPBridge Feb 2, 2024
13e546b
Generalize multifframe database manager
CPBridge Feb 1, 2024
aea5578
Add multiframe tests
CPBridge Feb 1, 2024
9df31eb
Automatically populate the 3D tag
CPBridge Feb 1, 2024
74b412d
Add ability to determine whether a segmentation is a volume
CPBridge Feb 2, 2024
91e11ce
Fix plane ordering bug; split spatial functions
CPBridge Feb 2, 2024
0687971
Merge branch 'feature/seg_volumes' of github.com:ImagingDataCommons/h…
CPBridge Apr 12, 2024
fb199d3
Merge branch 'v0.23.0dev' into feature/seg_volumes
CPBridge May 19, 2024
a671b27
Spelling
CPBridge May 19, 2024
c0716a5
Merge branch 'v0.23.0dev' into feature/seg_volumes
CPBridge May 27, 2024
81438ad
Merge branch 'v0.23.0dev' into feature/seg_volumes
CPBridge May 27, 2024
ba83039
Fix test for multiframe
CPBridge May 27, 2024
0e9aa46
Fix test for multiframe
CPBridge May 27, 2024
e53938e
WIP implementation of VolumeGeometry
CPBridge Jun 10, 2024
0a7f6ba
Remove print statements from tests
CPBridge Jun 10, 2024
8ae1900
Add some docstrings
CPBridge Jun 15, 2024
587e1da
Merge branch 'v0.23.0dev' into feature/seg_volumes
CPBridge Jun 15, 2024
b7f6cb4
Fixes to matrix transform
CPBridge Jun 16, 2024
607b1ae
further fix
CPBridge Jun 16, 2024
adec6b3
Move volume to new file
CPBridge Jun 19, 2024
6f41a70
Add new tests
CPBridge Jun 20, 2024
e9d9fd7
Moved to VolumeArray
CPBridge Jun 27, 2024
590f829
start on affine matrix mapping
CPBridge Jul 4, 2024
d9a3fdb
Add channels
CPBridge Jul 5, 2024
379060e
Add with_array
CPBridge Jul 5, 2024
dcfdc60
Added concat_volumes
CPBridge Jul 5, 2024
cee0c80
Rename VolumeArray -> Volume
CPBridge Jul 15, 2024
c79124b
Implment volume indexing
CPBridge Jul 16, 2024
e61119e
Add get_closest patient_orientation
CPBridge Jul 16, 2024
e73f6a9
WIP on flip and permute
CPBridge Jul 16, 2024
dd01046
Add flip volume
CPBridge Jul 16, 2024
2518549
Add to_patient_orientation
CPBridge Jul 16, 2024
3b00d6d
Add ability to pass Volume to segmentation constructor
CPBridge Jul 16, 2024
c82c8bf
Change set_array to setter
CPBridge Jul 16, 2024
508b537
Add TODOs
CPBridge Jul 16, 2024
7e1ff71
Add volread
CPBridge Jul 19, 2024
0c0946e
Add ability to sort volumes with duplicate and missing positions
CPBridge Jul 28, 2024
3cd033c
Add basic reading as volume. Lots of tidy up and docs to do
CPBridge Jul 28, 2024
5c247a3
Fixes
CPBridge Jul 29, 2024
d6a534f
Add affine to Segmentation.get_volume
CPBridge Jul 29, 2024
f272123
Fix seg.get_volume affine indexing
CPBridge Jul 29, 2024
23d91c3
Add tests, some failing
CPBridge Jul 29, 2024
2c04427
Fix indexing issues
CPBridge Jul 30, 2024
960fba3
Fix multiframe tests
CPBridge Jul 31, 2024
341a149
Add intensity operations to Volume
CPBridge Jul 31, 2024
262c712
Add cropping and padding to volumes
CPBridge Aug 2, 2024
7b4e6aa
Fix intensity normalization methods
CPBridge Aug 2, 2024
7abd30c
add handed check/ensure
CPBridge Aug 3, 2024
a546466
Add some tests for volumes
CPBridge Aug 3, 2024
6efd2b8
Remove source frame information from Volume
CPBridge Aug 4, 2024
4fde694
Add random crop method
CPBridge Aug 5, 2024
e0d6c8b
WIP on pixel transformations
CPBridge Aug 9, 2024
934077b
Create new VolumeGeometry class
CPBridge Aug 10, 2024
e4aa391
Refactor multiframe to use VolumeGeometry, add VolumeGeometry.create_…
CPBridge Aug 11, 2024
241a539
Add rotation_for_patient_orientation
CPBridge Aug 11, 2024
a8cfe82
Add volume to volume transformer
CPBridge Aug 18, 2024
3aaebcd
WIP on match geometry
CPBridge Aug 18, 2024
f178ac1
Add match_geometry method, tests
CPBridge Aug 18, 2024
9c6c6f2
Fix type hint
CPBridge Aug 19, 2024
3ec987c
Small typos and better error message
CPBridge Aug 19, 2024
086a370
Implement MultiFrameImage class
CPBridge Aug 20, 2024
282e004
Add randon flip and permute
CPBridge Aug 20, 2024
1e6ce19
Add volume to docs
CPBridge Aug 20, 2024
82d79d2
Handle pickling of multiframe images
CPBridge Aug 21, 2024
c4632d0
Work in progress pixel transforms
CPBridge Sep 11, 2024
01bb579
Merge branch 'master' into feature/seg_volumes
CPBridge Sep 25, 2024
69e81c5
Merge branch 'v0.24.0dev' into feature/seg_volumes
CPBridge Oct 5, 2024
c8eda6a
Merge branch 'v0.24.0dev' into feature/seg_volumes
CPBridge Oct 5, 2024
ad63ad2
Fix serialization
CPBridge Oct 5, 2024
6b9df12
Add tests for labelmap volumes
CPBridge Oct 5, 2024
5a2bdd6
Implement generalized parsing for multiframe images
CPBridge Oct 11, 2024
2a408ad
Fixes to labelmap reading
CPBridge Oct 12, 2024
93999e8
Fixes for labelmap reading dtypes, add test cases
CPBridge Oct 13, 2024
f448936
Style fixes
CPBridge Oct 13, 2024
799e4e0
Fixes to slice thickness
CPBridge Oct 17, 2024
c72cd9f
Fix background segment description
CPBridge Oct 17, 2024
cf1969f
Fixes for volume-based segment creation
CPBridge Oct 17, 2024
ced72c1
Move to using typing_extensions.Self
CPBridge Nov 2, 2024
7321d02
Add pixel transformations to ImageFileReader
CPBridge Nov 10, 2024
e6f4e0a
Implement apply methods for voi and modaiity transforms
CPBridge Nov 23, 2024
5bc14aa
Implement apply for real world mappings
CPBridge Nov 23, 2024
4e83657
Progress on pixel transform parsing
CPBridge Nov 24, 2024
7d7c03e
Factor out pixel transform code
CPBridge Nov 24, 2024
4caa018
Add palette lut from combined array
CPBridge Nov 24, 2024
befdec2
Fixes to multiframe, add various pixel transforms
CPBridge Dec 19, 2024
4fb9881
Fix volume indexing at -1
CPBridge Dec 22, 2024
3d34cc8
Implement missing parts of pixel transforms
CPBridge Dec 22, 2024
862ab71
Fixes to transform class
CPBridge Dec 23, 2024
6cc5150
Add some tests related to combined pixel transform
CPBridge Dec 24, 2024
9909cd4
add further combined pixel transform tests
CPBridge Dec 24, 2024
7a796d3
More tests and fixes for combined pixel transform
CPBridge Dec 24, 2024
3951eac
Tests for monochrome1
CPBridge Dec 24, 2024
afd3d2c
More tests and fixes for pixel transforms
CPBridge Dec 24, 2024
a75954d
add test for rvwm with lut
CPBridge Dec 24, 2024
760bf83
Add ability to select VOI by string
CPBridge Dec 26, 2024
a26042d
Add ability to specify an external VOI transformation
CPBridge Dec 26, 2024
983cdba
Add ability to search RWVMs
CPBridge Dec 26, 2024
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 added data/test_files/seg_image_sm_control_labelmap.dcm
Binary file not shown.
Binary file not shown.
9 changes: 9 additions & 0 deletions docs/package.rst
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,15 @@ highdicom.utils module
:undoc-members:
:show-inheritance:

highdicom.volume module
+++++++++++++++++++++++

.. automodule:: highdicom.volume
:members:
:inherited-members: pydicom.dataset.Dataset,pydicom.sequence.Sequence,Dataset,Sequence,list,str,DataElementSequence,enum.Enum,Enum,
:special-members: __call__
:undoc-members:
:show-inheritance:

.. _highdicom-legacy-subpackage:

Expand Down
2 changes: 1 addition & 1 deletion docs/seg.rst
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@ segments. Note that passing a "label map" is purely a convenience provided by
(`highdicom` splits the label map into multiple single-segment frames and
stores these, as required by the standard).

Therefore, The following snippet produces an equivalent SEG image to the
Therefore, the following snippet produces an equivalent SEG image to the
previous snippet, but passes the mask as a label map rather than as a stack of
segments.

Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ dependencies = [
"pillow>=8.3",
"pydicom>=3.0.1",
"pyjpegls>=1.0.0",
"typing-extensions>=4.0.0",
]

[project.optional-dependencies]
Expand Down
7 changes: 7 additions & 0 deletions src/highdicom/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,13 @@
VOILUTTransformation,
)
from highdicom.enum import (
AxisHandedness,
AnatomicalOrientationTypeValues,
CoordinateSystemNames,
ContentQualificationValues,
DimensionOrganizationTypeValues,
LateralityValues,
PadModes,
PatientSexValues,
PhotometricInterpretationValues,
PixelRepresentationValues,
Expand All @@ -56,13 +58,16 @@
from highdicom.uid import UID
from highdicom import utils
from highdicom.version import __version__
from highdicom import volume


__all__ = [
'LUT',
'UID',
'VOILUT',
'AlgorithmIdentificationSequence',
'AnatomicalOrientationTypeValues',
'AxisHandedness',
'ContentCreatorIdentificationCodeSequence',
'ContentQualificationValues',
'CoordinateSystemNames',
Expand All @@ -71,6 +76,7 @@
'LateralityValues',
'ModalityLUT',
'ModalityLUTTransformation',
'PadModes',
'PaletteColorLUT',
'PaletteColorLUTTransformation',
'PatientOrientationValuesBiped',
Expand Down Expand Up @@ -112,4 +118,5 @@
'spatial',
'sr',
'utils',
'volume',
]
21 changes: 19 additions & 2 deletions src/highdicom/_module_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,11 @@ def get_module_usage(
return None


def is_attribute_in_iod(attribute: str, sop_class_uid: str) -> bool:
def is_attribute_in_iod(
attribute: str,
sop_class_uid: str,
exclude_path_elements: Sequence[str] | None = None,
) -> bool:
"""Check whether an attribute is present within an IOD.

Parameters
Expand All @@ -225,6 +229,9 @@ def is_attribute_in_iod(attribute: str, sop_class_uid: str) -> bool:
Keyword for the attribute
sop_class_uid: str
SOP Class UID identifying the IOD.
exclude_path_elements: Sequence[str] | None, optional
If any of these elements are found anywhere in the attribute's path,
that occurrence is excluded.

Returns
-------
Expand All @@ -247,6 +254,11 @@ def is_attribute_in_iod(attribute: str, sop_class_uid: str) -> bool:
for module in IOD_MODULE_MAP[iod_name]:
module_attributes = MODULE_ATTRIBUTE_MAP[module['key']]
for attr in module_attributes:
if exclude_path_elements is not None:
if any(
p in exclude_path_elements for p in attr['path']
):
continue
if attr['keyword'] == attribute:
return True

Expand Down Expand Up @@ -279,12 +291,17 @@ def does_iod_have_pixel_data(sop_class_uid: str) -> bool:
'DoubleFloatPixelData',
]
return any(
is_attribute_in_iod(attr, sop_class_uid) for attr in pixel_attrs
is_attribute_in_iod(
attr,
sop_class_uid,
exclude_path_elements=['IconImageSequence'],
) for attr in pixel_attrs
)


def is_multiframe_image(dataset: Dataset):
"""Determine whether an image is a multiframe image.

The definition used is whether the IOD allows for multiple frames, not
whether this particular instance has more than one frame.

Expand Down
9 changes: 5 additions & 4 deletions src/highdicom/ann/content.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Content that is specific to Annotation IODs."""
from copy import deepcopy
from typing import cast, List, Optional, Sequence, Tuple, Union
from typing_extensions import Self

import numpy as np
from pydicom.dataset import Dataset
Expand Down Expand Up @@ -119,7 +120,7 @@ def from_dataset(
cls,
dataset: Dataset,
copy: bool = True
) -> 'Measurements':
) -> Self:
"""Construct instance from an existing dataset.

Parameters
Expand Down Expand Up @@ -165,7 +166,7 @@ def from_dataset(
)
]

return cast(Measurements, measurements)
return cast(cls, measurements)


class AnnotationGroup(Dataset):
Expand Down Expand Up @@ -770,7 +771,7 @@ def from_dataset(
cls,
dataset: Dataset,
copy: bool = True,
) -> 'AnnotationGroup':
) -> Self:
"""Construct instance from an existing dataset.

Parameters
Expand Down Expand Up @@ -838,4 +839,4 @@ def from_dataset(
for ds in group.PrimaryAnatomicStructureSequence
]

return cast(AnnotationGroup, group)
return cast(cls, group)
7 changes: 4 additions & 3 deletions src/highdicom/ann/sop.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
Tuple,
Union,
)
from typing_extensions import Self

import numpy as np
from pydicom import dcmread
Expand Down Expand Up @@ -418,7 +419,7 @@ def from_dataset(
cls,
dataset: Dataset,
copy: bool = True,
) -> 'MicroscopyBulkSimpleAnnotations':
) -> Self:
"""Construct instance from an existing dataset.

Parameters
Expand Down Expand Up @@ -450,14 +451,14 @@ def from_dataset(
ann = deepcopy(dataset)
else:
ann = dataset
ann.__class__ = MicroscopyBulkSimpleAnnotations
ann.__class__ = cls

ann.AnnotationGroupSequence = [
AnnotationGroup.from_dataset(item, copy=copy)
for item in ann.AnnotationGroupSequence
]

return cast(MicroscopyBulkSimpleAnnotations, ann)
return cast(cls, ann)


def annread(
Expand Down
Loading
Loading