imageio.plugins.pydicom#
Read/Write single-file DICOM instances using pydicom.
Backend Library: pydicom
This plugin reads and writes DICOM files using pydicom. It operates in individual files, meaning while it supports multi-frame files natively, it does not assemble data across files in a directory.
Methods#
Note
Check the respective function for supported kwargs and detailed documentation.
|
Read pixel data from the DICOM instance. |
|
Yield decoded frames one at a time (frame-wise decode). |
|
Write an image stack to DICOM. |
|
Standardized ndimage metadata from Dataset tags (no PixelData decode). |
|
Read (non-data) DICOM tags. |
Additional methods available inside the imopen
context:
|
Add the given ndimage to the frames in this image. |
|
Set the given colormap as the image's LUT. |
|
Set a piecewise linear gradient as the image's LUT. |
Instance-level (global) metadata of the file. |
|
Metadata in the shared functional group. |
|
The pixel compression to use when writing. |
Advanced API#
In addition to the default ImageIO v3 API this plugin exposes custom functions
and attributes for writing DICOM. These are available inside the
imopen context and allow fine-grained control over
tags, functional groups, palettes, and compression. The callables are documented
above; below is a usage example:
import imageio.v3 as iio
frames = [...] # list of (rows, cols) arrays, e.g. uint16
with iio.imopen("out.dcm", "w", plugin="pydicom") as f:
# global metadata
f.instance_metadata["PatientName"] = "Anonymous"
f.instance_metadata["Modality"] = "OT"
# bit depth
f.instance_metadata["BitsStored"] = 12
# pixel compression
f.compression = "rle" # or "jpeg-ls", "jpeg2000-lossless", ...
# shared FG (written once, applied to each frame)
f.shared_frame_metadata["PixelMeasuresSequence"] = [
{"PixelSpacing": [1.0, 1.0]}
]
# write each frame
for i, frame in enumerate(frames):
f.write_frame(
frame,
# set frame-level metadata
metadata={"FrameContentSequence": [{"FrameAcquisitionNumber": i}]},
)
meta = iio.immeta("out.dcm", plugin="pydicom")
assert meta["PatientName"] == "Anonymous"
Frames are buffered until flush (close() / context exit).
Compression#
Compression is imopen-only. imwrite / write() always produce an
uncompressed Dataset; set f.compression before close to run pydicom
Dataset.compress() once at flush. Changing the value after some
write_frame calls is fine — only the value at flush matters.
Accepted values are short names (resolved to transfer syntax UIDs) or a raw UID string:
"rle"— RLE Lossless"jpeg-ls"— JPEG-LS Lossless"jpeg-ls-near"— JPEG-LS Near-Lossless"jpeg2000"— JPEG 2000"jpeg2000-lossless"— JPEG 2000 Lossless
Availability depends on pydicom’s installed encoders (RLE is built-in; others may need extra packages). Unknown names raise immediately; unsupported UIDs fail at flush.
Example:
import imageio.v3 as iio
import numpy as np
img = np.arange(64, dtype=np.uint8).reshape(8, 8)
with iio.imopen("compressed.dcm", "w", plugin="pydicom") as f:
f.compression = "rle"
f.write(img)
Palette LUTs#
The plugin offers helpers to build color palettes when writing palettized DICOM images. Supported palettes are either dense or linear:
A dense palette maps each pixel index to a color from a lookup table.
A linear palette maps each pixel index via piecewise-linear interpolation between the provided
colorsat the providedindices.
Dense color maps use the ordinary LookupTableData tags, linear maps use SegmentedLookupTableData tags. Please ensure your reader supports these. Optional alpha is supported as a 4th LUT channel. Pixel frames must be index arrays into the LUT (not already-colored RGB).
When using a LUT, do not set BitsStored in instance_metadata.
Example using a dense palette:
import imageio.v3 as iio
import numpy as np
frame = ... # (rows, cols) index array, with values 0..3
colormap = np.array(
[[0, 0, 0], [255, 0, 0], [0, 255, 0], [0, 0, 255]],
dtype=np.uint8,
)
with iio.imopen("palette_dense.dcm", "w", plugin="pydicom") as f:
f.lut_dense(colormap)
f.write(frame)
Example using a linear palette:
import imageio.v3 as iio
frame = ... # (rows, cols) index array, uint8
with iio.imopen("palette_linear.dcm", "w", plugin="pydicom") as f:
f.lut_linear(
colors=[(0, 0, 0), (65535, 65535, 65535)],
indices=[0, 255],
)
f.write(frame)
Calling either helper replaces any previous palette state and clears the other encoding’s data tags (explicit and segmented are mutually exclusive). While we offer helpers for dense and linear, you can still manually build and assign other tables directly to the respective metadata tags.
Pixel reconstruction#
By default read / iter / imread / imiter reconstruct the image.
This means any LUT (lookup table), grayscale correction, or ROI (region of
interest) windowing is applied before the image is returned.
Pass raw=True to skip that pipeline and get stored values
(pixel_array(..., raw=True)). improps / properties take the same
raw flag so reported shape and dtype match read.
Notes#
Be aware that .write() on "<bytes>" needs to flush immediately so
imwrite can return encoded bytes. This may cause surprising behavior when used
inside an explicit imopen context.