Skip to content

open-dicom/csa_header

CSA Header

Parse CSA header information from Siemens MRI acquisitions with Python.

Package & Distribution

PyPI - Version PyPI - Python Version PyPI - Downloads

Build & Quality Assurance

Tests codecov pre-commit.ci status

Code Quality & Style

Code style: black Mypy checked

Citation & License

DOI License: MIT


Some Siemens MRI scans may include CSA headers that provide valuable information about the acquisition and storage of the data. These headers are stored as private data elements, usually looking something like:

(0029, 1010) CSA Image Header Type          OB: 'IMAGE NUM 4'
(0029, 1010) CSA Image Header Version       OB: '20100114'
(0029, 1010) CSA Image Header Info          OB: Array of 11560 bytes
(0029, 1020) CSA Series Header Type         OB: 'MR'
(0029, 1020) CSA Series Header Version      OB: '20100114'
(0029, 1020) CSA Series Header Info         OB: Array of 80248 bytes

The CSA Image Header Info and CSA Series Header Info elements contain encoded information which is crucial for the correct interpretation of the associated acquisition data.

For a detailed explanation on the CSA encoding scheme, please see this excellent article from NiBabel's documentation site.

Features

  • Fast and Lightweight: Minimal dependencies (numpy, pydicom)
  • Comprehensive Parsing: Supports both CSA header types (Type 1 and Type 2)
  • ASCCONV Support: Automatic parsing of embedded ASCCONV protocol parameters
  • Type-Safe: Complete type hints for all public APIs
  • Well-Tested: 96% test coverage with 161 tests
  • Python 3.9+: Modern Python with support through Python 3.13
  • NiBabel Compatible: Integrates seamlessly with neuroimaging workflows

Table of Contents

Installation

pip install csa_header

Optional Dependencies

For working with the provided examples and automatic example data downloading:

pip install csa_header[examples]

This installs:

  • nibabel for NiBabel integration examples
  • pooch for automatic downloading of example DICOM files

For development (includes pre-commit hooks and IPython):

pip install csa_header[dev]

Quickstart

Option 1: Using Example Data (Easiest!)

The quickest way to get started is using the built-in example data:

>>> # Install with examples support
>>> # pip install csa_header[examples]
>>>
>>> from csa_header.examples import fetch_example_dicom
>>> from csa_header import CsaHeader
>>> import pydicom
>>>
>>> # Fetch example DICOM (downloads once, then cached)
>>> dicom_path = fetch_example_dicom()
>>> dcm = pydicom.dcmread(dicom_path)
>>>
>>> # Parse CSA Series Header
>>> raw_csa = dcm[(0x29, 0x1020)].value
>>> parsed_csa = CsaHeader(raw_csa).read()
>>> len(parsed_csa)
79

The example file is an anonymized Siemens MPRAGE scan hosted on Zenodo: DOI

Option 2: Using Your Own DICOM Files

Use pydicom to read a DICOM header:

>>> import pydicom
>>> dcm = pydicom.dcmread("/path/to/file.dcm")

Extract a data element containing a CSA header, e.g., for CSA Series Header Info:

>>> data_element = dcm.get((0x29, 0x1020))
>>> data_element
(0029, 1020) [CSA Series Header Info]            OB: Array of 180076 elements

Read the raw byte array from the data element:

>>> raw_csa = data_element.value
>>> raw_csa
b'SV10\x04\x03\x02\x01O\x00\x00\x00M\x00\x00\x00UsedPatientWeight\x00      <Visible> "true" \n      \n      <ParamStr\x01\x00\x00\x00IS\x00\x00\x06...'

Parse the contents of the CSA header with the CsaHeader class:

>>> from csa_header import CsaHeader
>>> parsed_csa = CsaHeader(raw_csa).read()
>>> parsed_csa
{
    'NumberOfPrescans': {'index': 1, 'VR': 'IS', 'VM': 1, 'value': 0},
    'TransmitterCalibration': {'index': 2, 'VR': 'DS', 'VM': 1, 'value': 247.102},
    'PhaseGradientAmplitude': {'index': 3, 'VR': 'DS', 'VM': 1, 'value': 0.0},
    'ReadoutGradientAmplitude': {'index': 4, 'VR': 'DS', 'VM': 1, 'value': 0.0},
    'SelectionGradientAmplitude': {'index': 5, 'VR': 'DS', 'VM': 1, 'value': 0.0},
    'GradientDelayTime': {'index': 6,
    'VR': 'DS',
    'VM': 3,
    'value': [36.0, 35.0, 31.0]},
    'RfWatchdogMask': {'index': 7, 'VR': 'IS', 'VM': 1, 'value': 0},
    'RfPowerErrorIndicator': {'index': 8, 'VR': 'DS', 'VM': 1, 'value': None},
    'SarWholeBody': {'index': 9, 'VR': 'DS', 'VM': 3, 'value': None},
    'Sed': {'index': 10,
    'VR': 'DS',
    'VM': 3,
    'value': [1000000.0, 324.74800987, 324.74800832]}
    ...
}

Advanced Usage

Extracting ASCCONV Protocol

CSA headers often contain the complete scanner protocol in ASCCONV format under the MrPhoenixProtocol tag. This is automatically parsed into a nested dictionary:

