mcpField
D
dicom-processing

dicom-processing

github.com/awslabsデータ・データベース6883 回インストール4 週間前に更新
リポジトリ

dicom-processing について

DICOM と NIfTI の医用画像を変換、読み取り、匿名化するワークフロー用スキルです。シリーズ単位の一括処理や BIDS ディレクトリ構成の手順も扱います。

主な機能

  1. 01BIDS サイドカー付き DICOM から NIfTI への変換
  2. 02DICOM ヘッダーとピクセルデータの読み取り
  3. 03PHI とプライベートタグの除去
  4. 04NIfTI ボリュームとアフィン行列の検査
  5. 05SeriesInstanceUID 単位の一括処理

活用シーン

  1. 01DICOM シリーズを圧縮 NIfTI に変換
  2. 02医用画像のヘッダーやピクセルを確認
  3. 03個別検査や大規模コホートの匿名化
  4. 04BIDS 形式で画像データセットを整理

インストール

コマンドをコピーしてターミナルで実行します。

$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 ygzip 形式で出力する(.nii.gz)
-b yBIDS 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. DICOM ファイルを匿名化する(pydicom)
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 サイドカーも必要です。

応答形式

  • 必要なコマンドまたはコードを最初に示し、その後に説明する
  • 次の構成にする:入力の確認 → 動作するコード → 主要パラメーターの説明 → 注意点
  • タスクごとに、完全に動作する例を 1 つ示す。代替案をすべて示す必要はない
  • コードコメントは最小限かつ実用的にする(存在理由ではなく、何をするかを記述する)
  • 目安:コード 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。「シリーズ」は変換の基本単位であり、通常、1 つの NIfTI ボリュームは 1 つの SeriesInstanceUID に対応します。

UID は識別子であり、秘密情報ではありませんが、相互に関連付けることができます。 StudyInstanceUID を共有する 2 つのファイルは、同じ検査に由来します。匿名化では UID を置き換え(generate_uid())、リリース間の関連付けを断つ必要があります。

プライベートタグには PHI が含まれることがあります。 ベンダー固有のタグ(グループ番号が奇数のもの)には、担当者のメモ、患者 ID、焼き込み済みのメタデータが含まれていることがよくあります。必ず ds.remove_private_tags() を呼び出してください。

ピクセルデータにも PHI が含まれることがあります。 超音波フレーム、セカンダリーキャプチャ、スクリーンショットでは、患者名や MRN がピクセルに焼き込まれていることがよくあります。タグを削除してもピクセルは消去されません。このリスクがある場合は、別途 OCR とマスキングを実行してください。

ジオメトリとモダリティに関する主要な DICOM タグ:

タグ名前用途
(0008,0060)ModalityCT / MR / CR / US / PT ...
(0018,0050)SliceThicknessmm
(0028,0030)PixelSpacing面内間隔 [row, col] mm
(0020,0032)ImagePositionPatient患者座標におけるスライスの原点
(0020,0037)ImageOrientationPatient行/列の方向余弦

これら 5 つのタグで、NIfTI の affine 行列を再構築できます。

NIfTI と DICOM の違い。 NIfTI は 1 つのアフィン変換を持つ単一の 3D/4D ボリュームを保存します。DICOM はスライス単位のメタデータを保存します。変換ツール(dcm2niix)はシリーズ内のスライスを集約し、上記のタグからアフィン変換を計算します。

クイックリファレンス

# 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 を保持する 正しい方法: 非識別化するファイルごとに、StudyInstanceUID、SeriesInstanceUID、SOPInstanceUID を generate_uid() で置き換えます 理由: 元の UID は元の PACS までたどることができます。2 つのファイルで同じ StudyInstanceUID が使われていると、同じ検査に由来することがわかってしまいます

  • 誤り: 確認せずに dcm2niix のデフォルトの結合動作を使う 正しい方法: -m n を使って結合を無効にするか、出力ファイル数を想定されるシリーズのリストと照合します 理由: デフォルトの結合では、別々の撮像が 1 つの 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 は独自の構造を持つインデックスファイルです。不完全または古い場合や、存在しない場合もあります。ファイルを直接反復処理するほうが確実です

参考資料

コメント