Skill Tracer
Skills › Scientific Agent Skills › bids › conversion_tools.md

conversion_tools.md

490 lines · skills/bids/references/conversion_tools.md at 5f2bc03

Open on GitHub
1# BIDS Conversion Tools Reference
2
3This reference covers detailed workflows for converting DICOM and other raw data formats to BIDS using the three main conversion tools.
4

BIDS Conversion Tools Reference

This reference covers detailed workflows for converting DICOM and other raw data formats to BIDS using the three main conversion tools.

Raw lines 1 to 4
5## HeuDiConv
6
7HeuDiConv supports Python heuristic-based DICOM-to-BIDS conversion. It supports three usage modes — from fully automatic turnkey conversion to fully custom heuristics — and handles duplicates, provenance tracking, and sourcedata archiving out of the box.
8
9**Repository**: https://github.com/nipy/heudiconv
10**Docs**: https://heudiconv.readthedocs.io/
11**Tutorials**: https://heudiconv.readthedocs.io/en/latest/tutorials.html

HeuDiConv

HeuDiConv supports Python heuristic-based DICOM-to-BIDS conversion. It supports three usage modes — from fully automatic turnkey conversion to fully custom heuristics — and handles duplicates, provenance tracking, and sourcedata archiving out of the box.

Repository: https://github.com/nipy/heudiconv Docs: https://heudiconv.readthedocs.io/ Tutorials: https://heudiconv.readthedocs.io/en/latest/tutorials.html

Raw lines 5 to 12
13### Installation
15```bash
16uv pip install heudiconv
18# HeuDiConv wraps dcm2niix for the actual conversion
19# Install dcm2niix separately and verify `dcm2niix --version`; for example:
20# conda install -c conda-forge dcm2niix
21# or: apt-get install dcm2niix
22```

Installation

uv pip install heudiconv

