mcpField
P
pydicom

pydicom

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

pydicom について

pydicom スキルは、医用画像の DICOM ファイルを扱うユーザー向けに、Python での作業手順を案内し、ピクセルデータ、メタデータ、圧縮形式を扱います。匿名化、メタデータ抽出、画像変換用のスクリプトも含みます。

主な機能

  1. 01DICOM の読み書きと変更
  2. 02ピクセルデータとメタデータの抽出
  3. 03圧縮画像とマルチフレーム画像の処理
  4. 04患者情報の匿名化
  5. 05一般的な画像形式への変換

活用シーン

  1. 01CT や MRI ファイルのメタデータ確認
  2. 02研究共有用スキャンの匿名化
  3. 03DICOM のピクセルデータを画像に変換

インストール

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

$npx skills add https://github.com/crazymsn/academic-skills --skill pydicom

インストール後、Claude Code で/pydicomを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
common_tags.md
transfer_syntaxes.md
scripts/
anonymize_dicom.py
dicom_to_image.py
extract_metadata.py

詳細

Pydicom

概要

Pydicom は、医用画像データの標準フォーマットである DICOM ファイルを扱うための純粋な Python パッケージです。このスキルは、DICOM ファイルの読み取り、書き込み、操作に関するガイダンスを提供します。ピクセルデータ、メタデータ、各種圧縮フォーマットの扱いも含まれます。

このスキルを使用するタイミング

次のような作業でこのスキルを使用します:

  • 医用画像ファイル(CT、MRI、X 線、超音波、PET など)
  • メタデータの抽出や変更が必要な DICOM データセット
  • 医用スキャンからのピクセルデータの抽出と画像処理
  • 研究やデータ共有のための DICOM の匿名化
  • DICOM ファイルの標準画像フォーマットへの変換
  • 展開が必要な圧縮 DICOM データ
  • DICOM のシーケンスと構造化レポート
  • マルチスライスボリュームの再構成
  • PACS(Picture Archiving and Communication System)との連携

インストール

pydicom と一般的な依存パッケージをインストールします:

uv pip install pydicom
uv pip install pillow  # For image format conversion
uv pip install numpy   # For pixel array manipulation
uv pip install matplotlib  # For visualization

圧縮された DICOM ファイルを扱う場合は、追加のパッケージが必要になることがあります:

uv pip install pylibjpeg pylibjpeg-libjpeg pylibjpeg-openjpeg  # JPEG compression
uv pip install python-gdcm  # Alternative compression handler

主要なワークフロー

DICOM ファイルの読み取り

pydicom.dcmread() を使用して DICOM ファイルを読み取ります:

import pydicom

# Read a DICOM file
ds = pydicom.dcmread('path/to/file.dcm')

# Access metadata
print(f"Patient Name: {ds.PatientName}")
print(f"Study Date: {ds.StudyDate}")
print(f"Modality: {ds.Modality}")

# Display all elements
print(ds)

要点:

  • dcmread() は Dataset オブジェクトを返します
  • データ要素には属性表記(例: ds.PatientName)またはタグ表記(例: ds[0x0010, 0x0010])でアクセスできます
  • ds.file_meta を使用して、Transfer Syntax UID などのファイルメタデータにアクセスします
  • 属性が存在しない場合は、getattr(ds, 'AttributeName', default_value) または hasattr(ds, 'AttributeName') で処理します
ピクセルデータの操作

DICOM ファイルから画像データを抽出して操作します:

import pydicom
import numpy as np
import matplotlib.pyplot as plt

# Read DICOM file
ds = pydicom.dcmread('image.dcm')

# Get pixel array (requires numpy)
pixel_array = ds.pixel_array

# Image information
print(f"Shape: {pixel_array.shape}")
print(f"Data type: {pixel_array.dtype}")
print(f"Rows: {ds.Rows}, Columns: {ds.Columns}")

