Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
139 commits
Select commit Hold shift + click to select a range
16019a0
newly designed multi-frame conversion based on pixelmed
afshinmessiah Jun 25, 2020
6f62073
mend
afshinmessiah Jun 30, 2020
5af4d97
Flake8 verified code
afshinmessiah Jul 1, 2020
a05e189
Verified by mypy and flake8. Added stack module adder
afshinmessiah Jul 9, 2020
408cdde
mend
afshinmessiah Jul 9, 2020
2444cc5
mend
afshinmessiah Jul 9, 2020
09467ce
mend
afshinmessiah Jul 9, 2020
8f92d68
mend
afshinmessiah Jul 9, 2020
69b1892
Added frameset collection class
afshinmessiah Jul 14, 2020
55ebc0a
mend
afshinmessiah Jul 15, 2020
716c581
mend
afshinmessiah Aug 13, 2020
505d272
Debugged for exception on string conversion to DA, DT, TM
afshinmessiah Aug 27, 2020
cd9e8c5
mend
afshinmessiah Aug 27, 2020
c3f27d6
mend
afshinmessiah Sep 1, 2020
17d39e6
Fixed issues related to Marcus minor comments
afshinmessiah Sep 8, 2020
531b3ce
mend
afshinmessiah Sep 8, 2020
79f0194
mend
afshinmessiah Oct 4, 2020
918b842
mend
afshinmessiah Oct 4, 2020
942d6fc
mend
afshinmessiah Oct 4, 2020
4c8da89
added logger for conversion
afshinmessiah Oct 12, 2020
477f614
mend
afshinmessiah Oct 24, 2020
4a7c906
Modified the way frameanatomysequence was added
afshinmessiah Oct 28, 2020
4f17d11
mend
afshinmessiah Nov 8, 2020
7e2aa9c
mend
afshinmessiah Nov 8, 2020
a179f71
mend
afshinmessiah Nov 9, 2020
5b0bdba
mend
afshinmessiah Nov 9, 2020
32e9983
Image/Frame-Type bug was fixed
afshinmessiah Feb 9, 2021
fb8cc9b
Merge branch 'master' into dev_pixelmed_converstion_00
afshinmessiah Mar 30, 2021
aafa65c
changed the class structures for sop
afshinmessiah Apr 2, 2021
ac45b5e
modified the code to apply all major comments
afshinmessiah Apr 2, 2021
3277b49
mend
afshinmessiah Apr 2, 2021
5c1687c
mend
afshinmessiah Apr 2, 2021
fe51ca2
Added tests to dicom legacy converter
afshinmessiah Apr 4, 2021
b6559c3
mend
afshinmessiah Apr 4, 2021
7f7df4a
Modified code based on Markus's comments
afshinmessiah Apr 11, 2021
a6551fb
Modified code based on Markus's comments
afshinmessiah Apr 11, 2021
c417da5
finished applying Markus's comments
afshinmessiah Apr 12, 2021
831e3da
Finished applying Markus/Andrey's commnets
afshinmessiah Apr 15, 2021
9850125
modified commnets for 3rd round
afshinmessiah Apr 27, 2021
6455b85
Applied Chris's comments
afshinmessiah May 9, 2021
9326b97
Merge branch 'master' into dev_pixelmed_converstion_00
afshinmessiah May 9, 2021
64190d7
Swapped voctors in normal calculation
afshinmessiah May 9, 2021
ee44fd1
Corrected how the normal vector was calculated
afshinmessiah May 10, 2021
6c6fbe0
Moved FrameSet, FrameSetCollection and _DicomHelper classes into high…
afshinmessiah May 12, 2021
6382dec
mend
afshinmessiah May 12, 2021
796dc5d
made both FrameSet and FrameSetCollection classes private
afshinmessiah May 12, 2021
55fec52
applied Chris's comments for the 2nd round
afshinmessiah May 14, 2021
a601fda
Rebase and basic tidy-up
CPBridge Jul 6, 2025
dfd5618
Further tidy up
CPBridge Jul 6, 2025
c9188a0
Flake8 fixes
CPBridge Jul 6, 2025
d42af41
Refactor modality-specific components to modality-specific subclasses
CPBridge Jul 7, 2025
1086d96
Minor refactor
CPBridge Jul 7, 2025
e0afcaf
refactor all lines ending in backslash
CPBridge Jul 7, 2025
b691188
wip
CPBridge Sep 12, 2025
ae39d02
Rename methods for clarity
CPBridge Jan 15, 2026
fc6f44c
Merge branch 'master' into legacy_conversion_revamp
CPBridge Jan 20, 2026
02ba5c0
Rebase on Image class, implement pixel data transcoding
CPBridge Jan 21, 2026
14a324a
Merge branch 'v0.28.0dev' into legacy_conversion_revamp
CPBridge Jan 23, 2026
be2c57d
Major refactor of legacy conversion
CPBridge Mar 17, 2026
c271109
Merge branch 'v0.28.0dev' into legacy_conversion_revamp
CPBridge Mar 17, 2026
61b23ae
Improvements using validator
CPBridge Mar 17, 2026
271262c
Implement BodyPartExamined -> AnatomicRegionSequence mapping
CPBridge Mar 19, 2026
eb86f2a
Fix standard JSON file packaging
CPBridge Mar 19, 2026
e12cab2
Refactor handling of Enhanced X Image modules
CPBridge Mar 19, 2026
9a5963f
Skip optional modules if not all attributes have values
CPBridge Mar 20, 2026
62c644f
Refactor to remove configs
CPBridge Mar 20, 2026
9e96572
Correct handling of private attributes
CPBridge Mar 20, 2026
74a7d9d
Improve functional group inclusion logic
CPBridge Mar 20, 2026
e17288e
Factor out common docstring
CPBridge Mar 20, 2026
d396b1f
Improve error messages
CPBridge Mar 20, 2026
101a5e8
Minor docstring improvements
CPBridge Mar 20, 2026
48cae06
Add logic to determine when to include frame anatomy information
CPBridge Mar 26, 2026
46e153c
Add min/max pixel values
CPBridge Mar 26, 2026
c7545c3
Remove unused import
CPBridge Mar 26, 2026
93e7d28
Refactor copy pixels method
CPBridge Mar 26, 2026
f3917cf
Add checks on functional groups
CPBridge Mar 27, 2026
4efedf4
Further tests and refactor to rmove test classes
CPBridge Mar 27, 2026
431b671
Lint fixes
CPBridge Mar 27, 2026
6324783
Further tests
CPBridge Mar 27, 2026
565d41f
Add missing keywork marks
Mar 28, 2026
6fc35d5
Fix for aggregating ImageType, with test
CPBridge Mar 30, 2026
b3289a9
Fix for aggregating ImageType, with test
CPBridge Mar 30, 2026
92e4430
Further tests and fix for inconsistent type 2 attribute
CPBridge Mar 30, 2026
bf066bd
Linting
CPBridge Mar 30, 2026
51ad7b5
Set photometric interpretation based on transfer syntax
CPBridge Apr 1, 2026
b85c171
Add common instance reference module
Apr 2, 2026
a0835e7
Add tests for color transcoding
Apr 5, 2026
21b3b3e
Add tests for from_datasets
Apr 5, 2026
a8a45e6
Consolidate legacy classes, improve from_dataset
Apr 5, 2026
89e8fa5
Add read functions
Apr 5, 2026
60988b0
Fix specific character set
Apr 5, 2026
0af9e6e
Add check for regularly volume
Apr 5, 2026
a6337b3
Add default series description
Apr 5, 2026
be3dd5e
Improve handling of lossy image compression attributes
Apr 6, 2026
ecabdb0
Move all standard data from python to JSON files
CPBridge Apr 7, 2026
2f8eee2
Adjust _module_utils imports
CPBridge Apr 7, 2026
3d63b33
Remove outdated flake8 exclusion
CPBridge Apr 7, 2026
dea3ad3
Small bug fixes
CPBridge Apr 7, 2026
c6e5075
Further exclusions
CPBridge Apr 7, 2026
228bc86
Further minor fixes
CPBridge Apr 7, 2026
3c6dbb8
Merge branch 'master' into legacy_conversion_revamp
CPBridge Apr 8, 2026
45693e9
Add docs and quickstart page
CPBridge Apr 8, 2026
adf3567
Minor docs typo
CPBridge Apr 8, 2026
fc15ea0
Fix for re-encapsulating compressed pixel data
CPBridge Apr 9, 2026
f18d6c3
Merge branch 'v0.28.0dev' into legacy_conversion_revamp
CPBridge Apr 9, 2026
3e6bc6d
Add tests for decompressing to native transfer syntax
CPBridge Apr 9, 2026
2398bf6
mypy fixes for legacy module
CPBridge Apr 9, 2026
6b4e409
Remove sort_key parameter in favour of boolean sort option
Apr 14, 2026
07b7c1c
Docstring improvements
Apr 14, 2026
a153ad6
Improvements to legacy doc page
Apr 14, 2026
e352f30
remove print statement
CPBridge Apr 14, 2026
27edad9
Further exceptions
CPBridge Apr 23, 2026
3267e4d
Add robustness to empty dates and times
CPBridge Apr 30, 2026
0683bd7
Fix empty frame laterality
CPBridge Apr 30, 2026
5a6e650
Fix timezone related errors
CPBridge Apr 30, 2026
1c5e1c8
Work around ambiguous VR issues in source files
CPBridge Apr 30, 2026
f4f69b1
Add conversion of big endian to little endian
CPBridge May 1, 2026
4aceb40
Add option to skip private attributes
CPBridge May 1, 2026
65baa76
Add strict parameter
CPBridge May 1, 2026
96560b4
Various bug fixes
CPBridge May 1, 2026
9509459
Fix photometric interpretation
CPBridge May 1, 2026
b4e1316
Add anatomical structure pairing info
CPBridge May 29, 2026
c92774a
Handle unrecognized body part examined
CPBridge May 29, 2026
3db8fcb
Issue warning for missing frame laterality
CPBridge May 29, 2026
0f9a145
Move arguments to keyword only
Jun 7, 2026
76e145f
Implement monochrome 1 conversion
CPBridge Jun 12, 2026
948a4e4
Handle missing ImageType
CPBridge Jun 12, 2026
f0df08d
Fix _AttributeConfig docstrings
CPBridge Jun 12, 2026
bb4fe91
Add dimension indexing
CPBridge Jun 12, 2026
27097c1
Update docs on legacy sorting
CPBridge Jun 12, 2026
e61d953
Fixes to legacy docs
CPBridge Jun 12, 2026
234d2a8
Add note about future rearrangement of attributes
CPBridge Jun 12, 2026
b542032
Add single lceread function
CPBridge Jun 12, 2026
7ed4275
minor doc typos
CPBridge Jun 17, 2026
96de88f
Further docstring improvements
CPBridge Jun 17, 2026
f11a7a8
Fix limitation on different modality rescales per instance
CPBridge Jun 17, 2026
c266d91
Fix for largest/smallest pixel value
CPBridge Jun 18, 2026
84f40ee
Fix for incosistent presence of reference image sequence
CPBridge Jun 18, 2026
3f4532f
Fix spatial sorting
CPBridge Jun 25, 2026
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
2 changes: 1 addition & 1 deletion .github/workflows/run_unit_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ jobs:
pip install ${{ matrix.dependencies }}
- name: Lint with flake8
run: |
flake8 --exclude='bin,build,.eggs,src/highdicom/_*'
flake8 --exclude='bin,build,.eggs'
- name: Test with pytest
run: |
pytest --cov=highdicom --cov-fail-under=80
Expand Down
56 changes: 17 additions & 39 deletions bin/create_iods_modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@
logger = logging.getLogger(__name__)