# HeuDiConv wraps dcm2niix for the actual conversion
# Install dcm2niix separately and verify `dcm2niix --version`; for example:
# conda install -c conda-forge dcm2niix
# or: apt-get install dcm2niix
Raw lines 13 to 23
24### Mode 1: ReproIn (Turnkey Conversion — Recommended for New Studies)
26If scanner protocol names follow the [ReproIn naming convention](https://github.com/repronim/reproin), conversion is fully automatic with no heuristic file to write. ReproIn is a setup for automatic generation of sharable, version-controlled BIDS datasets directly from MR scanners.
28```bash
29# Turnkey conversion — just point at DICOMs, HeuDiConv does the rest
30heudiconv --files dicom/001 -o data -f reproin --bids --minmeta
31```
33#### ReproIn Protocol Naming Rules
35Protocol names encode BIDS entities directly. Format: `<seqtype>[-<suffix>][_<entity>-<label>]...`
37| Protocol name at scanner | BIDS output |
38|--------------------------|-------------|
39| `anat-T1w` | `sub-XX/anat/sub-XX_T1w.nii.gz` |
40| `func-bold_task-rest` or `func_task-rest` | `sub-XX/func/sub-XX_task-rest_bold.nii.gz` |
41| `dwi_dir-AP` | `sub-XX/dwi/sub-XX_dir-AP_dwi.nii.gz` |
42| `fmap_dir-PA` or `fmap-epi_dir-PA` | `sub-XX/fmap/sub-XX_dir-PA_epi.nii.gz` |
43| `fmap_acq-4mm` | `sub-XX/fmap/sub-XX_acq-4mm_epi.nii.gz` |
45**Key features:**
46- **Suffixes**: specify anatomical contrast explicitly; ReproIn may infer suffixes from DICOM image type, not a universal `anat` -> `T1w` default
47- **Subject ID**: extracted automatically from DICOM metadata (Patient ID)
48- **Session**: set once on any sequence (e.g., `anat-scout_ses-pre`) and ReproIn propagates it to all sequences in that scanner Program/Patient
49- **Run/duplicate handling**: encode `_run-01` or the documented increment convention. Repeated/cancelled runs can be marked `__dup...`; inspect them rather than assuming every repeat becomes a valid run
50- **Locator hierarchy**: output is nested under Region/Exam from the scanner's Study Description (customizable with `--locator`)
51- **sourcedata**: original DICOMs are archived as `.tgz` files under `sourcedata/` for reproducibility
52- **Dashes in names**: scanners may strip dashes from protocol names during DICOM export — ReproIn handles this gracefully
54#### ReproIn Overview
56See also:
57- [ReproIn Walkthrough](https://github.com/repronim/reproin#walkthrough) for scanner setup
58- [ReproNim Webinar slides and recording](https://github.com/repronim/reproin#presentations) on HeuDiConv + ReproIn

Mode 1: ReproIn (Turnkey Conversion — Recommended for New Studies)

If scanner protocol names follow the ReproIn naming convention, conversion is fully automatic with no heuristic file to write. ReproIn is a setup for automatic generation of sharable, version-controlled BIDS datasets directly from MR scanners.

# Turnkey conversion — just point at DICOMs, HeuDiConv does the rest
heudiconv --files dicom/001 -o data -f reproin --bids --minmeta

ReproIn Protocol Naming Rules

Protocol names encode BIDS entities directly. Format: <seqtype>[-<suffix>][_<entity>-<label>]...

Protocol name at scannerBIDS output
anat-T1wsub-XX/anat/sub-XX_T1w.nii.gz
func-bold_task-rest or func_task-restsub-XX/func/sub-XX_task-rest_bold.nii.gz
dwi_dir-APsub-XX/dwi/sub-XX_dir-AP_dwi.nii.gz
fmap_dir-PA or fmap-epi_dir-PAsub-XX/fmap/sub-XX_dir-PA_epi.nii.gz
fmap_acq-4mmsub-XX/fmap/sub-XX_acq-4mm_epi.nii.gz

Key features:

  • Suffixes: specify anatomical contrast explicitly; ReproIn may infer suffixes from DICOM image type, not a universal anat -> T1w default
  • Subject ID: extracted automatically from DICOM metadata (Patient ID)
  • Session: set once on any sequence (e.g., anat-scout_ses-pre) and ReproIn propagates it to all sequences in that scanner Program/Patient
  • Run/duplicate handling: encode _run-01 or the documented increment convention. Repeated/cancelled runs can be marked __dup...; inspect them rather than assuming every repeat becomes a valid run
  • Locator hierarchy: output is nested under Region/Exam from the scanner's Study Description (customizable with --locator)
  • sourcedata: original DICOMs are archived as .tgz files under sourcedata/ for reproducibility
  • Dashes in names: scanners may strip dashes from protocol names during DICOM export — ReproIn handles this gracefully

ReproIn Overview

See also:

Raw lines 24 to 59
60### Mode 2: Custom Heuristic Mapping into ReproIn (For Existing Data)
62If you already have collected data with non-ReproIn protocol names (or cannot control scanner naming), you can write a thin heuristic that maps your protocol names into ReproIn conventions. This gives you all ReproIn benefits (automatic entity handling, duplicate management, sourcedata archiving) while accommodating arbitrary scanner naming.
64See https://github.com/repronim/reproin/issues/18 for a brief HOWTO on this approach.
66Use a custom heuristic that imports ReproIn and remaps sequence metadata before delegating to its `infotodict`, or configure its `protocols2fix` substitutions. Merely returning ReproIn-looking keys from an unrelated heuristic does not invoke ReproIn.

Mode 2: Custom Heuristic Mapping into ReproIn (For Existing Data)

If you already have collected data with non-ReproIn protocol names (or cannot control scanner naming), you can write a thin heuristic that maps your protocol names into ReproIn conventions. This gives you all ReproIn benefits (automatic entity handling, duplicate management, sourcedata archiving) while accommodating arbitrary scanner naming.

See https://github.com/repronim/reproin/issues/18 for a brief HOWTO on this approach.

Use a custom heuristic that imports ReproIn and remaps sequence metadata before delegating to its infotodict, or configure its protocols2fix substitutions. Merely returning ReproIn-looking keys from an unrelated heuristic does not invoke ReproIn.

Raw lines 60 to 67
68### Mode 3: Custom Heuristic (Full Flexibility)
70For studies with complex mappings or non-standard requirements, write a full Python heuristic file. This is the most common workflow for retrospective conversion of existing datasets.
72#### Step 1: Reconnaissance — Discover DICOM series
74```bash
75# -f convertall: built-in heuristic that lists all series without converting
76# -c none: don't convert, just generate dicominfo.tsv
77heudiconv \
78 --files dicom/219/itbs/*/*.dcm \
79 -s 219 \
80 -f convertall \
81 -c none \
82 -o Nifti/
83```
85This creates `.heudiconv/219/info/dicominfo.tsv` containing one row per DICOM series with columns:
86- `series_id`, `sequence_name`, `protocol_name`, `series_description`
87- `dim1`-`dim4` (image dimensions), `TR`, `TE`, `image_type`
88- `is_derived`, `is_motion_corrected` — important for filtering
90Review this TSV (open in a spreadsheet) to understand what was acquired and plan the mapping to BIDS names. Repeat reconnaissance for protocol variants, sessions and scanners; one participant does not establish all mappings.
92#### Step 2: Write a heuristic file
94Illustrative study-specific mapping, exercised with synthetic `SeqInfo` records on
95HeuDiConv 1.5.1. Confirm actual series before use. Fieldmap phase versus phasedifference
96and matching echo pairs require protocol knowledge; `ImageType` alone cannot establish them.
98```python
99"""HeuDiConv heuristic for a typical fMRI study.
101Study design:
102- T1w MPRAGE anatomical
103- Resting-state BOLD
104- Task BOLD (n-back working memory)
105- DWI with two phase-encoding directions
106- Fieldmap (phase-difference)
107"""
109def create_key(template, outtype=('nii.gz',), annotation_classes=None):
110 if template is None or not template:
111 raise ValueError('Template must be a valid format string')
112 return template, outtype, annotation_classes
115def infotodict(seqinfo):
116 """Heuristic evaluator for determining which runs belong where.
118 Parameters
119 ----------
120 seqinfo : list of namedtuples
121 Each namedtuple has fields: .series_id, .sequence_name,
122 .protocol_name, .series_description, .dim1, .dim2, .dim3, .dim4,
123 .TR, .TE, .is_derived, .is_motion_corrected, .image_type, etc.
125 Returns
126 -------
127 info : dict
128 Keys are tuples from create_key(), values are lists of series_id
129 """
130 # Define BIDS output templates
131 t1w = create_key(
132 '{bids_subject_session_dir}/anat/{bids_subject_session_prefix}_run-{item:02d}_T1w'
133 )
134 rest_bold = create_key(
135 '{bids_subject_session_dir}/func/{bids_subject_session_prefix}_task-rest_run-{item:02d}_bold'
136 )
137 # {item:02d} auto-numbers runs when the same protocol is run multiple times
138 nback_bold = create_key(
139 '{bids_subject_session_dir}/func/{bids_subject_session_prefix}_task-nback_run-{item:02d}_bold'
140 )
141 dwi_AP = create_key(
142 '{bids_subject_session_dir}/dwi/{bids_subject_session_prefix}_dir-AP_run-{item:02d}_dwi'
143 )
144 dwi_PA = create_key(
145 '{bids_subject_session_dir}/dwi/{bids_subject_session_prefix}_dir-PA_run-{item:02d}_dwi'
146 )
147 fmap_phasediff = create_key(
148 '{bids_subject_session_dir}/fmap/{bids_subject_session_prefix}_run-{item:02d}_phasediff'
149 )
150 fmap_mag1 = create_key(
151 '{bids_subject_session_dir}/fmap/{bids_subject_session_prefix}_run-{item:02d}_magnitude1'
152 )
153 fmap_mag2 = create_key(
154 '{bids_subject_session_dir}/fmap/{bids_subject_session_prefix}_run-{item:02d}_magnitude2'
155 )
157 info = {
158 t1w: [], rest_bold: [], nback_bold: [],
159 dwi_AP: [], dwi_PA: [],
160 fmap_phasediff: [], fmap_mag1: [], fmap_mag2: [],
161 }
163 for s in seqinfo:
164 protocol = (s.protocol_name or "").lower()
165 series_desc = s.series_description.lower() if s.series_description else ''
167 # Anatomical — filter by dim3 to exclude localizers
168 if ('mprage' in protocol or 't1w' in protocol) and s.dim3 > 100:
169 info[t1w].append(s.series_id)
171 # Functional — filter by dim4 and exclude MOCO series
172 elif 'rest' in protocol and s.dim4 > 10 and not s.is_motion_corrected:
173 info[rest_bold].append(s.series_id)
174 elif 'nback' in protocol and s.dim4 > 10 and not s.is_motion_corrected:
175 info[nback_bold].append(s.series_id)
177 # Diffusion
178 elif ('dti' in protocol or 'dwi' in protocol) and s.dim4 > 1:
179 if 'ap' in protocol or 'ap' in series_desc:
180 info[dwi_AP].append(s.series_id)
181 elif 'pa' in protocol or 'pa' in series_desc:
182 info[dwi_PA].append(s.series_id)
184 # Fieldmaps
185 elif 'field' in protocol or 'fmap' in protocol:
186 if 'P' in s.image_type:
187 info[fmap_phasediff].append(s.series_id)
188 elif s.series_description and 'e1' in s.series_description.lower():
189 info[fmap_mag1].append(s.series_id)
190 elif s.series_description and 'e2' in s.series_description.lower():
191 info[fmap_mag2].append(s.series_id)
193 return info
194```
196#### Step 3: Convert
198```bash
199# Convert with custom heuristic
200heudiconv \
201 --files dicom/219/itbs/*/*.dcm \
202 -s 219 \
203 -ss itbs \
204 -f Nifti/code/heuristic.py \
205 -c dcm2niix \
206 --bids \
207 --minmeta \
208 -o Nifti/
210# Or using -d template for batch conversion of multiple subjects
211heudiconv \
212 -d "/path/to/dicoms/{subject}/*/*/*.dcm" \
213 -s 01 02 03 04 05 \
214 -f my_heuristic.py \
215 -c dcm2niix \
216 --bids \
217 --minmeta \
218 -o /path/to/bids_output
220# Key flags:
221# --files : point to specific DICOM files/directories
222# -d : DICOM path template ({subject}, {session} are replaced)
223# -s : subject label(s)
224# -ss : session label
225# -f : heuristic file path, or built-in name (reproin, convertall)
226# -c : converter (dcm2niix, none)
227# --bids / -b : output BIDS structure (creates JSON sidecars, etc.)
228# --minmeta : omit additional scaninfo metadata (not dcm2niix BIDS metadata)
229# -o : output directory
230# --overwrite : re-run conversion overwriting existing files
231```

Mode 3: Custom Heuristic (Full Flexibility)

For studies with complex mappings or non-standard requirements, write a full Python heuristic file. This is the most common workflow for retrospective conversion of existing datasets.

Step 1: Reconnaissance — Discover DICOM series

# -f convertall: built-in heuristic that lists all series without converting
# -c none: don't convert, just generate dicominfo.tsv
heudiconv \
    --files dicom/219/itbs/*/*.dcm \
    -s 219 \
    -f convertall \
    -c none \
    -o Nifti/

This creates .heudiconv/219/info/dicominfo.tsv containing one row per DICOM series with columns:

  • series_id, sequence_name, protocol_name, series_description
  • dim1-dim4 (image dimensions), TR, TE, image_type
  • is_derived, is_motion_corrected — important for filtering

Review this TSV (open in a spreadsheet) to understand what was acquired and plan the mapping to BIDS names. Repeat reconnaissance for protocol variants, sessions and scanners; one participant does not establish all mappings.

Step 2: Write a heuristic file

Illustrative study-specific mapping, exercised with synthetic SeqInfo records on HeuDiConv 1.5.1. Confirm actual series before use. Fieldmap phase versus phasedifference and matching echo pairs require protocol knowledge; ImageType alone cannot establish them.

"""HeuDiConv heuristic for a typical fMRI study.

Study design:
- T1w MPRAGE anatomical
- Resting-state BOLD
- Task BOLD (n-back working memory)
- DWI with two phase-encoding directions
- Fieldmap (phase-difference)
"""

def create_key(template, outtype=('nii.gz',), annotation_classes=None):
    if template is None or not template:
        raise ValueError('Template must be a valid format string')
    return template, outtype, annotation_classes


def infotodict(seqinfo):
    """Heuristic evaluator for determining which runs belong where.

    Parameters
    ----------
    seqinfo : list of namedtuples
        Each namedtuple has fields: .series_id, .sequence_name,
        .protocol_name, .series_description, .dim1, .dim2, .dim3, .dim4,
        .TR, .TE, .is_derived, .is_motion_corrected, .image_type, etc.

    Returns
    -------
    info : dict
        Keys are tuples from create_key(), values are lists of series_id
    """
    # Define BIDS output templates
    t1w = create_key(
        '{bids_subject_session_dir}/anat/{bids_subject_session_prefix}_run-{item:02d}_T1w'
    )
    rest_bold = create_key(
        '{bids_subject_session_dir}/func/{bids_subject_session_prefix}_task-rest_run-{item:02d}_bold'
    )
    # {item:02d} auto-numbers runs when the same protocol is run multiple times
    nback_bold = create_key(
        '{bids_subject_session_dir}/func/{bids_subject_session_prefix}_task-nback_run-{item:02d}_bold'
    )
    dwi_AP = create_key(
        '{bids_subject_session_dir}/dwi/{bids_subject_session_prefix}_dir-AP_run-{item:02d}_dwi'
    )
    dwi_PA = create_key(
        '{bids_subject_session_dir}/dwi/{bids_subject_session_prefix}_dir-PA_run-{item:02d}_dwi'
    )
    fmap_phasediff = create_key(
        '{bids_subject_session_dir}/fmap/{bids_subject_session_prefix}_run-{item:02d}_phasediff'
    )
    fmap_mag1 = create_key(
        '{bids_subject_session_dir}/fmap/{bids_subject_session_prefix}_run-{item:02d}_magnitude1'
    )
    fmap_mag2 = create_key(
        '{bids_subject_session_dir}/fmap/{bids_subject_session_prefix}_run-{item:02d}_magnitude2'
    )

    info = {
        t1w: [], rest_bold: [], nback_bold: [],
        dwi_AP: [], dwi_PA: [],
        fmap_phasediff: [], fmap_mag1: [], fmap_mag2: [],
    }

    for s in seqinfo:
        protocol = (s.protocol_name or "").lower()
        series_desc = s.series_description.lower() if s.series_description else ''

        # Anatomical — filter by dim3 to exclude localizers
        if ('mprage' in protocol or 't1w' in protocol) and s.dim3 > 100:
            info[t1w].append(s.series_id)

        # Functional — filter by dim4 and exclude MOCO series
        elif 'rest' in protocol and s.dim4 > 10 and not s.is_motion_corrected:
            info[rest_bold].append(s.series_id)
        elif 'nback' in protocol and s.dim4 > 10 and not s.is_motion_corrected:
            info[nback_bold].append(s.series_id)

        # Diffusion
        elif ('dti' in protocol or 'dwi' in protocol) and s.dim4 > 1:
            if 'ap' in protocol or 'ap' in series_desc:
                info[dwi_AP].append(s.series_id)
            elif 'pa' in protocol or 'pa' in series_desc:
                info[dwi_PA].append(s.series_id)

        # Fieldmaps
        elif 'field' in protocol or 'fmap' in protocol:
            if 'P' in s.image_type:
                info[fmap_phasediff].append(s.series_id)
            elif s.series_description and 'e1' in s.series_description.lower():
                info[fmap_mag1].append(s.series_id)
            elif s.series_description and 'e2' in s.series_description.lower():
                info[fmap_mag2].append(s.series_id)

    return info

Step 3: Convert

# Convert with custom heuristic
heudiconv \
    --files dicom/219/itbs/*/*.dcm \
    -s 219 \
    -ss itbs \
    -f Nifti/code/heuristic.py \
    -c dcm2niix \
    --bids \
    --minmeta \
    -o Nifti/

# Or using -d template for batch conversion of multiple subjects
heudiconv \
    -d "/path/to/dicoms/{subject}/*/*/*.dcm" \
    -s 01 02 03 04 05 \
    -f my_heuristic.py \
    -c dcm2niix \
    --bids \
    --minmeta \
    -o /path/to/bids_output

# Key flags:
# --files : point to specific DICOM files/directories
# -d : DICOM path template ({subject}, {session} are replaced)
# -s : subject label(s)
# -ss : session label
# -f : heuristic file path, or built-in name (reproin, convertall)
# -c : converter (dcm2niix, none)
# --bids / -b : output BIDS structure (creates JSON sidecars, etc.)
# --minmeta : omit additional scaninfo metadata (not dcm2niix BIDS metadata)
# -o : output directory
# --overwrite : re-run conversion overwriting existing files
Raw lines 68 to 232
233### The .heudiconv Directory
235Every conversion creates/updates a `.heudiconv/` hidden directory alongside the output:
236- `.heudiconv/<subject>/info/dicominfo.tsv` — DICOM series metadata
237- `.heudiconv/<subject>/info/<heuristic>.py` — copy of the heuristic used
238- Conversion records for each subject/session
240**Cache review**: HeuDiConv may reuse conversion records under `.heudiconv/`. Preserve provenance, inspect the generated mapping, and use a fresh output directory when verifying a changed heuristic instead of deleting the only record.
242Keep `.heudiconv/` with your data — together with `code/` it provides valuable provenance information.

The .heudiconv Directory

Every conversion creates/updates a .heudiconv/ hidden directory alongside the output:

  • .heudiconv/<subject>/info/dicominfo.tsv — DICOM series metadata
  • .heudiconv/<subject>/info/<heuristic>.py — copy of the heuristic used
  • Conversion records for each subject/session

Cache review: HeuDiConv may reuse conversion records under .heudiconv/. Preserve provenance, inspect the generated mapping, and use a fresh output directory when verifying a changed heuristic instead of deleting the only record.

Keep .heudiconv/ with your data — together with code/ it provides valuable provenance information.

Raw lines 233 to 243
244### HeuDiConv Tips
2461. **Use `--minmeta`** when additional scaninfo metadata is not needed; it is not a deidentification guarantee
2472. **Use `{item:02d}` in templates** for auto-numbering runs: if multiple series match, they get `run-01`, `run-02`, etc. Inspect duplicate output targets before conversion; collision behavior depends on overwrite settings
2483. **Filter by `dim3`/`dim4`** to exclude localizers (small `dim3`) and single-volume scouts (`dim4 == 1`)
2494. **Check `s.is_motion_corrected`** to exclude scanner-generated MOCO series (e.g., `if not s.is_motion_corrected`)
2505. **Check `s.is_derived`** to skip other derived/processed series
2516. **Store heuristic with dataset** under `code/` for reproducibility
2527. **Use `--files`** when DICOM organization doesn't follow a clean `{subject}` template pattern
2538. **For new studies**: prefer ReproIn protocol naming from the start — it eliminates the need for custom heuristics entirely
2549. **For existing data with arbitrary names**: consider the "map into reproin" approach rather than writing a fully custom heuristic — you get duplicate handling, session propagation, and other ReproIn features for free

HeuDiConv Tips

  1. **Use --minmeta** when additional scaninfo metadata is not needed; it is not a deidentification guarantee
  2. **Use {item:02d} in templates** for auto-numbering runs: if multiple series match, they get run-01, run-02, etc. Inspect duplicate output targets before conversion; collision behavior depends on overwrite settings
  3. **Filter by dim3/dim4** to exclude localizers (small dim3) and single-volume scouts (dim4 == 1)
  4. **Check s.is_motion_corrected** to exclude scanner-generated MOCO series (e.g., if not s.is_motion_corrected)
  5. **Check s.is_derived** to skip other derived/processed series
  6. Store heuristic with dataset under code/ for reproducibility
  7. **Use --files** when DICOM organization doesn't follow a clean {subject} template pattern
  8. For new studies: prefer ReproIn protocol naming from the start — it eliminates the need for custom heuristics entirely
  9. For existing data with arbitrary names: consider the "map into reproin" approach rather than writing a fully custom heuristic — you get duplicate handling, session propagation, and other ReproIn features for free
Raw lines 244 to 255
256## dcm2bids (Configuration-File-Based)
258dcm2bids uses JSON configuration files instead of Python heuristics. Simpler for straightforward datasets.
260**Repository**: https://github.com/UNFmontreal/Dcm2Bids
261**Docs**: https://unfmontreal.github.io/Dcm2Bids/

dcm2bids (Configuration-File-Based)

dcm2bids uses JSON configuration files instead of Python heuristics. Simpler for straightforward datasets.

Repository: https://github.com/UNFmontreal/Dcm2Bids Docs: https://unfmontreal.github.io/Dcm2Bids/

Raw lines 256 to 262
263### Installation
265```bash
266uv pip install dcm2bids
267# Install dcm2niix separately and ensure it is on PATH
268```

Installation

uv pip install dcm2bids
# Install dcm2niix separately and ensure it is on PATH
Raw lines 263 to 269
270### Workflow
272#### Step 1: Scaffold a BIDS directory
274```bash
275dcm2bids_scaffold -o /path/to/bids_output
276```
278Creates the basic BIDS structure with `dataset_description.json`, `README`, `.bidsignore`, etc.
280#### Step 2: Run helper to inspect DICOM metadata
282```bash
283dcm2bids_helper -d /path/to/dicom_dir -o /path/to/bids_output
284```
286Creates `tmp_dcm2bids/helper/` with converted NIfTI files and JSON sidecars. Review the JSON files to find distinguishing metadata fields.
288#### Step 3: Write configuration file
290```json
292 "descriptions": [
293 {
294 "id": "id_t1w",
295 "datatype": "anat",
296 "suffix": "T1w",
297 "criteria": {
298 "SeriesDescription": "*MPRAGE*",
299 "ImageType": ["ORIGINAL", "PRIMARY", "M", "ND", "NORM"]
300 }
301 },
302 {
303 "id": "id_bold_rest",
304 "datatype": "func",
305 "suffix": "bold",
306 "custom_entities": "task-rest",
307 "criteria": {
308 "SeriesDescription": "*REST*BOLD*",
309 "ImageType": ["ORIGINAL", "PRIMARY", "M", "ND", "MOSAIC"]
310 },
311 "sidecar_changes": {
312 "TaskName": "rest"
313 }
314 },
315 {
316 "id": "id_bold_nback",
317 "datatype": "func",
318 "suffix": "bold",
319 "custom_entities": "task-nback",
320 "criteria": {
321 "SeriesDescription": "*NBACK*",
322 "EchoTime": 0.03
323 },
324 "sidecar_changes": {
325 "TaskName": "nback"
326 }
327 },
328 {
329 "id": "id_dwi",
330 "datatype": "dwi",
331 "suffix": "dwi",
332 "custom_entities": "dir-AP",
333 "criteria": {
334 "SeriesDescription": "*DTI*AP*"
335 }
336 },
337 {
338 "id": "id_fmap_phasediff",
339 "datatype": "fmap",
340 "suffix": "phasediff",
341 "criteria": {
342 "SeriesDescription": "*field*map*",
343 "EchoTime1": 0.00492,
344 "EchoTime2": 0.00738
345 },
346 "sidecar_changes": {
347 "IntendedFor": [
348 "id_bold_rest",
349 "id_bold_nback"
350 ]
351 }
352 }
353 ]
355```
357**Configuration file fields:**
358- `datatype`: BIDS datatype (`anat`, `func`, `dwi`, `fmap`, etc.)
359- `suffix`: BIDS suffix (`T1w`, `bold`, `dwi`, etc.)
360- `custom_entities`: additional BIDS entities (`task-rest`, `dir-AP`, `acq-highres`, etc.)
361- `criteria`: dictionary of DICOM/JSON metadata fields to match (supports wildcards `*`)
362- `sidecar_changes`: fields to add/modify in the output JSON sidecar
363- `id`: description identifier used by cross-file links such as `IntendedFor`. dcm2bids 3.3.1 resolves matching IDs to BIDS URIs by default; it does not expand arbitrary `{subject}` strings here
365#### Step 4: Convert
367```bash
368# Single subject
369dcm2bids -d /path/to/dicom_dir -p 01 -c dcm2bids_config.json -o /path/to/bids_output
371# With session
372dcm2bids -d /path/to/dicom_dir -p 01 -s pre -c dcm2bids_config.json -o /path/to/bids_output
374# Flags:
375# -d : DICOM source directory
376# -p : participant label
377# -s : session label (optional)
378# -c : configuration file
379# -o : output BIDS directory
380# --auto_extract_entities : extract supported entities (e.g. task/echo/part) from metadata
381# --force_dcm2bids : overwrite existing conversions
382```

Workflow

Step 1: Scaffold a BIDS directory

dcm2bids_scaffold -o /path/to/bids_output

Creates the basic BIDS structure with dataset_description.json, README, .bidsignore, etc.

Step 2: Run helper to inspect DICOM metadata

dcm2bids_helper -d /path/to/dicom_dir -o /path/to/bids_output

Creates tmp_dcm2bids/helper/ with converted NIfTI files and JSON sidecars. Review the JSON files to find distinguishing metadata fields.

Step 3: Write configuration file

{
    "descriptions": [
        {
            "id": "id_t1w",
            "datatype": "anat",
            "suffix": "T1w",
            "criteria": {
                "SeriesDescription": "*MPRAGE*",
                "ImageType": ["ORIGINAL", "PRIMARY", "M", "ND", "NORM"]
            }
        },
        {
            "id": "id_bold_rest",
            "datatype": "func",
            "suffix": "bold",
            "custom_entities": "task-rest",
            "criteria": {
                "SeriesDescription": "*REST*BOLD*",
                "ImageType": ["ORIGINAL", "PRIMARY", "M", "ND", "MOSAIC"]
            },
            "sidecar_changes": {
                "TaskName": "rest"
            }
        },
        {
            "id": "id_bold_nback",
            "datatype": "func",
            "suffix": "bold",
            "custom_entities": "task-nback",
            "criteria": {
                "SeriesDescription": "*NBACK*",
                "EchoTime": 0.03
            },
            "sidecar_changes": {
                "TaskName": "nback"
            }
        },
        {
            "id": "id_dwi",
            "datatype": "dwi",
            "suffix": "dwi",
            "custom_entities": "dir-AP",
            "criteria": {
                "SeriesDescription": "*DTI*AP*"
            }
        },
        {
            "id": "id_fmap_phasediff",
            "datatype": "fmap",
            "suffix": "phasediff",
            "criteria": {
                "SeriesDescription": "*field*map*",
                "EchoTime1": 0.00492,
                "EchoTime2": 0.00738
            },
            "sidecar_changes": {
                "IntendedFor": [
                    "id_bold_rest",
                    "id_bold_nback"
                ]
            }
        }
    ]
}

Configuration file fields:

  • datatype: BIDS datatype (anat, func, dwi, fmap, etc.)
  • suffix: BIDS suffix (T1w, bold, dwi, etc.)
  • custom_entities: additional BIDS entities (task-rest, dir-AP, acq-highres, etc.)
  • criteria: dictionary of DICOM/JSON metadata fields to match (supports wildcards *)
  • sidecar_changes: fields to add/modify in the output JSON sidecar
  • id: description identifier used by cross-file links such as IntendedFor. dcm2bids 3.3.1 resolves matching IDs to BIDS URIs by default; it does not expand arbitrary {subject} strings here

Step 4: Convert

# Single subject
dcm2bids -d /path/to/dicom_dir -p 01 -c dcm2bids_config.json -o /path/to/bids_output

# With session
dcm2bids -d /path/to/dicom_dir -p 01 -s pre -c dcm2bids_config.json -o /path/to/bids_output

# Flags:
# -d : DICOM source directory
# -p : participant label
# -s : session label (optional)
# -c : configuration file
# -o : output BIDS directory
# --auto_extract_entities : extract supported entities (e.g. task/echo/part) from metadata
# --force_dcm2bids : overwrite existing conversions
Raw lines 270 to 383
384### dcm2bids Tips
3861. **Use `dcm2bids_helper` first** to see exactly what metadata dcm2niix extracts
3872. **Criteria matching uses wildcards** (`*`) and is case-sensitive
3883. **Multiple criteria** are ANDed together; use the most specific combination
3894. **`sidecar_changes`** can inject any BIDS metadata (useful for `TaskName`, `IntendedFor`)
3905. **Store config file** under `code/dcm2bids_config.json` for reproducibility

dcm2bids Tips

  1. **Use dcm2bids_helper first** to see exactly what metadata dcm2niix extracts
  2. Criteria matching uses wildcards (*) and is case-sensitive
  3. Multiple criteria are ANDed together; use the most specific combination
  4. **sidecar_changes** can inject any BIDS metadata (useful for TaskName, IntendedFor)
  5. Store config file under code/dcm2bids_config.json for reproducibility
Raw lines 384 to 391
392## BIDScoin (GUI + YAML Configuration)
394BIDScoin provides a graphical interface and YAML-based configuration. Good for users who prefer visual mapping.
396**Repository**: https://github.com/Donders-Institute/bidscoin
397**Docs**: https://bidscoin.readthedocs.io/

BIDScoin (GUI + YAML Configuration)

BIDScoin provides a graphical interface and YAML-based configuration. Good for users who prefer visual mapping.

Repository: https://github.com/Donders-Institute/bidscoin Docs: https://bidscoin.readthedocs.io/

Raw lines 392 to 398
399### Installation
401```bash
402uv pip install "bidscoin[dcm2niix2bids]"
403# GUI requires a working Qt/display environment; install only needed plugin extras
404```

Installation

uv pip install "bidscoin[dcm2niix2bids]"
# GUI requires a working Qt/display environment; install only needed plugin extras
Raw lines 399 to 405
406### Workflow
408```bash
409# Step 1: Create a bidsmap template by scanning DICOMs
410bidsmapper /path/to/raw /path/to/bids
412# Step 2: Edit the bidsmap (launches GUI)
413bidseditor /path/to/bids
415# Step 3: Convert using the finalized bidsmap
416bidscoiner /path/to/raw /path/to/bids
417```

Workflow

# Step 1: Create a bidsmap template by scanning DICOMs
bidsmapper /path/to/raw /path/to/bids

# Step 2: Edit the bidsmap (launches GUI)
bidseditor /path/to/bids

# Step 3: Convert using the finalized bidsmap
bidscoiner /path/to/raw /path/to/bids
Raw lines 406 to 418
419### BIDScoin Tips
4211. **GUI-based editing** is BIDScoin's strength - the `bidseditor` shows DICOM metadata alongside BIDS mapping
4222. **YAML bidsmap** can be edited manually if preferred
4233. **Plugin architecture** supports custom conversion backends beyond dcm2niix
4244. **Good for multi-site studies** where protocol names vary - visual mapping makes differences obvious

BIDScoin Tips

  1. GUI-based editing is BIDScoin's strength - the bidseditor shows DICOM metadata alongside BIDS mapping
  2. YAML bidsmap can be edited manually if preferred
  3. Plugin architecture supports custom conversion backends beyond dcm2niix
  4. Good for multi-site studies where protocol names vary - visual mapping makes differences obvious
Raw lines 419 to 425
426## Comparison
428| Feature | HeuDiConv | dcm2bids | BIDScoin |
429|---------|-----------|----------|----------|
430| Configuration | Python heuristic | JSON config | YAML + GUI |
431| Flexibility | Highest (full Python) | Medium (criteria matching) | Medium (plugin system) |
432| Learning curve | Steeper (Python) | Moderate | Gentlest (GUI) |
433| Batch processing | Excellent | Good | Good |
434| ReproIn support | Built-in | No | No |
435| DataLad integration | Built-in | No | No |
436| Best for | Complex studies, automation | Simple-to-moderate studies | Visual learners, multi-site |
437| Active development | Yes | Yes | Yes |

Comparison

FeatureHeuDiConvdcm2bidsBIDScoin
ConfigurationPython heuristicJSON configYAML + GUI
FlexibilityHighest (full Python)Medium (criteria matching)Medium (plugin system)
Learning curveSteeper (Python)ModerateGentlest (GUI)
Batch processingExcellentGoodGood
ReproIn supportBuilt-inNoNo
DataLad integrationBuilt-inNoNo
Best forComplex studies, automationSimple-to-moderate studiesVisual learners, multi-site
Active developmentYesYesYes
Raw lines 426 to 438
439## Post-Conversion Checklist
441After converting DICOM to BIDS with any tool:
4431. **Run the BIDS validator**: `bids-validator-deno /path/to/bids_output`
4442. **Check JSON sidecars** for critical fields (`RepetitionTime`, `TaskName`, `SliceTiming`, `PhaseEncodingDirection`)
4453. **Verify NIfTI headers** match expectations (dimensions, voxel sizes, orientation)
4464. **Add missing metadata** that dcm2niix couldn't extract from DICOM
4475. **Create `participants.tsv`** with demographic data
4486. **Write events files** for task fMRI
4497. **Write `README`** describing the dataset
4508. **Deface anatomical images** if sharing data
4519. **Run `bids-validator-deno` again** after any manual modifications

Post-Conversion Checklist

After converting DICOM to BIDS with any tool:

  1. Run the BIDS validator: bids-validator-deno /path/to/bids_output
  2. Check JSON sidecars for critical fields (RepetitionTime, TaskName, SliceTiming, PhaseEncodingDirection)
  3. Verify NIfTI headers match expectations (dimensions, voxel sizes, orientation)
  4. Add missing metadata that dcm2niix couldn't extract from DICOM
  5. **Create participants.tsv** with demographic data
  6. Write events files for task fMRI
  7. **Write README** describing the dataset
  8. Deface anatomical images if sharing data
  9. **Run bids-validator-deno again** after any manual modifications
Raw lines 439 to 452
453## Common DICOM-to-BIDS Pitfalls

Common DICOM-to-BIDS Pitfalls

Raw lines 453 to 454
455### Multiband/SMS sequences
456- dcm2niix may split slices incorrectly for multiband data
457- Check `dim4` (number of volumes) matches expectations
458- Verify `SliceTiming` is correct for the multiband factor

Multiband/SMS sequences

  • dcm2niix may split slices incorrectly for multiband data
  • Check dim4 (number of volumes) matches expectations
  • Verify SliceTiming is correct for the multiband factor
Raw lines 455 to 459
460### Dual-echo fieldmaps
461- Siemens stores both echoes in one series; dcm2niix splits them
462- GE/Philips may store them as separate series
463- Verify `EchoTime1` < `EchoTime2` in the phasediff sidecar

Dual-echo fieldmaps

  • Siemens stores both echoes in one series; dcm2niix splits them
  • GE/Philips may store them as separate series
  • Verify EchoTime1 < EchoTime2 in the phasediff sidecar
Raw lines 460 to 464
465### Phase encoding direction
466- DICOM `InPlanePhaseEncodingDirection` → BIDS `PhaseEncodingDirection`
467- Mapping depends on acquisition orientation and NIfTI axis conventions
468- **Always verify** by checking the actual distortion pattern in the images

Phase encoding direction

  • DICOM InPlanePhaseEncodingDirection → BIDS PhaseEncodingDirection
  • Mapping depends on acquisition orientation and NIfTI axis conventions
  • Always verify by checking the actual distortion pattern in the images
Raw lines 465 to 469
470### Multi-run numbering
471- Ensure runs are numbered sequentially (`run-01`, `run-02`)
472- HeuDiConv: use `{item:02d}` placeholder
473- dcm2bids: review automatic duplicate-run assignment or supply `custom_entities`; `--auto_extract_entities` does not mean generic run-number detection

Multi-run numbering

  • Ensure runs are numbered sequentially (run-01, run-02)
  • HeuDiConv: use {item:02d} placeholder
  • dcm2bids: review automatic duplicate-run assignment or supply custom_entities; --auto_extract_entities does not mean generic run-number detection
Raw lines 470 to 474
475### Derived/processed series
476- Scanners may export inline-processed data (e.g., motion-corrected, distortion-corrected)
477- Review series against the BIDS suffix rules; some scanner derivatives are allowed (for example specific DWI-derived maps)
478- Use `is_derived`, `is_motion_corrected` and `image_type` as evidence; do not blindly exclude all `DERIVED` series because valid fieldmaps and reconstructed images may use that flag

Derived/processed series

  • Scanners may export inline-processed data (e.g., motion-corrected, distortion-corrected)
  • Review series against the BIDS suffix rules; some scanner derivatives are allowed (for example specific DWI-derived maps)
  • Use is_derived, is_motion_corrected and image_type as evidence; do not blindly exclude all DERIVED series because valid fieldmaps and reconstructed images may use that flag
Raw lines 475 to 479
480## Version and execution boundaries
482Reviewed 2026-09-30 against HeuDiConv 1.5.1 installed source, dcm2bids 3.3.1
483[configuration documentation](https://unfmontreal.github.io/Dcm2Bids/3.3.1/how-to/create-config-file/)
484and installed source, and BIDScoin 4.6.2
485[installation](https://bidscoin.readthedocs.io/en/stable/installation.html) and
486[workflow](https://bidscoin.readthedocs.io/en/stable/workflow.html) documentation.
487HeuDiConv's rendered latest docs still identify 1.4.0; the tagged
488[1.5.1 source](https://github.com/nipy/heudiconv/tree/v1.5.1) resolves that discrepancy.
489CLI help and synthetic mapping tests were run. Full scanner conversion and the
490BIDScoin GUI examples remain illustrative and require local acquisition verification.

Version and execution boundaries

Reviewed 2026-09-30 against HeuDiConv 1.5.1 installed source, dcm2bids 3.3.1 configuration documentation and installed source, and BIDScoin 4.6.2 installation and workflow documentation. HeuDiConv's rendered latest docs still identify 1.4.0; the tagged 1.5.1 source resolves that discrepancy. CLI help and synthetic mapping tests were run. Full scanner conversion and the BIDScoin GUI examples remain illustrative and require local acquisition verification.

Raw lines 480 to 490