# Apply windowing for display (CT/MRI)
if hasattr(ds, 'WindowCenter') and hasattr(ds, 'WindowWidth'):
    from pydicom.pixel_data_handlers.util import apply_voi_lut
    windowed_image = apply_voi_lut(pixel_array, ds)
else:
    windowed_image = pixel_array

# Display image
plt.imshow(windowed_image, cmap='gray')
plt.title(f"{ds.Modality} - {ds.StudyDescription}")
plt.axis('off')
plt.show()

カラー画像の扱い:

# RGB images have shape (rows, columns, 3)
if ds.PhotometricInterpretation == 'RGB':
    rgb_image = ds.pixel_array
    plt.imshow(rgb_image)
elif ds.PhotometricInterpretation == 'YBR_FULL':
    from pydicom.pixel_data_handlers.util import convert_color_space
    rgb_image = convert_color_space(ds.pixel_array, 'YBR_FULL', 'RGB')
    plt.imshow(rgb_image)

マルチフレーム画像(動画/シリーズ):

# For multi-frame DICOM files
if hasattr(ds, 'NumberOfFrames') and ds.NumberOfFrames > 1:
    frames = ds.pixel_array  # Shape: (num_frames, rows, columns)
    print(f"Number of frames: {frames.shape[0]}")

    # Display specific frame
    plt.imshow(frames[0], cmap='gray')
DICOM から画像フォーマットへの変換

提供されている dicom_to_image.py スクリプトを使用するか、手動で変換します:

from PIL import Image
import pydicom
import numpy as np

ds = pydicom.dcmread('input.dcm')
pixel_array = ds.pixel_array

# Normalize to 0-255 range
if pixel_array.dtype != np.uint8:
    pixel_array = ((pixel_array - pixel_array.min()) /
                   (pixel_array.max() - pixel_array.min()) * 255).astype(np.uint8)

# Save as PNG
image = Image.fromarray(pixel_array)
image.save('output.png')

スクリプトを使用する場合: python scripts/dicom_to_image.py input.dcm output.png

メタデータの変更

DICOM データ要素を変更します:

import pydicom
from datetime import datetime

ds = pydicom.dcmread('input.dcm')

# Modify existing elements
ds.PatientName = "Doe^John"
ds.StudyDate = datetime.now().strftime('%Y%m%d')
ds.StudyDescription = "Modified Study"

# Add new elements
ds.SeriesNumber = 1
ds.SeriesDescription = "New Series"

# Remove elements
if hasattr(ds, 'PatientComments'):
    delattr(ds, 'PatientComments')
# Or using del
if 'PatientComments' in ds:
    del ds.PatientComments

# Save modified file
ds.save_as('modified.dcm')
DICOM ファイルの匿名化

患者を特定できる情報を削除または置換します:

import pydicom
from datetime import datetime

ds = pydicom.dcmread('input.dcm')

# Tags commonly containing PHI (Protected Health Information)
tags_to_anonymize = [
    'PatientName', 'PatientID', 'PatientBirthDate',
    'PatientSex', 'PatientAge', 'PatientAddress',
    'InstitutionName', 'InstitutionAddress',
    'ReferringPhysicianName', 'PerformingPhysicianName',
    'OperatorsName', 'StudyDescription', 'SeriesDescription',
]

# Remove or replace sensitive data
for tag in tags_to_anonymize:
    if hasattr(ds, tag):
        if tag in ['PatientName', 'PatientID']:
            setattr(ds, tag, 'ANONYMOUS')
        elif tag == 'PatientBirthDate':
            setattr(ds, tag, '19000101')
        else:
            delattr(ds, tag)

# Update dates to maintain temporal relationships
if hasattr(ds, 'StudyDate'):
    # Shift dates by a random offset
    ds.StudyDate = '20000101'

# Keep pixel data intact
ds.save_as('anonymized.dcm')

