A DICOM repack plugin
5.7K
pl-dicom_repack is a ChRIS
ds plugin which takes in a list of DICOMs as input files and
creates a single DICOM as output files.
This plugin takes in a list of dicom files that belong to a particular series and are homogeneous in nature, i.e. each DICOM file must have the same shape (rows, columns, samples per pixel, bit depth and photometric interpretation) as the rest of the files in the series. The pixel data of every file is concatenated, in file-name order, into a single multiframe DICOM. The header is taken from the first file in that order.
Additionally, this plugin also modifies the "NumberOfFrames" header tag of the output DICOM with the number of frames written.
Memory use does not depend on the length of the series. Peak memory is roughly one slice plus the Python/numpy/pydicom baseline (about 65 MiB measured), whether the series has 100 or 3000 slices:
.<name>.partial name next to its
final location and renamed only when complete, so a failed run never leaves a
truncated DICOM behind.Measured on 800 slices of 512x512 16-bit (420 MB of pixel data): 863 MiB peak before, 64 MiB after, with identical pixel data.
Slices stored with a compressed transfer syntax (e.g. RLE, JPEG) are decoded and the
output is written uncompressed, as Explicit VR Little Endian. Native (uncompressed)
slices are copied byte for byte and keep their transfer syntax. If a series mixes the two,
everything is decoded. Decoding needs the codecs listed in requirements.txt.
Only grayscale RLE was tested; colour images that need a colour-space conversion
(e.g. JPEG YBR_FULL_422) are not handled specially.
| Input | Output |
|---|---|
incoming/a/b/*.dcm | outgoing/a/b.dcm |
incoming/*.dcm (files directly in the input directory) | outgoing/incoming.dcm |
A series that cannot be merged (non-uniform slices, a truncated file, a file without pixel
data, no readable files) is reported on stderr and produces no output, while other series
are still processed. The plugin then exits with status 1. An unreadable file inside an
otherwise good series is skipped with a message and is not counted as a frame.
s001.dcm, s010.dcm);
the plugin does not sort by InstanceNumber or slice position.InstanceNumber
and ImagePositionPatient describe only the first frame. No per-frame functional groups
are created.BitsAllocated = 1) is not supported.pl-dicom_repack is a ChRIS plugin, meaning it can
run from either within ChRIS or the command-line.
To get started with local command-line usage, use Apptainer
(a.k.a. Singularity) to run pl-dicom_repack as a container:
apptainer exec docker://fnndsc/pl-dicom_repack dicom_repack [--args values...] input/ output/
To print its available options, run:
apptainer exec docker://fnndsc/pl-dicom_repack dicom_repack --help
dicom_repack requires two positional arguments: a directory containing
input data, and a directory where to create output data.
First, create the input directory and move input data into it.
mkdir incoming/ outgoing/
mv some.dat other.dat incoming/
apptainer exec docker://fnndsc/pl-dicom_repack:latest dicom_repack [--args] incoming/ outgoing/
Instructions for developers.
Build a local container image:
docker build -t localhost/fnndsc/pl-dicom_repack .
Mount the source code dicom_repack.py into a container to try out changes without rebuild.
docker run --rm -it --userns=host -u $(id -u):$(id -g) \
-v $PWD/dicom_repack.py:/usr/local/lib/python3.11/site-packages/dicom_repack.py:ro \
-v $PWD/in:/incoming:ro -v $PWD/out:/outgoing:rw -w /outgoing \
localhost/fnndsc/pl-dicom_repack dicom_repack /incoming /outgoing
Run unit tests using pytest.
It's recommended to rebuild the image to ensure that sources are up-to-date.
Use the option --build-arg extras_require=dev to install extra dependencies for testing.
docker build -t localhost/fnndsc/pl-dicom_repack:dev --build-arg extras_require=dev .
docker run --rm -it -v "$PWD:/app:ro" -w /app localhost/fnndsc/pl-dicom_repack:dev \
pytest -o cache_dir=/tmp/pytest
The mount is needed because the image does not contain tests/. tests/test_repack.py
builds small synthetic series (native, big-endian, implicit VR, RLE-compressed, odd sizes)
and checks the output frame by frame, the failure handling, and that peak memory does not
grow with the number of slices.
Steps for release can be automated by Github Actions. This section is about how to do those steps manually.
Increase the version number in setup.py and commit this file.
Build and push an image tagged by the version. For example, for version 1.2.3:
docker build -t docker.io/fnndsc/pl-dicom_repack:1.2.3 .
docker push docker.io/fnndsc/pl-dicom_repack:1.2.3
Run chris_plugin_info
to produce a JSON description of this plugin, which can be uploaded to ChRIS.
docker run --rm docker.io/fnndsc/pl-dicom_repack:1.2.3 chris_plugin_info -d docker.io/fnndsc/pl-dicom_repack:1.2.3 > chris_plugin_info.json
Intructions on how to upload the plugin to ChRIS can be found here: https://chrisproject.org/docs/tutorials/upload_plugin
Content type
Image
Digest
sha256:970cb9b96…
Size
89.1 MB
Last updated
4 days ago
docker pull fnndsc/pl-dicom_repack