Skip to content

DICOM → NIfTI, BIDS & DWI

Turn a DICOM series into the files a neuroimaging or ML pipeline expects: a NIfTI volume, a BIDS JSON sidecar, and — for diffusion — an FSL gradient table.

A series → NIfTI

import pydcm

vol = pydcm.load_series("ct_series/")
vol.pixels          # [depth, rows, cols] float32 HU, spatially sorted
vol.spacing         # (z, y, x) mm
vol.affine          # 4×4 voxel→world
path = vol.to_nifti("ct.nii.gz")

The affine is validated including the gantry-tilt case (the column-2 increment follows the true Image-Position-Patient step, so tilted CT does not drift). Non-tilted series are bit-identical to the straightforward construction.

BIDS sidecar

meta = pydcm.bids_sidecar("ep2d_diff/")     # dict, standard BIDS fields
meta["PhaseEncodingDirection"]               # e.g. "j-"
meta["SliceTiming"]                          # per-slice acquisition times
meta["EffectiveEchoSpacing"], meta["TotalReadoutTime"]

Write it next to the NIfTI yourself:

import json
with open("ep2d_diff.json", "w") as f:
    json.dump(meta, f, indent=2)

Diffusion (DWI) → FSL .bval / .bvec

import glob

files = glob.glob("ep2d_diff/*.dcm")
bvals, bvecs = pydcm.diffusion_table(files, output_prefix="dwi")   # writes dwi.bval / dwi.bvec
  • rotate=True (default) rotates each gradient from the patient (LPS) frame into the image/voxel frame — the convention FSL expects relative to the NIfTI.
  • Vendor coverage is built in: Siemens CSA + mosaic, enhanced multi-frame, and the GE / Philips / UIH private encodings.

To get the 4-D diffusion volume and the table together:

dwi = pydcm.load_dwi("ep2d_diff/")          # 4-D stack grouped by (b-value, gradient)

The output feeds FSL, MRtrix or dipy directly — pydcm produces the gradient table; the downstream analysis stays in those tools.