提供されているスクリプトを使用する場合: python scripts/anonymize_dicom.py input.dcm output.dcm

DICOM ファイルの書き込み

ゼロから DICOM ファイルを作成します:

import pydicom
from pydicom.dataset import Dataset, FileDataset
from datetime import datetime
import numpy as np

# Create file meta information
file_meta = Dataset()
file_meta.MediaStorageSOPClassUID = pydicom.uid.generate_uid()
file_meta.MediaStorageSOPInstanceUID = pydicom.uid.generate_uid()
file_meta.TransferSyntaxUID = pydicom.uid.ExplicitVRLittleEndian

# Create the FileDataset instance
ds = FileDataset('new_dicom.dcm', {}, file_meta=file_meta, preamble=b"\0" * 128)

# Add required DICOM elements
ds.PatientName = "Test^Patient"
ds.PatientID = "123456"
ds.Modality = "CT"
ds.StudyDate = datetime.now().strftime('%Y%m%d')
ds.StudyTime = datetime.now().strftime('%H%M%S')
ds.ContentDate = ds.StudyDate
ds.ContentTime = ds.StudyTime

# Add image-specific elements
ds.SamplesPerPixel = 1
ds.PhotometricInterpretation = "MONOCHROME2"
ds.Rows = 512
ds.Columns = 512
ds.BitsAllocated = 16
ds.BitsStored = 16
ds.HighBit = 15
ds.PixelRepresentation = 0

# Create pixel data
pixel_array = np.random.randint(0, 4096, (512, 512), dtype=np.uint16)
ds.PixelData = pixel_array.tobytes()

# Add required UIDs
ds.SOPClassUID = pydicom.uid.CTImageStorage
ds.SOPInstanceUID = file_meta.MediaStorageSOPInstanceUID
ds.SeriesInstanceUID = pydicom.uid.generate_uid()
ds.StudyInstanceUID = pydicom.uid.generate_uid()

# Save the file
ds.save_as('new_dicom.dcm')
圧縮と展開

圧縮された DICOM ファイルを扱います:

import pydicom

# Read compressed DICOM file
ds = pydicom.dcmread('compressed.dcm')

# Check transfer syntax
print(f"Transfer Syntax: {ds.file_meta.TransferSyntaxUID}")
print(f"Transfer Syntax Name: {ds.file_meta.TransferSyntaxUID.name}")

# Decompress and save as uncompressed
ds.decompress()
ds.save_as('uncompressed.dcm', write_like_original=False)

# Or compress when saving (requires appropriate encoder)
ds_uncompressed = pydicom.dcmread('uncompressed.dcm')
ds_uncompressed.compress(pydicom.uid.JPEGBaseline8Bit)
ds_uncompressed.save_as('compressed_jpeg.dcm')

一般的な転送構文:

  • ExplicitVRLittleEndian - 非圧縮、最も一般的
  • JPEGBaseline8Bit - JPEG 非可逆圧縮
  • JPEGLossless - JPEG 可逆圧縮
  • JPEG2000Lossless - JPEG 2000 可逆圧縮
  • RLELossless - ランレングス符号化による可逆圧縮

完全な一覧は references/transfer_syntaxes.md を参照してください。

DICOM シーケンスの操作

入れ子になったデータ構造を扱います:

import pydicom

ds = pydicom.dcmread('file.dcm')

# Access sequences
if 'ReferencedStudySequence' in ds:
    for item in ds.ReferencedStudySequence:
        print(f"Referenced SOP Instance UID: {item.ReferencedSOPInstanceUID}")

# Create a sequence
from pydicom.sequence import Sequence

sequence_item = Dataset()
sequence_item.ReferencedSOPClassUID = pydicom.uid.CTImageStorage
sequence_item.ReferencedSOPInstanceUID = pydicom.uid.generate_uid()

ds.ReferencedImageSequence = Sequence([sequence_item])
DICOM シリーズの処理