>>> parsed_csa = CsaHeader(raw_csa).read()
>>> protocol = parsed_csa.get('MrPhoenixProtocol')
>>> if protocol:
...     # Access protocol parameters
...     tr = protocol['alTR'][0]  # Repetition time
...     te = protocol['alTE'][0]  # Echo time
...     print(f"TR: {tr} ms, TE: {te} ms")
TR: 2000 ms, TE: 30 ms

Diffusion MRI (DWI) Parameters

Extract diffusion-specific parameters for DTI/DWI analysis:

>>> # From image header (0x0029, 0x1020)
>>> image_header = CsaHeader(dcm[0x0029, 0x1020].value).read()
>>> b_value = image_header.get('B_value')
>>> gradient = image_header.get('DiffusionGradientDirection')
>>> print(f"B-value: {b_value}, Gradient: {gradient}")
B-value: 1000, Gradient: [0.707, 0.707, 0.0]

Functional MRI (fMRI) Parameters

Extract slice timing for slice timing correction:

>>> # From series header (0x0029, 0x1010)
>>> series_header = CsaHeader(dcm[0x0029, 0x1010].value).read()
>>> slice_times = series_header.get('MosaicRefAcqTimes')
>>> n_slices = series_header.get('NumberOfImagesInMosaic')
>>> print(f"Slice times: {slice_times[:3]}... ({n_slices} slices)")
Slice times: [0.0, 52.5, 105.0]... (64 slices)

Integration with NiBabel

csa_header works seamlessly with NiBabel for comprehensive neuroimaging workflows:

import nibabel as nib
import pydicom
from csa_header import CsaHeader

# Load DICOM with both pydicom and NiBabel
dcm = pydicom.dcmread('scan.dcm')
nib_img = nib.load('scan.dcm')

# Extract CSA header information
if (0x0029, 0x1010) in dcm:
    csa = CsaHeader(dcm[0x0029, 0x1010].value)
    csa_info = csa.read()

    # Use NiBabel for image data
    data = nib_img.get_fdata()

    # Use CSA for metadata
    slice_times = csa_info.get('MosaicRefAcqTimes', [])

    print(f"Image shape: {data.shape}")
    print(f"Slice timing from CSA: {len(slice_times)} time points")

Use Cases with NiBabel

  • Slice Timing Correction: Extract MosaicRefAcqTimes for accurate fMRI preprocessing
  • Diffusion Imaging: Get b-values and gradient directions for DTI analysis
  • Protocol Verification: Confirm acquisition parameters match expected values
  • Quality Assurance: Extract technical parameters for QA pipelines
  • BIDS Conversion: Generate complete metadata for BIDS-compliant datasets

See examples/nibabel_integration.py for complete integration examples.

Examples

The examples/ directory contains comprehensive usage examples:

  • basic_usage_example.py: Beginner-friendly introduction using example data

    • Automatic download of example DICOM files
    • Basic CSA header parsing
    • Accessing specific CSA tags
    • Perfect for first-time users!
  • nibabel_integration.py: Complete workflow combining csa_header with NiBabel

    • Extract DWI parameters (b-values, gradients)
    • Extract fMRI parameters (slice timing, TR/TE)
    • Parse ASCCONV protocol parameters
    • Batch processing multiple DICOM files

Run examples:

# Basic example with automatic data download
python examples/basic_usage_example.py

# NiBabel integration with your own DICOM
python examples/nibabel_integration.py path/to/siemens_dicom.dcm

Tests

This package uses hatch to manage development and packaging. To run the tests, simply run:

hatch run test

Coverage

To run the tests with coverage, run:

hatch run cov

Or, to automatically generate an HTML report and open it in your default browser:

hatch run cov-show

Contributing

Contributions are welcome! This project is community-maintained and aims to be a reliable tool for the medical imaging community.

How to Contribute

  1. Report Issues: Found a bug or have a feature request? Open an issue
  2. Submit Pull Requests: See CONTRIBUTING.md for detailed guidelines
  3. Improve Documentation: Help make the docs better
  4. Share Examples: Contribute integration examples or use cases

Development Setup

# Clone the repository
git clone https://github.com/open-dicom/csa_header.git
cd csa_header

# Install hatch
pip install hatch

# Run tests
hatch run test:test

# Run linting
hatch run lint:all

# Install pre-commit hooks
hatch run pre-commit install

See CONTRIBUTING.md for complete development guidelines including:

  • Code style requirements
  • Testing requirements (90%+ coverage)
  • Commit message conventions
  • Pull request process

Citation

If you use csa_header in your research, please cite it using the following:

BibTeX:

@software{baratz_2025_csa_header,
  author       = {Baratz, Zvi and Brett, Matthew},
  title        = {csa_header: Parse CSA header information from Siemens MRI acquisitions},
  year         = 2025,
  publisher    = {Zenodo},
  version      = {v1.0.2},
  doi          = {10.5281/zenodo.17474448},
  url          = {https://doi.org/10.5281/zenodo.17474448}
}

APA:

Baratz, Z., & Brett, M. (2025). csa_header: Parse CSA header information from Siemens MRI acquisitions (v1.0.2). Zenodo. https://doi.org/10.5281/zenodo.17474448

For the specific version you're using, please check the Zenodo record for the appropriate DOI and citation information.

Alternatively, you can use the CITATION.cff file in this repository, which is automatically recognized by GitHub and can be imported into reference managers.

License

csa_header is distributed under the terms of the MIT license.

About

Parse Siemens CSA header information

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •  

Languages