pydicom について
pydicom スキルは、医用画像の DICOM ファイルを扱うユーザー向けに、Python での作業手順を案内し、ピクセルデータ、メタデータ、圧縮形式を扱います。匿名化、メタデータ抽出、画像変換用のスクリプトも含みます。
主な機能
- 01DICOM の読み書きと変更
- 02ピクセルデータとメタデータの抽出
- 03圧縮画像とマルチフレーム画像の処理
- 04患者情報の匿名化
- 05一般的な画像形式への変換
活用シーン
- 01CT や MRI ファイルのメタデータ確認
- 02研究共有用スキャンの匿名化
- 03DICOM のピクセルデータを画像に変換
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ crazymsn/ academic-skills --skill pydicomインストール後、Claude Code で/pydicomを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/common_tags.mdtransfer_syntaxes.mdscripts/anonymize_dicom.pydicom_to_image.pyextract_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を使って手動で調整します
問題: 大規模なシリーズでのメモリの問題
- 解決策: ファイルを逐次処理するか、メモリマップ配列を使用するか、画像をダウンサンプリングします
ベストプラクティス
- 属性にアクセスする前に、必ず必要な属性の有無を確認してください。
hasattr()またはget()を使用します - ファイルを変更する際はファイルのメタデータを保持してください。
write_like_original=Trueを指定してsave_as()を使用します - ピクセルデータを処理する前に、Transfer Syntax UID を使用して圧縮形式を把握してください
- 信頼できないソースからファイルを読み込む際は、例外を適切に処理してください
- 医用画像の可視化には適切なウィンドウ処理(VOI LUT)を適用してください
- 3D ボリュームを処理する際は、空間情報(ピクセル間隔、スライス厚)を維持してください
- 医療データを共有する前に、匿名化が適切に行われているかを十分に確認してください
- UID を正しく使用してください。新しいインスタンスを作成する際は新しい UID を生成し、変更する際は既存の UID を保持してください
ドキュメント
pydicom の公式ドキュメント: https://pydicom.github.io/pydicom/dev/