複数の関連する DICOM ファイルを扱います:

import pydicom
import numpy as np
from pathlib import Path

# Read all DICOM files in a directory
dicom_dir = Path('dicom_series/')
slices = []

for file_path in dicom_dir.glob('*.dcm'):
    ds = pydicom.dcmread(file_path)
    slices.append(ds)

# Sort by slice location or instance number
slices.sort(key=lambda x: float(x.ImagePositionPatient[2]))
# Or: slices.sort(key=lambda x: int(x.InstanceNumber))

# Create 3D volume
volume = np.stack([s.pixel_array for s in slices])
print(f"Volume shape: {volume.shape}")  # (num_slices, rows, columns)

# Get spacing information for proper scaling
pixel_spacing = slices[0].PixelSpacing  # [row_spacing, col_spacing]
slice_thickness = slices[0].SliceThickness
print(f"Voxel size: {pixel_spacing[0]}x{pixel_spacing[1]}x{slice_thickness} mm")

ヘルパースクリプト

このスキルには、scripts/ ディレクトリに次のユーティリティスクリプトが含まれています:

anonymize_dicom.py

Protected Health Information(PHI)を削除または置換して DICOM ファイルを匿名化します。

python scripts/anonymize_dicom.py input.dcm output.dcm
dicom_to_image.py

DICOM ファイルを一般的な画像フォーマット(PNG、JPEG、TIFF)に変換します。

python scripts/dicom_to_image.py input.dcm output.png
python scripts/dicom_to_image.py input.dcm output.jpg --format JPEG
extract_metadata.py

DICOM メタデータを抽出し、読みやすい形式で表示します。

python scripts/extract_metadata.py file.dcm
python scripts/extract_metadata.py file.dcm --output metadata.txt

参考資料

詳細な参考情報は references/ ディレクトリにあります:

  • common_tags.md: 一般的によく使われる DICOM タグを分類別(Patient、Study、Series、Image など)にまとめた包括的な一覧
  • transfer_syntaxes.md: DICOM 転送構文と圧縮フォーマットの完全なリファレンス

よくある問題と解決策

問題: "Unable to decode pixel data"

  • 解決策: 追加の圧縮ハンドラーをインストールします: uv pip install pylibjpeg pylibjpeg-libjpeg python-gdcm

問題: タグにアクセスする際の "AttributeError"

  • 解決策: hasattr(ds, 'AttributeName') で属性が存在するか確認するか、ds.get('AttributeName', default) を使用します

問題: 画像表示が不適切(暗すぎる/明るすぎる)

  • 解決策: VOI LUT ウィンドウ処理を適用します: apply_voi_lut(pixel_array, ds)。または WindowCenter と WindowWidth を使って手動で調整します

問題: 大規模なシリーズでのメモリの問題

  • 解決策: ファイルを逐次処理するか、メモリマップ配列を使用するか、画像をダウンサンプリングします

ベストプラクティス

  1. 属性にアクセスする前に、必ず必要な属性の有無を確認してください。hasattr() または get() を使用します
  2. ファイルを変更する際はファイルのメタデータを保持してください。write_like_original=True を指定して save_as() を使用します
  3. ピクセルデータを処理する前に、Transfer Syntax UID を使用して圧縮形式を把握してください
  4. 信頼できないソースからファイルを読み込む際は、例外を適切に処理してください
  5. 医用画像の可視化には適切なウィンドウ処理(VOI LUT)を適用してください
  6. 3D ボリュームを処理する際は、空間情報(ピクセル間隔、スライス厚)を維持してください
  7. 医療データを共有する前に、匿名化が適切に行われているかを十分に確認してください
  8. UID を正しく使用してください。新しいインスタンスを作成する際は新しい UID を生成し、変更する際は既存の UID を保持してください

ドキュメント

pydicom の公式ドキュメント: https://pydicom.github.io/pydicom/dev/

コメント