dicom-processing
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseDICOM Processing
DICOM 处理
Overview
概述
Pipeline skill for converting, reading, and de-identifying medical images in DICOM and NIfTI formats. Encodes deterministic commands and code for:
- DICOM → NIfTI conversion with (including BIDS sidecars)
dcm2niix - Reading DICOM headers and pixel data with
pydicom - PHI removal (de-identification) with or CTP DicomAnonymizer
pydicom - NIfTI inspection with
nibabel - Batch processing grouped by
SeriesInstanceUID - BIDS-compliant directory organization
Use this skill whenever the user works with , , , DICOM directories, or anonymization workflows.
.dcm.nii.nii.gz用于转换、读取和去标识化 DICOM 与 NIfTI 格式医学图像的流水线 skill。为以下任务提供确定性命令和代码:
- 使用 将 DICOM 转换为 NIfTI(包括 BIDS sidecar)
dcm2niix - 使用 读取 DICOM 头信息和像素数据
pydicom - 使用 或 CTP DicomAnonymizer 移除 PHI(去标识化)
pydicom - 使用 检查 NIfTI
nibabel - 按 分组进行批处理
SeriesInstanceUID - 构建符合 BIDS 的目录结构
当用户处理 、、、DICOM 目录或去标识化工作流时,请使用此 skill。
.dcm.nii.nii.gzUsage
使用方法
1. Convert a DICOM series to NIfTI (dcm2niix)
1. 将 DICOM 序列转换为 NIfTI(dcm2niix)
bash
undefinedbash
undefinedStandard conversion: gzip output, BIDS sidecar, pattern-named files
Standard conversion: gzip output, BIDS sidecar, pattern-named files
dcm2niix -z y -b y -f %p_%s -o output_dir input_dir
Flags (memorize):
| Flag | Meaning |
| --- | --- |
| `-z y` | gzip output (`.nii.gz`) |
| `-b y` | emit BIDS JSON sidecar |
| `-f %p_%s` | filename pattern: `%p` = protocol, `%s` = series number |
| `-m n` | do NOT merge 2D slices across series (prevents cross-series mixing) |
| `-o` | output directory |
Common naming tokens: `%p` protocol, `%s` series, `%t` time, `%i` patient ID, `%n` patient name, `%d` description.dcm2niix -z y -b y -f %p_%s -o output_dir input_dir
参数(需记忆):
| 参数 | 含义 |
| --- | --- |
| `-z y` | gzip 输出(`.nii.gz`) |
| `-b y` | 输出 BIDS JSON sidecar |
| `-f %p_%s` | 文件名模式:`%p` = protocol,`%s` = series number |
| `-m n` | 不跨序列合并 2D 切片(防止混合不同序列) |
| `-o` | 输出目录 |
常用命名标记:`%p` protocol、`%s` series、`%t` time、`%i` patient ID、`%n` patient name、`%d` description。2. Read a DICOM file with pydicom
2. 使用 pydicom 读取 DICOM 文件
python
import pydicom
ds = pydicom.dcmread('file.dcm')
print(ds.PatientName, ds.StudyDate, ds.Modality)
print(ds.pixel_array.shape) # numpy array of pixel datapython
import pydicom
ds = pydicom.dcmread('file.dcm')
print(ds.PatientName, ds.StudyDate, ds.Modality)
print(ds.pixel_array.shape) # numpy array of pixel data3. De-identify a DICOM file (pydicom)
3. 使用 pydicom 对 DICOM 文件进行去标识化
python
import pydicom
from pydicom.uid import generate_uid
ds = pydicom.dcmread('file.dcm')
tags_to_remove = [
'PatientName', 'PatientID', 'PatientBirthDate',
'InstitutionName', 'ReferringPhysicianName', 'StudyDate',
]
for tag in tags_to_remove:
if tag in ds:
del ds[tag]
ds.PatientID = 'ANON_001'python
import pydicom
from pydicom.uid import generate_uid
ds = pydicom.dcmread('file.dcm')
tags_to_remove = [
'PatientName', 'PatientID', 'PatientBirthDate',
'InstitutionName', 'ReferringPhysicianName', 'StudyDate',
]
for tag in tags_to_remove:
if tag in ds:
del ds[tag]
ds.PatientID = 'ANON_001'Remove private (vendor) tags — they frequently contain PHI
Remove private (vendor) tags — they frequently contain PHI
ds.remove_private_tags()
ds.remove_private_tags()
Replace UIDs so the study/series/instance cannot be linked back
Replace UIDs so the study/series/instance cannot be linked back
ds.StudyInstanceUID = generate_uid()
ds.SeriesInstanceUID = generate_uid()
ds.SOPInstanceUID = generate_uid()
ds.save_as('anon.dcm')
undefinedds.StudyInstanceUID = generate_uid()
ds.SeriesInstanceUID = generate_uid()
ds.SOPInstanceUID = generate_uid()
ds.save_as('anon.dcm')
undefined4. Batch de-identification with CTP DicomAnonymizer
4. 使用 CTP DicomAnonymizer 进行批量去标识化
bash
undefinedbash
undefinedRSNA CTP / DicomBrowser DAP (DICOM Anonymizer Program)
RSNA CTP / DicomBrowser DAP (DICOM Anonymizer Program)
java -jar DAP.jar -p profile.script -i input/ -o output/
Use this for large cohorts or when a validated DICOM Supplement 142 profile is required.java -jar DAP.jar -p profile.script -i input/ -o output/
对于大型队列,或需要使用经过验证的 DICOM Supplement 142 profile 时,请采用此方法。5. Load a NIfTI volume with nibabel
5. 使用 nibabel 加载 NIfTI volume
python
import nibabel as nib
img = nib.load('file.nii.gz')
data = img.get_fdata() # numpy ndarray
affine = img.affine # 4x4 voxel-to-world transform
header = img.headerpython
import nibabel as nib
img = nib.load('file.nii.gz')
data = img.get_fdata() # numpy ndarray
affine = img.affine # 4x4 voxel-to-world transform
header = img.header6. Batch pattern: group by SeriesInstanceUID, convert per series
6. 批处理模式:按 SeriesInstanceUID 分组并逐序列转换
python
from pathlib import Path
from collections import defaultdict
import pydicom, subprocess
def group_by_series(input_dir):
series = defaultdict(list)
for p in Path(input_dir).rglob('*.dcm'):
ds = pydicom.dcmread(p, stop_before_pixels=True)
series[ds.SeriesInstanceUID].append(p)
return series
def convert_all(input_dir, output_dir):
Path(output_dir).mkdir(parents=True, exist_ok=True)
# dcm2niix handles series grouping internally when given a directory
subprocess.run(
['dcm2niix', '-z', 'y', '-b', 'y', '-f', '%p_%s',
'-o', output_dir, input_dir],
check=True,
)python
from pathlib import Path
from collections import defaultdict
import pydicom, subprocess
def group_by_series(input_dir):
series = defaultdict(list)
for p in Path(input_dir).rglob('*.dcm'):
ds = pydicom.dcmread(p, stop_before_pixels=True)
series[ds.SeriesInstanceUID].append(p)
return series
def convert_all(input_dir, output_dir):
Path(output_dir).mkdir(parents=True, exist_ok=True)
# dcm2niix handles series grouping internally when given a directory
subprocess.run(
['dcm2niix', '-z', 'y', '-b', 'y', '-f', '%p_%s',
'-o', output_dir, input_dir],
check=True,
)7. BIDS organization
7. BIDS 目录组织
dataset/
├── dataset_description.json
├── participants.tsv
└── sub-01/
└── ses-01/
├── anat/ sub-01_ses-01_T1w.nii.gz
├── func/ sub-01_ses-01_task-rest_bold.nii.gz
└── dwi/ sub-01_ses-01_dwi.nii.gzRule: , with a matching sidecar.
sub-<label>/ses-<label>/<modality>/<sub>_<ses>_<suffix>.nii.gz.jsondataset/
├── dataset_description.json
├── participants.tsv
└── sub-01/
└── ses-01/
├── anat/ sub-01_ses-01_T1w.nii.gz
├── func/ sub-01_ses-01_task-rest_bold.nii.gz
└── dwi/ sub-01_ses-01_dwi.nii.gz规则:,并提供匹配的 sidecar。
sub-<label>/ses-<label>/<modality>/<sub>_<ses>_<suffix>.nii.gz.jsonResponse Format
响应格式
- Lead with the command or code the user needs — explain after
- Structure as: confirm inputs → working code → key parameters explained → gotchas
- One complete working example per task; do not show every alternative
- Keep code comments minimal and functional (what, not why-it-exists)
- Target: 50-100 lines of code with brief surrounding explanation
- 先给出用户所需的命令或代码,之后再进行解释
- 按以下结构组织:确认输入 → 可运行代码 → 关键参数说明 → 注意事项
- 每项任务提供一个完整可运行示例;不要展示每一种替代方案
- 保持代码注释精简且实用(说明做什么,而非为什么需要)
- 目标:提供 50–100 行代码及简短 surrounding explanation
Core Concepts
核心概念
Format and De-identification Decision Tree
格式与去标识化决策树
What is the target format?
├─ NIfTI (analysis) → dcm2niix -z y -b y
│ ├─ Need BIDS layout? → add -f sub-%i_ses-%t_%p, reorganize post-hoc
│ └─ Single series only? → point dcm2niix at series directory directly
└─ DICOM (archive/PACS) → pydicom read/write
De-identification method:
├─ Small cohort (< 100 studies) → pydicom script (remove tags + private + replace UIDs)
├─ Large cohort or regulatory → CTP DicomAnonymizer with Supplement 142 profile
└─ Burned-in pixel PHI risk?
├─ US / Secondary Capture / Screenshots → YES: add OCR + pixel masking step
└─ CT / MR / PT → Usually NO: tag-level de-ID sufficientDICOM hierarchy. . A "series" is the atomic unit for conversion — one NIfTI volume typically corresponds to one .
Patient → Study → Series → InstanceSeriesInstanceUIDUIDs are identifiers, not secrets, but they are linkable. Two files sharing a came from the same exam. De-identification must replace UIDs () to break linkage across releases.
StudyInstanceUIDgenerate_uid()Private tags carry PHI. Vendor-specific tags (odd group numbers) often embed operator notes, patient IDs, or burned-in metadata. Always call .
ds.remove_private_tags()Pixel data can contain PHI too. Ultrasound frames, secondary captures, and screenshots frequently have burned-in patient name/MRN in the pixels. Tag removal does not scrub pixels — run OCR + masking separately when this risk applies.
Key DICOM tags for geometry and modality:
| Tag | Name | Purpose |
|---|---|---|
| Modality | CT / MR / CR / US / PT ... |
| SliceThickness | mm |
| PixelSpacing | in-plane spacing |
| ImagePositionPatient | origin of slice in patient coords |
| ImageOrientationPatient | row/col direction cosines |
These five tags are sufficient to reconstruct the NIfTI matrix.
affineNIfTI vs DICOM. NIfTI stores a single 3D/4D volume with one affine; DICOM stores slice-level metadata. Converters () aggregate slices of a series and compute the affine from the tags above.
dcm2niixWhat is the target format?
├─ NIfTI (analysis) → dcm2niix -z y -b y
│ ├─ Need BIDS layout? → add -f sub-%i_ses-%t_%p, reorganize post-hoc
│ └─ Single series only? → point dcm2niix at series directory directly
└─ DICOM (archive/PACS) → pydicom read/write
De-identification method:
├─ Small cohort (< 100 studies) → pydicom script (remove tags + private + replace UIDs)
├─ Large cohort or regulatory → CTP DicomAnonymizer with Supplement 142 profile
└─ Burned-in pixel PHI risk?
├─ US / Secondary Capture / Screenshots → YES: add OCR + pixel masking step
└─ CT / MR / PT → Usually NO: tag-level de-ID sufficientDICOM 层级结构。 。“series”是转换的原子单位——一个 NIfTI volume 通常对应一个 。
Patient → Study → Series → InstanceSeriesInstanceUIDUID 是标识符,而不是机密,但它们是可关联的。 两个文件共享同一个 ,说明它们来自同一次检查。去标识化必须替换 UID(),以断开不同数据发布版本之间的关联。
StudyInstanceUIDgenerate_uid()私有标签可能包含 PHI。 厂商特定标签(奇数组号)经常嵌入操作人员备注、患者 ID 或烧录元数据。始终调用 。
ds.remove_private_tags()像素数据也可能包含 PHI。 超声帧、Secondary Capture 和截图经常在像素中烧录患者姓名或 MRN。移除标签无法清除像素中的 PHI;当存在此风险时,应单独运行 OCR 和掩膜处理。
用于几何和 modality 的关键 DICOM 标签:
| 标签 | 名称 | 用途 |
|---|---|---|
| Modality | CT / MR / CR / US / PT ... |
| SliceThickness | mm |
| PixelSpacing | 面内间距 |
| ImagePositionPatient | 患者坐标系中切片的原点 |
| ImageOrientationPatient | 行/列方向余弦 |
这五个标签足以重建 NIfTI 的 矩阵。
affineNIfTI 与 DICOM 的区别。 NIfTI 存储单个 3D/4D volume,并包含一个 affine;DICOM 则存储切片级元数据。转换器()会聚合一个 series 的切片,并根据上述标签计算 affine。
dcm2niixQuick Reference
快速参考
bash
undefinedbash
undefinedConvert
Convert
dcm2niix -z y -b y -f %p_%s -o out/ in/
dcm2niix -z y -b y -f %p_%s -o out/ in/
Skip merging across series (safer)
Skip merging across series (safer)
dcm2niix -z y -b y -m n -f %p_%s -o out/ in/
dcm2niix -z y -b y -m n -f %p_%s -o out/ in/
Batch anonymization (CTP)
Batch anonymization (CTP)
java -jar DAP.jar -p profile.script -i input/ -o output/
```pythonjava -jar DAP.jar -p profile.script -i input/ -o output/
```pythonRead DICOM
Read DICOM
ds = pydicom.dcmread('file.dcm')
ds.PatientName, ds.Modality, ds.pixel_array.shape
ds = pydicom.dcmread('file.dcm')
ds.PatientName, ds.Modality, ds.pixel_array.shape
Header-only (fast, no pixels)
Header-only (fast, no pixels)
ds = pydicom.dcmread('file.dcm', stop_before_pixels=True)
ds = pydicom.dcmread('file.dcm', stop_before_pixels=True)
Anonymize core fields
Anonymize core fields
for t in ['PatientName','PatientID','PatientBirthDate',
'InstitutionName','ReferringPhysicianName','StudyDate']:
if t in ds: del ds[t]
ds.remove_private_tags()
ds.StudyInstanceUID = generate_uid()
ds.SeriesInstanceUID = generate_uid()
ds.SOPInstanceUID = generate_uid()
for t in ['PatientName','PatientID','PatientBirthDate',
'InstitutionName','ReferringPhysicianName','StudyDate']:
if t in ds: del ds[t]
ds.remove_private_tags()
ds.StudyInstanceUID = generate_uid()
ds.SeriesInstanceUID = generate_uid()
ds.SOPInstanceUID = generate_uid()
Load NIfTI
Load NIfTI
img = nib.load('file.nii.gz'); data = img.get_fdata(); aff = img.affine
undefinedimg = nib.load('file.nii.gz'); data = img.get_fdata(); aff = img.affine
undefinedCommon Mistakes
常见错误
-
Wrong: Not removing private tags during DICOM de-identification Right: Always callas part of the de-identification pipeline Why: Vendor private tags (odd group numbers) routinely contain PHI that survives standard tag-level scrubbing
ds.remove_private_tags() -
Wrong: Keeping original UIDs after anonymization Right: Replace,
StudyInstanceUID, andSeriesInstanceUIDwithSOPInstanceUIDfor every de-identified file Why: Original UIDs are linkable back to the source PACS — two files sharing a StudyInstanceUID reveal they came from the same examgenerate_uid() -
Wrong: Using default dcm2niix merge behavior without verification Right: Useto disable merging, or inspect output file counts against the expected series list Why: Default merging can combine distinct acquisitions into one NIfTI volume, corrupting the data
-m n -
Wrong: Ignoring burned-in annotations in pixel data during de-identification Right: Add an OCR detection and pixel masking step for ultrasound, secondary capture, and screenshot modalities Why: Tag-level de-identification does not scrub pixels — patient name/MRN burned into the image persists after tag removal
-
Wrong: Outputting uncompressedfiles from dcm2niix Right: Always pass
.niito dcm2niix for gzipped-z youtput unless downstream tools explicitly require uncompressed Why: Uncompressed NIfTI files are 3-5× larger, wasting storage and slowing transfers with no benefit for most pipelines.nii.gz -
Wrong: Reading full pixel data when only DICOM headers are needed Right: Usefor metadata-only scans Why: Loading pixel arrays for large cohorts wastes memory and time when only tags like Modality, SeriesInstanceUID, or SliceThickness are needed
pydicom.dcmread(path, stop_before_pixels=True) -
Wrong: Treating DICOMDIR as a file directory and iterating its entries Right: Iterate actualfiles using
.dcminstead Why: DICOMDIR is an index file with its own structure — it may be incomplete, outdated, or absent; direct file iteration is more reliablePath(input_dir).rglob('*.dcm')
-
错误: DICOM 去标识化期间未删除私有标签 正确: 始终将纳入去标识化流水线 原因: 厂商私有标签(奇数组号)经常包含 PHI,即使执行标准标签级清理也仍会残留
ds.remove_private_tags() -
错误: 匿名化后保留原始 UID 正确: 对每个去标识化文件,使用替换
generate_uid()、StudyInstanceUID和SeriesInstanceUID原因: 原始 UID 可以关联回源 PACS——两个文件共享同一个 StudyInstanceUID,意味着它们来自同一次检查SOPInstanceUID -
错误: 未经验证即使用 dcm2niix 的默认合并行为 正确: 使用禁用合并,或将输出文件数量与预期 series 列表进行核对 原因: 默认合并可能把不同的采集数据组合到一个 NIfTI volume 中,从而破坏数据
-m n -
错误: 去标识化时忽略像素数据中烧录的标注信息 正确: 对 ultrasound、Secondary Capture 和 screenshot modality 增加 OCR 检测和像素掩膜步骤 原因: 标签级去标识化无法清除像素——烧录在图像中的患者姓名/MRN 在移除标签后仍会保留
-
错误: dcm2niix 输出未压缩的文件 正确: 除非下游工具明确要求未压缩格式,否则始终向 dcm2niix 传递
.nii,以生成 gzip 压缩的-z y输出 原因: 未压缩的 NIfTI 文件会大 3–5 倍,在大多数流水线中没有任何收益,却会浪费存储空间并降低传输速度.nii.gz -
错误: 只需要 DICOM 头信息时仍读取完整像素数据 正确: 使用扫描纯元数据 原因: 对大型队列加载 pixel array 会浪费内存和时间,尤其是在只需要 Modality、SeriesInstanceUID 或 SliceThickness 等标签时
pydicom.dcmread(path, stop_before_pixels=True) -
错误: 将 DICOMDIR 当作文件目录并遍历其中的条目 正确: 使用遍历实际的
Path(input_dir).rglob('*.dcm')文件 原因: DICOMDIR 是具有特定结构的索引文件——它可能不完整、已过期或不存在;直接遍历文件更加可靠.dcm
References
参考资料
- dcm2niix: Li et al. J Neurosci Methods 2016, https://doi.org/10.1016/j.jneumeth.2016.03.001
- pydicom: https://pydicom.github.io/pydicom/stable/
- BIDS: Gorgolewski et al. Sci Data 2016, https://doi.org/10.1038/sdata.2016.44
- DICOM de-identification: DICOM PS3.15 Annex E, https://dicom.nema.org/medical/dicom/current/output/chtml/part15/chapter_E.html
- dcm2niix:Li 等,J Neurosci Methods 2016,https://doi.org/10.1016/j.jneumeth.2016.03.001
- pydicom:https://pydicom.github.io/pydicom/stable/
- BIDS:Gorgolewski 等,Sci Data 2016,https://doi.org/10.1038/sdata.2016.44
- DICOM 去标识化:DICOM PS3.15 Annex E,https://dicom.nema.org/medical/dicom/current/output/chtml/part15/chapter_E.html