---
title: "vxconvert DICOM-to-BIDS conversion"
description: "HeuDiConv wrapper architecture for DICOM→BIDS/NIfTI conversion, two-phase header/pixel split, custom grouping/classification, and vicom integration."
image: "https://docs.virdx.dev/img/virdx-social-card.png"
---

> Documentation Index
> Fetch the complete documentation index at: https://docs.virdx.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# vxconvert DICOM-to-BIDS conversion

vxconvert wraps HeuDiConv + dcm2niix to convert DICOM files into BIDS-organized NIfTI volumes with JSON sidecars. All paths below are relative to the `virdx/vxconvert` repo root.

## Two-phase pipeline

### Phase 1: Grouping + Classification (header-only)

1. **`validate_dicom()`** (from heudiconv) — reads each DICOM with `stop_before_pixels=True` to avoid pixel I/O during scanning.
2. **`filter_dicom()`** (`src/vxconvert/grouping.py`) — rejects non-MR, localizers, scouts, derived series. Typically filters ~30–50% of input files.
3. **`custom_grouping_study_then_seqname()`** (`src/vxconvert/grouping.py`) — groups by `StudyInstanceUID` → `SeriesInstanceUID`, with further splits on echo/TR when multiple are present.
4. **`custom_seqinfo()`** (`src/vxconvert/grouping.py`) — extracts ~40 metadata fields from DICOM headers into a custom `SeqInfo` tuple.
5. **`infotodict()`** (`src/vxconvert/infotodict.py`) — classifies each `SeqInfo` into BIDS modalities (anat/dwi/fmap/perf/func) using `SequenceClassifier`.

### Phase 2: Pixel conversion

dcm2niix reads full DICOM files (including pixels) per series → outputs NIfTI + JSON sidecars.

**Output structure**: `sub-{subject}/ses-{session}/{modality}/{filename}.nii.gz` + `.json`.

## vicom integration

Enable with `HEUDICONV_ENABLE_VICOM=true`. When enabled, **`postprocess_json()`** (`src/vxconvert/postprocessing.py`) calls **`vicom_adapter()`** to enrich JSON sidecars with Volume-compatible fields:

- Converts JSON keys to snake_case.
- Sets `volume_type` from BIDS suffix: `DWI`, `T1`, `T2`, `ADC`, `PM` (parametric maps), or `MISC`.
- Sets `is_trace` and `is_synthetic` flags for trace-weighted DWI and computed ADC maps.
- Extracts `b_value` / `adc_b_values` from filename patterns like `bval-1000` or `bval-0and1000`.
- Computes `image_plane`, `field_of_view`, `spacing` from the NIfTI affine matrix via vicom's `get_all_header_data`.
- **Timing normalization**:
  - `echo_time`: normalized to milliseconds internally, output in seconds.
  - `repetition_time`, `inversion_time`: converted from BIDS seconds to milliseconds (multiply by 1000).
- Renames: `study_instance_uid` → `study_identifier`, `series_instance_uid` → `series_identifier`, etc.

vicom must be installed separately (`pip install vicom`); raises `ImportError` if missing.

## Key files

- `src/vxconvert/grouping.py` — `filter_dicom`, `custom_seqinfo`, `custom_grouping_study_then_seqname`
- `src/vxconvert/infotodict.py` — `infotodict` classification logic
- `src/vxconvert/postprocessing.py` — `postprocess_json`, `vicom_adapter`
- `src/vxconvert/bids.py` — `SequenceClassifier`, `BidsEntities`
- `src/vxconvert/cli/convert.py` — CLI entrypoint, batch mode via `ProcessPoolExecutor`

## vxData integration (removed, 2026-04)

The old ingestion path that fed converted volumes into the data platform
(worker `f_20260409_vxconvert_volumes`) did not survive the `data-platform`
archive (2026-05-27) and has no successor in `mono/apps/vxdata-jobs`. The
target payload types themselves are alive and unchanged in
`mono/packages/vxdata-schemas/src/vxdata/schemas/payloads.py` (`ImagingStudy`,
`Volume`, incl. `Volume.sequence_name`) — so the sidecar fields `vicom_adapter`
emits still map onto current `Volume` fields. Only the job that did the
uploading is missing; vxconvert itself is a standalone converter today.

Source: https://docs.virdx.dev/knowledge/wiki/workstreams/infrastructure/sops/vxconvert-dicom-to-bids/index.mdx
