-
Notifications
You must be signed in to change notification settings - Fork 3
Quickstart
Audience: Beginners
Estimated time: 5 minutes
Prerequisites: Basic Python knowledge, DICOM files from Siemens scanner
Extract slice timing information from a Siemens fMRI DICOM file in just a few lines of code. This is essential for fMRI preprocessing with tools like SPM, FSL, or AFNI.
pip install csa_header pydicomimport pydicom
from csa_header import CsaHeader
# 1. Load your Siemens DICOM file
dcm = pydicom.dcmread('your_fmri_scan.dcm')
# 2. Extract CSA Series Header Info tag (0x0029, 0x1010)
series_header_bytes = dcm[0x0029, 0x1010].value
# 3. Parse the CSA header binary format
csa = CsaHeader(series_header_bytes)
series_info = csa.read()
# 4. Get slice timing values
slice_times = series_info['MosaicRefAcqTimes']['value']
n_slices = series_info['NumberOfImagesInMosaic']['value']
print(f"Number of slices: {n_slices}")
print(f"Slice timing (ms): {slice_times}")Number of slices: 36
Slice timing (ms): [0.0, 52.5, 105.0, 157.5, 210.0, 262.5, 315.0, ...]
flowchart LR
A[DICOM File] -->|pydicom.dcmread| B[DICOM Dataset]
B -->|Extract tag 0x0029,0x1010| C[Raw Bytes]
C -->|CsaHeader| D[Parser Object]
D -->|.read| E[Python Dictionary]
E -->|Access key| F[Slice Times]
style A fill:#e1f5ff
style C fill:#fff4e1
style E fill:#e8f5e9
style F fill:#c8e6c9
Step-by-step:
- Line 5: Load DICOM file using pydicom
-
Line 8: Extract raw bytes from CSA tag
(0x0029, 0x1010)- this contains series-level metadata - Line 11-12: Parse the binary CSA format into a Python dictionary with tag names as keys
- Line 15-16: Access specific parameters by tag name
If you don't have a Siemens DICOM file handy, you can test with sample data:
# Download a sample from the repository examples
# Or use your own Siemens fMRI DICOM file
import pydicom
from csa_header import CsaHeader
dcm = pydicom.dcmread('path/to/your/siemens_dicom.dcm')
# Verify it's a Siemens file
if hasattr(dcm, 'Manufacturer'):
print(f"Manufacturer: {dcm.Manufacturer}")
if 'SIEMENS' not in dcm.Manufacturer.upper():
print("⚠️ Warning: Not a Siemens file!")
else:
print("⚠️ No manufacturer information found")
# Check if CSA headers are present
if (0x0029, 0x1010) in dcm:
print("✅ CSA Series Header found")
series_csa = CsaHeader(dcm[0x0029, 0x1010].value).read()
print(f"Available tags: {len(series_csa)}")
else:
print("❌ No CSA Series Header found")
if (0x0029, 0x1020) in dcm:
print("✅ CSA Image Header found")
image_csa = CsaHeader(dcm[0x0029, 0x1020].value).read()
print(f"Available tags: {len(image_csa)}")
else:
print("❌ No CSA Image Header found")Tip
Choose the right CSA header for your needs:
-
Series Header
(0x0029, 0x1010): Slice timing, protocol parameters, mosaic info -
Image Header
(0x0029, 0x1020): B-values, gradients, slice position
# For DWI/DTI: Use Image Header (0x0029, 0x1020)
image_header_bytes = dcm[0x0029, 0x1020].value
image_info = CsaHeader(image_header_bytes).read()
# Get diffusion parameters
b_value = image_info['B_value']['value']
gradient = image_info['DiffusionGradientDirection']['value']
print(f"B-value: {b_value}")
print(f"Gradient direction: {gradient}")Expected output:
B-value: 1000
Gradient direction: [0.707, 0.707, 0.0]
# Access ASCCONV protocol parameters
series_info = CsaHeader(dcm[0x0029, 0x1010].value).read()
# The protocol is automatically parsed into a nested dictionary
protocol = series_info.get('MrPhoenixProtocol', {}).get('value', {})
if protocol:
tr = protocol.get('alTR', [None])[0] # Repetition time in ms
te = protocol.get('alTE', [None])[0] # Echo time in ms
print(f"TR: {tr} ms")
print(f"TE: {te} ms")Expected output:
TR: 2000 ms
TE: 30 ms
A: Not all sequences include slice timing. This is normal for:
- Single-slice acquisitions
- Non-EPI sequences
- Some older scanner software versions
See Troubleshooting#missing-slice-timing for solutions.
A: No. CSA headers are Siemens-specific proprietary structures. Other manufacturers use different formats:
-
GE: Use
pydicomto access standard DICOM tags -
Philips: Look for private tags in
(2001, xxxx)range - Canon/Toshiba: Limited private tag documentation
A: No, but it's helpful! csa_header only requires pydicom and numpy. NiBabel is useful for:
- Loading DICOM images as numpy arrays
- Converting to NIfTI format
- Advanced neuroimaging workflows
See Integration with NiBabel for combined workflows.
A: Siemens DICOM files contain two CSA headers:
| Header | Tag | Contains | Use For |
|---|---|---|---|
| Series Header | (0x0029, 0x1010) |
Series-level info | Slice timing, protocol, mosaic info |
| Image Header | (0x0029, 0x1020) |
Image-level info | B-values, gradients, slice position |
A: Don't worry! The CsaHeader class automatically detects the format:
-
CSA2 (modern): Starts with
'SV10'identifier - CSA1 (legacy): No identifier
Both are parsed identically - you don't need to do anything different.
Now that you've extracted basic CSA information, explore more advanced topics:
- User Guide - Complete examples for fMRI, DWI, and QA workflows
- Technical Reference - Understand CSA format details and ASCCONV protocol
- Integration with NiBabel - Combine with neuroimaging pipelines
- User Guide#functional-mri-fmri - Complete fMRI preprocessing workflow
- User Guide#diffusion-mri-dwidti - Extract DWI parameters and gradients
- User Guide#protocol-verification - QA and protocol checking
- Troubleshooting - Common issues and solutions
- GitHub Issues - Report bugs or ask questions
Here's a complete template you can copy and adapt:
#!/usr/bin/env python3
"""
Extract CSA header information from Siemens DICOM files.
"""
import sys
import pydicom
from csa_header import CsaHeader, CsaReadError
def extract_csa_info(dicom_path: str) -> dict:
"""
Extract CSA header information from a Siemens DICOM file.
Parameters
----------
dicom_path : str
Path to Siemens DICOM file
Returns
-------
dict
Dictionary containing extracted CSA information
"""
# Load DICOM file
dcm = pydicom.dcmread(dicom_path)
results = {}
# Check manufacturer
if not hasattr(dcm, 'Manufacturer'):
raise ValueError("No manufacturer information found")
if 'SIEMENS' not in dcm.Manufacturer.upper():
raise ValueError(f"Not a Siemens file (manufacturer: {dcm.Manufacturer})")
# Extract Series Header (0x0029, 0x1010)
if (0x0029, 0x1010) in dcm:
try:
series_data = dcm[0x0029, 0x1010].value
series_info = CsaHeader(series_data).read()
# Extract slice timing if available
if 'MosaicRefAcqTimes' in series_info:
results['slice_times'] = series_info['MosaicRefAcqTimes']['value']
if 'NumberOfImagesInMosaic' in series_info:
results['n_slices'] = series_info['NumberOfImagesInMosaic']['value']
# Extract protocol parameters
if 'MrPhoenixProtocol' in series_info:
protocol = series_info['MrPhoenixProtocol']['value']
if isinstance(protocol, dict):
results['TR'] = protocol.get('alTR', [None])[0]
results['TE'] = protocol.get('alTE', [None])[0]
except CsaReadError as e:
print(f"Error parsing Series Header: {e}", file=sys.stderr)
# Extract Image Header (0x0029, 0x1020)
if (0x0029, 0x1020) in dcm:
try:
image_data = dcm[0x0029, 0x1020].value
image_info = CsaHeader(image_data).read()
# Extract diffusion parameters if available
if 'B_value' in image_info:
results['b_value'] = image_info['B_value']['value']
if 'DiffusionGradientDirection' in image_info:
results['gradient'] = image_info['DiffusionGradientDirection']['value']
except CsaReadError as e:
print(f"Error parsing Image Header: {e}", file=sys.stderr)
return results
if __name__ == '__main__':
if len(sys.argv) < 2:
print("Usage: python script.py <path_to_dicom>")
sys.exit(1)
try:
info = extract_csa_info(sys.argv[1])
print("\n=== CSA Header Information ===")
for key, value in info.items():
if isinstance(value, list) and len(value) > 5:
print(f"{key}: [{value[0]}, {value[1]}, ..., {value[-1]}] ({len(value)} values)")
else:
print(f"{key}: {value}")
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
sys.exit(1)Save this as extract_csa.py and run:
python extract_csa.py your_dicom_file.dcmReady for more? Continue to the User Guide for comprehensive examples and workflows.
Version: 1.0+