DCMTK 명령줄 레퍼런스
DCMTK는 OFFIS DICOM 툴킷으로, DICOM 표준의 주요 부분을 구현한 성숙한 BSD 라이선스 참조 구현체입니다. 이 스킬은 명령줄 도구를 다룹니다(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 소규모 독립형 Q/R 데이터베이스 서버(테스트 PACS) + 인덱서
dcmwlm 소규모 독립형 Modality Worklist 서버
dcmsign DICOM 디지털 서명 (서명/검증/제거)
dcmrt 방사선 치료 객체 검사 (RT Plan / Struct / Dose / 등)
dcmpstat 프레젠테이션 상태 + 인쇄 SCP/SCU (고급; 여기서 다루지 않음)
dcmtls TLS 지원 (dcmnet 도구에서 사용; 자체 도구 아님)
CLI 이름 지정은 패턴을 한 번 보면 일관적입니다: 인코딩하는 도구는 dcmc*로 시작하고 (dcmcjpeg, dcmcjpls, dcmcrle); 디코딩하는 도구는 dcmd*로 시작합니다 (dcmdjpeg, dcmdjpls, dcmdrle); SCU는 *scu로 끝나고 (네트워크 클라이언트) SCP는 *scp로 끝납니다 (네트워크 서버).
DIMSE 서비스 맵
서비스 클래스 작업 SCU 도구 SCP 도구
─────────────────────────────────────────────────────────────────
검증(Verification) C-ECHO echoscu storescp 수락
저장(Storage) C-STORE storescu, dcmsend storescp, dcmrecv
질의/검색(Query/Retrieve) C-FIND findscu dcmqrscp
C-MOVE movescu dcmqrscp
C-GET getscu dcmqrscp
작업 목록(Worklist) C-FIND findscu (-W 옵션 포함) wlmscpfs
실제 PACS의 경우 SCP로 Orthanc / DCM4CHEE / ConQuest를 사용합니다. DCMTK 자체 SCP(dcmqrscp, wlmscpfs)는 테스트 및 통합 환경 구축용입니다.
플래그 접두사 규칙
-x 항상 상호 배타적인 선택 (여러 모드 중 하나)
+x 항상 기능을 켜거나 무언가를 추가함
--x -x 또는 +x의 긴 형식; 동일한 의미
따라서 -xe (리틀 엔디언 제안)와 +e1 (JPEG Baseline 인코딩)은 서로 관련이 없습니다 — 다른 접두사, 다른 도구 제품군, 다른 의미입니다.
작업별 적합한 도구
| 원하는 작업 … | 도구 | 참조 |
|---|---|---|
| PACS에 연결 가능한지 확인 | echoscu | dcmnet.md |
| DICOM 파일을 PACS로 전송 | dcmsend (세밀한 TS 제어를 위해 storescu) | 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 |
| SR을 XML로 왕복 | dsr2xml / xml2dsr | dcmsr.md |
| 테스트 PACS 구축 | dcmqrscp + dcmqridx | dcmqrdb-wlm.md |
| 테스트 Modality Worklist 서버 구축 | wlmscpfs | dcmqrdb-wlm.md |
| DICOM 디지털 서명 서명/검증 | dcmsign | dcmsign-dcmrt.md |
| RT Plan / Struct / Dose 객체 검사 | 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. PACS로 DICOM 파일 전송 (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— 검증됨, TS 협상에 대한 완전한-x*제어,+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-gsiStudy/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는 프레임당 하나의 출력 파일을 씁니다(파일 이름에 프레임 번호 접미사가 추가됨).
파일의 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의 더 이상 사용되지 않는 별칭입니다 — 항상 dcm2img를 사용하세요.
dcm2img가 단순성을 위해 모든 것을 처리합니다. JPEG 압축을 제어하거나 렌더링 없이 구문만 변환해야 하는 경우 아래의 압축 코덱 섹션을 참조하세요.