PGK_PATH = os.path.join(
PKG_JSON_PATH = os.path.join(
os.path.dirname(__file__),
'..',
'src',
'highdicom'
'highdicom',
'_standard',
)


Expand All @@ -25,10 +26,6 @@ def _load_json_from_file(filename):
return json.load(f)


def _dump_json(data):
return json.dumps(data, indent=4, sort_keys=True)


def _create_sop_to_iods(directory):
filename = os.path.join(directory, 'sops.json')
sops = _load_json_from_file(filename)
Expand Down Expand Up @@ -97,14 +94,16 @@ def _create_modules(directory):
return modules


if __name__ == '__main__':

if __name__ == "__main__":
logging.basicConfig()
logger.setLevel(logging.DEBUG)

# Positional argument is path to directory containing JSON files generated
# using the dicom-standard Python package, see
# https://github.com/innolitics/dicom-standard/tree/master/standard
# If generating yourself using the instructions in that repo, be sure to
# use "make all" instead of just "make", otherwise some of the required
# files are skipped
try:
directory = sys.argv[1]
except IndexError as e:
Expand All @@ -119,37 +118,16 @@ def _create_modules(directory):
current_time = datetime.datetime.time(now).strftime('%H:%M:%S')

iods = _create_iods(directory)
iods_docstr = '\n'.join([
'"""DICOM Information Object Definitions (IODs)',
f'auto-generated on {current_date} at {current_time}.',
'"""',
'from typing import Dict, List'
])
iods_filename = os.path.join(PKG_JSON_PATH, 'iods.json')
with open(iods_filename, 'w') as jf:
json.dump(iods, jf, indent=2)

sop_to_iods = _create_sop_to_iods(directory)
iods_filename = os.path.join(PGK_PATH, '_iods.py')
with open(iods_filename, 'w') as fp:
fp.write(iods_docstr)
fp.write('\n\n')
iods_formatted = _dump_json(iods).replace('null', 'None')
fp.write(
f'IOD_MODULE_MAP: Dict[str, List[Dict[str, str]]] = {iods_formatted}'
)
fp.write('\n\n')
sop_to_iods_formatted = _dump_json(sop_to_iods).replace('null', 'None')
fp.write(f'SOP_CLASS_UID_IOD_KEY_MAP = {sop_to_iods_formatted}')
sop_to_iods_filename = os.path.join(PKG_JSON_PATH, 'sop_class_to_iod.json')
with open(sop_to_iods_filename, 'w') as jf:
json.dump(sop_to_iods, jf, indent=2)

modules = _create_modules(directory)
modules_docstr = '\n'.join([
'"""DICOM modules'
f'auto-generated on {current_date} at {current_time}.'
'"""',
'from typing import Dict, List, Sequence, Union'
])
modules_filename = os.path.join(PGK_PATH, '_modules.py')
with open(modules_filename, 'w') as fp:
fp.write(modules_docstr)
fp.write('\n\n')
modules_formatted = _dump_json(modules).replace('null', 'None')
fp.write(
f'MODULE_ATTRIBUTE_MAP: Dict[str, List[Dict[str, Union[str, Sequence[str]]]]] = {modules_formatted}' # noqa: E501
)
modules_filename = os.path.join(PKG_JSON_PATH, 'modules.json')
with open(modules_filename, 'w') as jf:
json.dump(modules, jf, indent=2)
227 changes: 226 additions & 1 deletion docs/legacy.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,229 @@
Legacy Converted Enhanced Images
================================

This page is under construction, and more detail will be added soon.
Many medical images, including CT, MRI, and PET, consist of sets of 2D frames.
When the DICOM standard was originally developed, such series were typically
stored with each individual 2D frame in a separate DICOM instance (and
therefore a separate DICOM file) to reduce file size. Many users will be
familiar with MRI, PET, and CT images stored in this way using the CT Image
("1.2.840.10008.5.1.4.1.1.2"), MR Image ("1.2.840.10008.5.1.4.1.1.4"), and
Positron Emission Tomography Image ("1.2.840.10008.5.1.4.1.1.128") SOP Classes,
often with tens or hundreds of separate files needed to store a single series.

More recently, new additions to the standard prefer a "multiframe" arrangement
where multiple 2D images are stored as individual frames within a single DICOM
instance. Newer modalities, such as optical coherence tomography, whole slide
microscopy images, or digital breast tomosynthesis (DBT) images, were
implemented using these "multiframe" formats from the outset. Furthermore,
"enhanced" multiframe versions of the older modalities (PET, CT, MRI) were also
defined to allow storage of these modalities in a multiframe format, leading to
the Enhanced PET Image, Enhanced CT Image, and Enhanced MR Image SOP Classes.
However, adoption of these Enhanced SOP Classes by manufacturers for
established modalities has been slow: most PET, CT, and MR images you see still
use the original "legacy" SOP Classes.

Because the multiframe formats are generally easier to store and work with, a
common requirement is to convert old legacy (single-frame) series of images to
the corresponding new multiframe/enhanced format. Unfortunately, this is not
typically possible. The new enhanced formats made a number of other changes in
addition to the number of frames in an instance, and there is not usually
enough information in the legacy instances to populate all the required
attributes correctly.

To get around this problem, a further set of "Legacy Converted Enhanced" SOP
Classes was created. These share many characteristics with the new Enhanced
images, but are designed such that it is possible to convert existing legacy
series to them. They also provide a mechanism to explicitly encode references
to the original source images.

Highdicom provides Python classes for these legacy converted enhanced images,
enabling their construction from existing legacy (single-frame) instances:

- :class:`highdicom.legacy.LegacyConvertedEnhancedMRImage` for MR images stored
in the legacy "MR Image Storage" SOP Class.
- :class:`highdicom.legacy.LegacyConvertedEnhancedCTImage` for CT images stored
in the legacy "CT Image Storage" SOPClass.
- :class:`highdicom.legacy.LegacyConvertedEnhancedPETImage` for PET images
stored in the legacy "Positron Emission Tomography" SOPClass.


Basic Conversion
----------------

Basic conversion of legacy to enhanced format is very straightforward. You just
pass the legacy instances as a list (order is unimportant using the default
parameters) and specify UIDs, an instance number, and a series number for the
new instance. Generally it is recommended to choose a series description too,
but if you don't, the original series description of the legacy series will be
used with "(enhanced conversion)" added as a suffix unless adding that suffix
would go beyond the character limit for series descriptions (64 characters).


.. code-block:: python

import highdicom as hd
from pydicom import dcmread
from pydicom.data import get_testdata_file


# Use this series of files from the pydicom test data
legacy_ct_files = [
get_testdata_file('dicomdirtests/77654033/CT2/17136'),
get_testdata_file('dicomdirtests/77654033/CT2/17196'),
get_testdata_file('dicomdirtests/77654033/CT2/17166'),
]

# Read in the files
ct_series = [dcmread(f) for f in legacy_ct_files]

# Use the class constructor to perform the conversion
multiframe = hd.legacy.LegacyConvertedEnhancedCTImage(
ct_series,
series_number=1,
instance_number=1,
series_instance_uid=hd.UID(),
sop_instance_uid=hd.UID(),
series_description="Enhanced Test Files",
)

# Save out the new multiframe conversion
multiframe.save_as("legacy_converted_ct.dcm")


Encoding, Decoding, and Transcoding
-----------------------------------

By default, the new instance will keep the transfer syntax of the legacy
datasets. If the legacy datasets are compressed, highdicom will simply re-use
the existing compressed pixel data without decoding it and combine the
compressed frames together. This is both more efficient and avoids any possible
further information loss due to re-encoding.

Alternatively, you can opt to choose a new transfer syntax for the new
instance, in which case highdicom will decode and/or (re-)encode the pixel data
(as necessary) from the legacy instances. Since this can be slow, you can
optionally specify a non-zero number of sub-processes to perform this operation
using the ``workers`` parameter. When using multiple workers, you must place
your code within a ``if __name__ == "__main__":`` guard (this is a requirement
wherever you use multiprocessing in Python).

.. code-block:: python

import highdicom as hd
from pydicom import dcmread
from pydicom.uid import RLELossless
from pydicom.data import get_testdata_file


if __name__ == "__main__":
# Use this series of files from the pydicom test data
legacy_ct_files = [
get_testdata_file('dicomdirtests/77654033/CT2/17136'),
get_testdata_file('dicomdirtests/77654033/CT2/17196'),
get_testdata_file('dicomdirtests/77654033/CT2/17166'),
]

# Read in the files
ct_series = [dcmread(f) for f in legacy_ct_files]

# Create multiframe instance using lossless RLE compression
multiframe = hd.legacy.LegacyConvertedEnhancedCTImage(
ct_series,
series_number=1,
instance_number=1,
series_instance_uid=hd.UID(),
sop_instance_uid=hd.UID(),
series_description="Enhanced Test Files",
transfer_syntax_uid=RLELossless,
workers=8, # 8 conversion sub-processes
)

# Save out the new multiframe conversion
multiframe.save_as("legacy_converted_ct.dcm")


Including Multiple Series
-------------------------

Although a Legacy Converted Enhanced image most often consists of legacy
datasets from a single series, this is not actually a limitation. In some
situations, you may wish to include images from multiple series in one
multiframe file. This is allowed if certain conditions are met, such as images
having the same size, pixel representation, photometric interpretation, etc.

Sorting Frames and Dimension Indices
------------------------------------

In multiframe objects such as Legacy Converted Enhanced images, an attribute
called the Dimension Index Sequence describes how the frames are sorted along
one or more dimensions.

Under the default behavior, highdicom attempts to choose suitable sorting
dimensions automatically based on the legacy images. The current logic is as
follows (we may generalize in the future to more complex schemes):

1. Attempt to sort frames spatially as a regularly-spaced volume. This may fail
because the spacings are not regular, orientations do not match, and/or there
are multiple frames at each image position.
2. If step 1 fails, attempt to sort by Instance Number of the legacy series,
or, if there are multiple series, by Series Number then by Instance Number
as two dimension indices.
3. If this fails (because series and/or instance numbers are missing), store
frames in the order they were passed and do not include a Dimension Index
Sequence (it is optional).

The ``include_dimension_index`` parameter allows you to control this process.
The default value is ``None`` and results in the above behavior. If instead,
you pass ``include_dimension_index=True``, an exception will be raised if steps
1 and 2 fail rather than skipping the Dimension Index Sequence. A value of
``False`` means that no attempt will be made to sort the frames, they will
simply be stored in the order you passed them. Your alternative sorting
scheme will *not* be stored in the Dimension Index Sequence (this capability
may be added in the future).

For example, to sort by ``KVP`` and then ``SliceLocation``:

.. code-block:: python

import highdicom as hd
from pydicom import dcmread
from pydicom.data import get_testdata_file


# Use this series of files from the pydicom test data
legacy_ct_files = [
get_testdata_file('dicomdirtests/77654033/CT2/17136'),
get_testdata_file('dicomdirtests/77654033/CT2/17196'),
get_testdata_file('dicomdirtests/77654033/CT2/17166'),
]

# Read in the files
ct_series = [dcmread(f) for f in legacy_ct_files]

# Sort using KVP and slice location
ct_series = sorted(
ct_series, key=lambda dcm: (dcm.KVP, dcm.SliceLocation)
)

# Create multiframe instance with custom sort key
multiframe = hd.legacy.LegacyConvertedEnhancedCTImage(
ct_series,
series_number=1,
instance_number=1,
series_instance_uid=hd.UID(),
sop_instance_uid=hd.UID(),
series_description="Enhanced Test Files",
include_dimension_index=False, # disable default sorting
)

# Save out the new multiframe conversion
multiframe.save_as("legacy_converted_ct.dcm")

Requiring Volumes
-----------------

The ``require_volume`` option allows you to specify that highdicom should only
convert series that consist of parallel, regularly-spaced frames (i.e. those
that could be used to form a :class:`highdicom.Volume`). This is optional,
Legacy Converted Enhanced images that are not volumes are still entirely valid
according to the DICOM standard.
48 changes: 43 additions & 5 deletions docs/quickstart.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1029,11 +1029,49 @@ preferred for storing annotations for clinical or research purposes.
gsps.save_as('gsps.dcm')


.. .. _creation-legacy:
.. _creation-legacy:

.. Creating Legacy Converted Enhanced Images
.. -----------------------------------------
Creating Legacy Converted Enhanced Images
-----------------------------------------

Highdicom provides the following Python classes for converting legacy
single-frame images to multi-frame Legacy Converted Enhanced images:

- :class:`highdicom.legacy.LegacyConvertedEnhancedMRImage` for MR images stored
in the legacy "MR Image Storage" SOP Class.
- :class:`highdicom.legacy.LegacyConvertedEnhancedCTImage` for CT images stored
in the legacy "CT Image Storage" SOPClass.
- :class:`highdicom.legacy.LegacyConvertedEnhancedPETImage` for PET images
stored in the legacy "Positron Emission Tomography" SOPClass.

.. .. code-block:: python
Here is a simple example using CT. See :ref:`legacy` for more detail.

.. code-block:: python

.. from highdicom.legacy.sop import LegacyConvertedEnhancedCTImage
import highdicom as hd
from pydicom import dcmread
from pydicom.data import get_testdata_file


# Use this series of files from the pydicom test data
legacy_ct_files = [
get_testdata_file('dicomdirtests/77654033/CT2/17136'),
get_testdata_file('dicomdirtests/77654033/CT2/17196'),
get_testdata_file('dicomdirtests/77654033/CT2/17166'),
]

# Read in the files
ct_series = [dcmread(f) for f in legacy_ct_files]

# Use the class constructor to perform the conversion
multiframe = hd.legacy.LegacyConvertedEnhancedCTImage(
ct_series,
series_number=1,
instance_number=1,
series_instance_uid=hd.UID(),
sop_instance_uid=hd.UID(),
series_description="Enhanced Test Files",
)

# Save out the new multiframe conversion
multiframe.save_as("legacy_converted_ct.dcm")
2 changes: 1 addition & 1 deletion docs/volume.rst
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ volume.
]
ct_series = [pydicom.dcmread(f) for f in ct_files]

vol = get_volume_from_series(ct_series)
vol = hd.get_volume_from_series(ct_series)

Array Manipulation
------------------
Expand Down
Loading
Loading