DCMTK 命令行参考 是做什么的?
DCMTK 是 OFFIS DICOM 工具包——一个成熟的、BSD 许可的参考实现,涵盖了 DICOM 标准的大部分内容。本技能涵盖其命令行工具(C++ API 不在讨论范围内)。
如果你能用 DICOM 做某事,那么很可能存在一个对应的 dcm* 二进制文件。
难点在于:该工具集非常庞大(约 70 个二进制文件,分布在 12 个模块中),并且标志约定(-x 与 +x 是不同的标志)令人惊讶。本技能的存在是为了让 AI 代理能够选择正确的工具,在第一次尝试时写出正确的调用,并避开经典的 DCMTK 陷阱。
心智模型
DCMTK 根据工具所涉及的内容将工具分组到模块中:
dcmdata 磁盘上的 DICOM 文件:解析、转储、修改、编码/解码(无网络)
dcmnet TCP 上的 DIMSE:ECHO、STORE、FIND、MOVE、GET
dcmimage 将 DICOM 像素数据渲染为常见图像格式(PNG/PNM/BMP/TIFF)
dcmjpeg DICOM 像素数据的 JPEG(DCT)压缩/解压缩
dcmjpls DICOM 像素数据的 JPEG-LS 压缩/解压缩
dcmsr 结构化报告:转储、渲染、与 XML 进行往返转换
dcmqrdb 一个小型的独立查询/检索数据库服务器(测试 PACS)+ 索引器
dcmwlm 一个小型的独立模态工作列表服务器
dcmsign DICOM 数字签名(签名/验证/移除)
dcmrt 放射治疗对象检查(RT 计划/结构/剂量等)
dcmpstat 呈现状态 + 打印 SCP/SCU(高级;此处不讨论)
dcmtls TLS 支持(由 dcmnet 工具使用;本身不是工具)
一旦你看到 CLI 命名,它是一致的:编码工具以 dcmc* 开头(dcmcjpeg、dcmcjpls、dcmcrle);解码工具以 dcmd* 开头(dcmdjpeg、dcmdjpls、dcmdrle);SCU 以 *scu 结尾(网络客户端),SCP 以 *scp 结尾(网络服务器)。
DIMSE 服务映射
服务类 操作 SCU 工具 SCP 工具
─────────────────────────────────────────────────────────────────
验证 C-ECHO echoscu storescp 接受
存储 C-STORE storescu, dcmsend storescp, dcmrecv
查询/检索 C-FIND findscu dcmqrscp
C-MOVE movescu dcmqrscp
C-GET getscu dcmqrscp
工作列表 C-FIND findscu (使用 -W) wlmscpfs
对于真正的 PACS,你会使用 Orthanc / DCM4CHEE / ConQuest 作为 SCP。DCMTK 自己的 SCP(dcmqrscp、wlmscpfs)用于测试和集成脚手架。
标志前缀约定
-x 始终是一个互斥选择(多种模式中的一种)
+x 始终打开某个功能或添加某些内容
--x -x 或 +x 的长格式;语义相同
所以 -xe(提议小端)和 +e1(编码 JPEG Baseline)不相关——不同的前缀,不同的工具族,不同的含义。
为任务选择合适的工具
| 你想要… | 工具 | 参考 |
|---|---|---|
| 验证 PACS 是否可达 | echoscu | dcmnet.md |
| 将 DICOM 文件发送到 PACS | dcmsend(或使用 storescu 进行精细 TS 控制) | dcmnet.md |
| 将 DICOM 接收到文件夹 | storescp(或 dcmrecv) | dcmnet.md |
| 查询 PACS(按 PatientID / Date / Accession) | findscu | dcmnet.md |
| 从 PACS 拉取研究 | movescu 或 getscu | dcmnet.md |
| 显示 DICOM 文件中的所有标签 | dcmdump | dcmdata.md |
| 在 DICOM 文件中查找一个标签 | dcmdump --search KEY | dcmdata.md |
| 匿名化/修改标签 | dcmodify | dcmdata.md |
| 将 DICOM 转换为 JSON | dcm2json | dcmdata.md |
| 将 DICOM 转换为 XML | dcm2xml | dcmdata.md |
| 验证文件是否为有效的 DICOM Part-10 | dcmftest | dcmdata.md |
| 为媒体交换构建 DICOMDIR | dcmmkdir(旧别名:dcmgpdir) | dcmdata.md |
| 更改传输语法(仅限未压缩) | dcmconv | dcmdata.md |
| 使用 JPEG 压缩 DICOM | dcmcjpeg | image-codecs.md |
| 解压缩 JPEG 编码的 DICOM | dcmdjpeg | image-codecs.md |
| 使用 JPEG-LS 压缩/解压缩 | dcmcjpls / dcmdjpls | image-codecs.md |
| 使用 RLE 压缩/解压缩 | dcmcrle / dcmdrle | dcmdata.md |
| 将 DICOM 渲染为 PNG / JPEG / TIFF / BMP / PNM | dcm2img | image-codecs.md |
| 调整 DICOM 图像大小 | dcmscale | image-codecs.md |
| 将 JPEG/PNG/BMP/TIFF 封装为 DICOM | img2dcm | img-pdf-import.md |
| 将 PDF(或 CDA/STL/OBJ)封装为封装的 DICOM | dcmencap(旧别名:pdf2dcm) | img-pdf-import.md |
| 从 DICOM 中提取嵌入的 PDF/CDA/STL/OBJ | dcmdecap(旧别名:dcm2pdf) | img-pdf-import.md |
| 转储结构化报告的内容树 | dsrdump | dcmsr.md |
| 将 SR 渲染为 HTML | dsr2html | dcmsr.md |
| 通过 XML 往返 SR | dsr2xml / xml2dsr | dcmsr.md |
| 搭建测试 PACS | dcmqrscp + dcmqridx | dcmqrdb-wlm.md |
| 搭建测试模态工作列表服务器 | wlmscpfs | dcmqrdb-wlm.md |
| 签名/验证 DICOM 数字签名 | dcmsign | dcmsign-dcmrt.md |
| 检查 RT 计划/结构/剂量对象 | drtdump | dcmsign-dcmrt.md |
有关共享标志(日志记录、网络、TLS、传输语法协商、文件格式),请参阅 common-options.md。有关传输语法 UID 和匹配的 -x* / +t* 标志,请参阅 transfer-syntax-uids.md。
顶级配方
下面的示例使用这些占位符——将它们替换为目标环境的实际值:
PACS_HOST 对端 PACS 的主机名或 IP 例如 pacs.hospital.local
PACS_PORT 对端的 DICOM TCP 端口 例如 104、4242、11112
PACS_AET 被调用的 AE 标题 — 必须与对端的配置匹配 例如 MAIN_PACS
MY_AET 我们自己的调用 AE 标题 例如 ACME_SCU
1. 验证 PACS 是否可达(C-ECHO)
echoscu -v PACS_HOST PACS_PORT -aec PACS_AET -aet MY_AET
成功时显示 Received Echo Response (Success)。如果你看到 Association Rejected,说明对端不识别你的 -aec AE 标题,或者你的 IP 未在其配置的白名单中。
2. 将 DICOM 文件发送到 PACS(C-STORE)
单个文件,完全 TS 控制:
storescu -v PACS_HOST PACS_PORT -aec PACS_AET -aet MY_AET input.dcm
文件夹,递归,成功时按文件重命名:
dcmsend -v PACS_HOST PACS_PORT -aec PACS_AET -aet MY_AET +sd +r /path/to/studies/
何时使用哪个:
storescu— 经过实战检验,完全通过-x*控制 TS 协商,没有内置的“扫描文件夹”模式(除了+sd +r)。当你需要精确控制提议哪些 TS 时使用它。dcmsend— 更新、更简单。处理目录扫描、状态摘要、.done/.bad重命名。建议用于向已知对端批量发送的默认选项。
常见失败:Association Aborted: presentation context not supported。对端不接受文件编码所用的 SOP 类或 TS。使用 -d 运行以查看协商过程;提供的 AC 与接受的 AC 会让问题显而易见。
3. 将 DICOM 接收到文件夹(C-STORE SCP)
storescp -v -aet MY_AET --output-directory /path/to/incoming/ \
--sort-conc-studies study_ PACS_PORT
文件到达 /path/to/incoming/study_<StudyInstanceUID>/ 下。
对于更灵活的文件名模板和基于研究的事后处理钩子,dcmrecv 是更现代的替代方案——同样的理念,更简单的配置:
dcmrecv -v --output-directory /path/to/incoming/ PACS_PORT
4. 查询 PACS(C-FIND)
C-FIND 查询由 -k 键构建:每个 -k 要么约束搜索(-k "(0010,0020)=PATIENT_ID"),要么请求返回该属性(-k "(0010,0010)" 且值为空)。
某个患者的所有研究:
findscu -v -S \
-k "(0008,0052)=STUDY" \
-k "(0010,0020)=PATIENT_ID" \
-k "(0010,0010)" \
-k "(0020,000D)" \
-k "(0008,0020)" \
PACS_HOST PACS_PORT -aec PACS_AET -aet MY_AET
需要了解的标志:
-S研究根模型(默认且最常见);-P患者根;-W工作列表(0008,0052)QueryRetrieveLevel——必须与模型匹配(STUDY/SERIES/IMAGE)- 每个带值的
-k进行约束;每个不带值(只有标签)的-k请求 SCP 返回它
5. 检索研究(C-MOVE)
C-MOVE 请求 SCP 将实例推送到目标 AE——这意味着目标必须是 SCP 可达的正在运行的 storescp/dcmrecv,并且目标的 AE 标题必须在 SCP 上预先注册。
终端 A — 启动本地监听器:
storescp -v --output-directory ./retrieved/ -aet MY_AET 11112
终端 B — 发出 C-MOVE(目标 = 我们在端口 11112 上的 MY_AET):
movescu -v -S \
-k "(0008,0052)=STUDY" \
-k "(0020,000D)=1.2.3.4.5.STUDY.UID" \
-aem MY_AET \
PACS_HOST PACS_PORT -aec PACS_AET -aet MY_AET
如果 PACS 在其配置中没有 MY_AET 的条目,则移动失败并显示 Move Destination Unknown。movescu 本身也可以作为从属监听器运行,使用 --port 11112 --output-directory ./out/——对于你不想单独启动 storescp 终端的测试很有用。
对于 SCP 根本不需要知道你的监听器的点对点检索,C-GET(getscu)更简单:
getscu -v -S -k "(0008,0052)=STUDY" -k "(0020,000D)=1.2.3.4.5.STUDY.UID" \
--output-directory ./retrieved/ \
PACS_HOST PACS_PORT -aec PACS_AET
但许多生产 PACS 不支持 C-GET——C-MOVE 是更安全的默认选择。
6. 转储文件中的标签
整个文件,每个标签:
dcmdump input.dcm
仅一个标签(按名称或按组/元素):
dcmdump --search PatientID input.dcm
dcmdump --search "0010,0010" input.dcm
输出是每行一个属性:
(0010,0010) PN [DOE^JANE] # 8, 1 PatientName
列:标签、VR、值、长度、值多重性、属性名称。
要递归进入序列项(例如,读取结构化报告树),添加 +R。要跳过原始像素数据转储,添加 --max-read-length 4。dcmdump 的输出可以被 dump2dcm 解析回 DICOM,以进行往返编辑。
7. 匿名化/修改标签
dcmodify 原地修改(除非使用 -nb,否则会创建 .bak 备份):
# 在所有出现的地方替换 PatientName(主集合 + 每个序列项)
dcmodify -nb -ma "(0010,0010)=ANON^PATIENT" input.dcm
# 插入一个不存在的标签
dcmodify -nb -i "(0010,4000)=anonymized 2026-05-25" input.dcm
# 删除所有私有标签(组号为奇数)
dcmodify -nb -ep input.dcm
# 为研究/序列/实例层次结构生成新的 UID
dcmodify -nb -gst -gse -gsi input.dcm
操作标志(每个标签互斥):
-i如果不存在则插入(如果存在则报错)-m如果存在则修改(如果不存在则报错)-ma全部修改(主集合 + 每个序列项)-e擦除 /-ea全部擦除 /-ep擦除私有标签-gst-gse-gsi重新生成 Study/Series/SOPInstance UID
陷阱: 默认情况下,dcmodify 会为每个修改的文件写入一个 .bak。在 10k 文件匿名化时,这会使磁盘使用量翻倍,并且在批处理中几乎总是不需要的——始终为批处理传递 -nb。
8. 将 DICOM 渲染为 PNG / JPEG / TIFF / BMP / PNM
dcm2img +on input.dcm out.png # PNG(8 位)
dcm2img +on2 input.dcm out.png # PNG(16 位——保持完整位深)
dcm2img +oj input.dcm out.jpg # JPEG(8 位有损基线)
dcm2img +ot input.dcm out.tiff # TIFF
dcm2img +ob input.dcm out.bmp # BMP
dcm2img +op input.dcm out.pgm # PNM 原始格式(灰度用 PGM,彩色用 PPM)
dcm2img 标志字母约定:+o<字母> 选择输出格式(n=PNG、j=JPEG、t=TIFF、b=BMP、p=PNM/PGM/PPM、l=JPEG-LS)。+oa(--write-auto)根据输出文件扩展名选择。
dcm2img 会自动解压缩 JPEG / JPEG-LS / RLE 输入——无需单独的 dcmdjpeg 步骤。对于多帧数据,+Fa 为每帧写入一个输出文件(文件名会附加帧号后缀)。
如果你需要控制窗宽窗位,而不是让 dcm2img 使用文件的 VOI LUT:
dcm2img +on +Wm input.dcm out.png # 使用像素的最小/最大值作为窗宽窗位
dcm2img +on +W 50 350 input.dcm out.png # WindowCenter=50, WindowWidth=350
dcm2pnm、dcmj2pnm、dcml2pnm 是 dcm2img 的已弃用别名。