关于 dicom-processing
面向处理 DICOM 和 NIfTI 医学影像的流程技能,提供转换、读取与去标识化指导。涵盖批量按序列处理及 BIDS 目录组织。
主要功能
- 01DICOM 转 NIfTI 并生成 BIDS 侧车文件
- 02读取 DICOM 头信息与像素数据
- 03移除 PHI 并处理私有标签
- 04检查 NIfTI 体积与仿射矩阵
- 05按 SeriesInstanceUID 批量处理
适用场景
- 01将 DICOM 序列转换为压缩 NIfTI
- 02检查医学影像的头信息和像素
- 03对单个或大型队列进行去标识化
- 04按 BIDS 规范整理影像数据集
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ awslabs/ hcls-agent-skills --skill dicom-processing安装后在 Claude Code 中输入/dicom-processing确认已加载。
详细介绍
DICOM 处理
概述
用于转换、读取和去标识化 DICOM 与 NIfTI 格式医学图像的流水线技能。提供确定性的命令和代码,用于:
- 使用
dcm2niix将 DICOM 转换为 NIfTI(包括 BIDS 辅助文件) - 使用
pydicom读取 DICOM 头信息和像素数据 - 使用
pydicom或 CTP DicomAnonymizer 移除 PHI(去标识化) - 使用
nibabel检查 NIfTI - 按
SeriesInstanceUID分组进行批处理 - 按 BIDS 规范组织目录
当用户处理 .dcm、.nii、.nii.gz、DICOM 目录或匿名化工作流时,请使用此技能。
用法
1. 将 DICOM 序列转换为 NIfTI(dcm2niix)
# Standard conversion: gzip output, BIDS sidecar, pattern-named files
dcm2niix -z y -b y -f %p_%s -o output_dir input_dir
标志(请记住):
| 标志 | 含义 |
|---|---|
-z y | 输出 gzip 文件(.nii.gz) |
-b y | 生成 BIDS JSON 辅助文件 |
-f %p_%s | 文件名模式:%p = 协议,%s = 序列号 |
-m n | 不要合并跨序列的 2D 切片(防止不同序列混合) |
-o | 输出目录 |
常见命名标记:%p 协议,%s 序列,%t 时间,%i 患者 ID,%n 患者姓名,%d 描述。
2. 使用 pydicom 读取 DICOM 文件
import pydicom
ds = pydicom.dcmread('file.dcm')
print(ds.PatientName, ds.StudyDate, ds.Modality)
print(ds.pixel_array.shape) # numpy array of pixel data
3. 使用 pydicom 对 DICOM 文件进行去标识化
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
ds.remove_private_tags()
# 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')
4. 使用 CTP DicomAnonymizer 批量去标识化
# RSNA CTP / DicomBrowser DAP (DICOM Anonymizer Program)
java -jar DAP.jar -p profile.script -i input/ -o output/
适用于大型队列,或需要经过验证的 DICOM Supplement 142 配置文件的情况。
5. 使用 nibabel 加载 NIfTI 体数据
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.header
6. 批处理模式:按 SeriesInstanceUID 分组,逐序列转换
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 目录组织
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.gz
规则:sub-<label>/ses-<label>/<modality>/<sub>_<ses>_<suffix>.nii.gz,并配有匹配的 .json 辅助文件。
响应格式
- 先给出用户需要的命令或代码,再进行解释
- 结构为:确认输入 → 可运行的代码 → 说明关键参数 → 注意事项
- 每项任务提供一个完整可运行的示例;不要列出所有替代方案
- 代码注释应精简且实用(说明作用,而非存在原因)
- 目标:50–100 行代码,并附简短说明
核心概念
格式与去标识化决策树
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 sufficient
DICOM 层级。 Patient → Study → Series → Instance。“序列”是转换的基本单位——一个 NIfTI 体数据通常对应一个 SeriesInstanceUID。
UID 是标识符,不是机密信息,但可以用于关联。 两个文件若具有相同的 StudyInstanceUID,则来自同一次检查。去标识化必须替换 UID(generate_uid()),以断开不同发布版本之间的关联。
私有标签可能包含 PHI。 特定厂商的标签(奇数群组号)通常会嵌入操作员备注、患者 ID 或烧录的元数据。务必调用 ds.remove_private_tags()。
像素数据也可能包含 PHI。 超声影像、二次捕获图像和屏幕截图中经常会在像素内烧录患者姓名/MRN。移除标签并不会清除像素——存在此类风险时,应另外运行 OCR 并进行遮罩处理。
几何和模态相关的重要 DICOM 标签:
| 标签 | 名称 | 用途 |
|---|---|---|
(0008,0060) | Modality | CT / MR / CR / US / PT ... |
(0018,0050) | SliceThickness | mm |
(0028,0030) | PixelSpacing | 面内间距 [row, col] mm |
(0020,0032) | ImagePositionPatient | 切片在患者坐标系中的原点 |
(0020,0037) | ImageOrientationPatient | 行/列方向余弦 |
这五个标签足以重建 NIfTI affine 矩阵。
NIfTI 与 DICOM。 NIfTI 将一个 3D/4D 体数据及其单个 affine 矩阵存储在一起;DICOM 则存储切片级元数据。转换器(dcm2niix)会汇总一个序列中的切片,并根据上述标签计算 affine 矩阵。
快速参考
# Convert
dcm2niix -z y -b y -f %p_%s -o out/ in/
# Skip merging across series (safer)
dcm2niix -z y -b y -m n -f %p_%s -o out/ in/
# Batch anonymization (CTP)
java -jar DAP.jar -p profile.script -i input/ -o output/
# Read DICOM
ds = pydicom.dcmread('file.dcm')
ds.PatientName, ds.Modality, ds.pixel_array.shape
# Header-only (fast, no pixels)
ds = pydicom.dcmread('file.dcm', stop_before_pixels=True)
# 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()
# Load NIfTI
img = nib.load('file.nii.gz'); data = img.get_fdata(); aff = img.affine
常见错误
-
错误: DICOM 去标识化时未移除私有标签 正确做法: 始终在去标识化流程中调用
ds.remove_private_tags()原因: 厂商私有标签(奇数群组号)通常包含 PHI,标准的标签级清理无法将其移除 -
错误: 匿名化后保留原始 UID 正确做法: 对每个去标识化文件,使用
generate_uid()替换StudyInstanceUID、SeriesInstanceUID和SOPInstanceUID原因: 原始 UID 可关联回源 PACS——两个文件共享同一个 StudyInstanceUID,就能看出它们来自同一次检查 -
错误: 使用 dcm2niix 默认的合并行为而不进行验证 正确做法: 使用
-m n禁用合并,或根据预期序列列表检查输出文件数量 原因: 默认合并可能会将不同的采集数据合并到一个 NIfTI 体积中,导致数据损坏 -
错误: 去标识化时忽略像素数据中烧录的注释 正确做法: 对超声、二次捕获和截图模态,添加 OCR 检测和像素遮罩步骤 原因: 标签级去标识化不会清理像素——标签移除后,烧录在图像中的患者姓名/MRN 仍然存在
-
错误: 从 dcm2niix 输出未压缩的
.nii文件 正确做法: 始终向 dcm2niix 传递-z y,以输出经过 gzip 压缩的.nii.gz文件,除非下游工具明确要求未压缩文件 原因: 未压缩的 NIfTI 文件体积大 3–5 倍,会浪费存储空间并减慢传输速度,对大多数流程却没有任何好处 -
错误: 只需要 DICOM 头信息时仍读取完整像素数据 正确做法: 对于仅需元数据的扫描,使用
pydicom.dcmread(path, stop_before_pixels=True)原因: 对大型队列加载像素数组会浪费内存和时间,而实际上只需要 Modality、SeriesInstanceUID 或 SliceThickness 等标签 -
错误: 将 DICOMDIR 当作文件目录并遍历其中的条目 正确做法: 改用
Path(input_dir).rglob('*.dcm')遍历实际的.dcm文件 原因: DICOMDIR 是具有自身结构的索引文件,可能不完整、已过期或不存在;直接遍历文件更可靠
参考资料
- 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 附录 E,https://dicom.nema.org/medical/dicom/current/output/chtml/part15/chapter_E.html