📋 この記事の目次
DICOMとは?医療画像の標準フォーマット
医療AIに興味を持って「まずは画像を触ってみよう」と思ったとき、最初にぶつかるのが DICOM(ダイコム) という聞き慣れないファイル形式ではないでしょうか。
DICOMは「Digital Imaging and Communications in Medicine」の略で、CT・MRI・X線・超音波など、病院で撮影される医療画像のほぼすべてに使われている国際標準規格です。JPEGやPNGと違い、画像データだけでなく患者情報や撮影条件などのメタデータが1つのファイルにまとめて格納されているのが大きな特徴です。
💡 DICOMファイルの特徴
DICOMファイルには、画像のピクセルデータに加えて「患者名」「撮影日」「スライス厚」「ウィンドウ幅」など、数百種類のメタデータ(タグ)が含まれています。拡張子は .dcm が一般的ですが、拡張子がないファイルも多く存在します。
医療画像AIを開発するには、このDICOMファイルを正しく読み込み、ピクセルデータを取り出す必要があります。そこで活躍するのが、今回紹介する pydicom です。
pydicomのインストールと環境準備
pydicom は、PythonでDICOMファイルを扱うためのオープンソースライブラリです。DICOMファイルの読み込み・書き出し・メタデータの取得や編集が簡単にできます。
インストール
pip でインストールできます。画像を表示するために matplotlib、数値計算用に numpy も併せて入れましょう。
サンプルDICOMファイルの入手
学習用のDICOMファイルが手元にない場合でも大丈夫です。pydicomには練習用のサンプルデータが同梱されています。以下のコードでサンプルファイルのパスを取得できます。
Python
from pydicom.data import get_testdata_file
# pydicom同梱のサンプルファイル一覧を確認
print(get_testdata_file("CT_small.dcm"))
また、パブリックドメインの医療画像データセットとしては The Cancer Imaging Archive(TCIA) が有名です。研究・学習目的で多数のDICOMデータを無料でダウンロードできます。
⚠ 注意:患者データの取り扱い
実際の臨床データを使う場合は、個人情報保護に十分注意してください。DICOMファイルには患者名・生年月日・施設名などの個人情報が含まれます。学習や研究には、匿名化済みのデータセットまたはpydicom同梱のサンプルデータを使用しましょう。
DICOMファイルを読み込んでみよう
pydicomでDICOMファイルを読み込むのはとても簡単です。dcmread() 関数にファイルパスを渡すだけです。
from pydicom.data import get_testdata_file
import pydicom
# サンプルファイルのパスを取得して読み込む
fpath = get_testdata_file("CT_small.dcm")
ds = pydicom.dcmread(fpath)
# データセットオブジェクトの中身を確認
print(ds)
dcmread() の戻り値は Dataset オブジェクトです。DICOMファイルに含まれるすべてのタグ情報と画像データがこのオブジェクトに格納されています。print(ds) を実行すると、タグの一覧が表示されます。
メタデータ(タグ情報)を取得する
DICOMファイルの強みは、画像と一緒に撮影条件や装置情報がすべて記録されていることです。pydicomでは、タグ名を属性としてアクセスするだけで値を取得できます。
Python
# 主要なメタデータにアクセス
print("患者名 :", ds.PatientName)
print("患者ID :", ds.PatientID)
print("モダリティ :", ds.Modality) # CT, MR, CR など
print("撮影日 :", ds.StudyDate)
print("画像サイズ :", ds.Rows, "×", ds.Columns)
print("スライス厚 :", ds.SliceThickness)
print("ピクセル間隔 :", ds.PixelSpacing)
出力例は次のようになります。
患者名 : CompressedSamples^CT1
患者ID : 1CT1
モダリティ : CT
撮影日 : 20040119
画像サイズ : 128 × 128
スライス厚 : 5.000000
ピクセル間隔 : [0.661468, 0.661468]
タグ番号でアクセスする方法
DICOMの各項目には「タグ番号」と呼ばれる (グループ, エレメント) の組が割り当てられています。タグ番号で直接アクセスすることもできます。
Python
# タグ番号でアクセス(Modality = (0008, 0060))
modality_tag = ds[0x0008, 0x0060]
print(modality_tag)
# → (0008, 0060) Modality CS: 'CT'
# 全タグの一覧をループで確認
for elem in ds:
if elem.tag.group != 0x7FE0: # ピクセルデータは除外
print(elem)
💡 よく使うDICOMタグ一覧
医療画像AI開発でよく参照するタグをまとめておきます。Modality(CTかMRIかの判別)、PixelSpacing(ピクセルの実寸)、SliceThickness(スライス厚)、RescaleSlope / RescaleIntercept(CT値への変換係数)、WindowCenter / WindowWidth(表示ウィンドウの設定値)あたりは頻繁に使います。
画像データをmatplotlibで表示する
DICOMファイルの画像データ(ピクセル配列)は ds.pixel_array で取得できます。これはNumPy配列として返されるので、そのまま matplotlib で表示できます。
from pydicom.data import get_testdata_file
import matplotlib.pyplot as plt
import pydicom
import numpy as np
# DICOMファイルを読み込み
fpath = get_testdata_file("CT_small.dcm")
ds = pydicom.dcmread(fpath)
# ピクセルデータをNumPy配列として取得
pixel_array = ds.pixel_array
print("配列の形状:", pixel_array.shape) # (128, 128)
print("データ型 :", pixel_array.dtype) # int16
# matplotlibで表示
plt.figure(figsize=(6, 6))
plt.imshow(pixel_array, cmap="gray")
plt.title("DICOM Image")
plt.colorbar(label="Pixel Value")
plt.axis("off")
plt.tight_layout()
plt.show()
CT_small.dcm をmatplotlibで表示した例
pixel_array は2次元のNumPy配列(グレースケール画像の場合)で、各要素がピクセル値を表しています。CT画像の場合、ピクセル値はCT値(ハンスフィールド値)に変換する前の「生の格納値」です。
CT値(ハンスフィールド値)への変換
CT画像では、格納されたピクセル値をCT値(HU: Hounsfield Unit)に変換するために、DICOMタグの RescaleSlope と RescaleIntercept を使います。
# CT値(HU)に変換
slope = float(ds.RescaleSlope)
intercept = float(ds.RescaleIntercept)
hu_image = pixel_array * slope + intercept
print("HU最小値:", hu_image.min())
print("HU最大値:", hu_image.max())
CT値は組織の密度を数値化したもので、水が 0 HU、空気が −1000 HU、骨が +1000 HU 前後です。この変換は医療画像AIの前処理で必ず行うステップなので、しっかり覚えておきましょう。
ウィンドニング(表示調整)を理解しよう
CT画像を plt.imshow() でそのまま表示すると、コントラストが弱くて見づらいことがあります。これは、CT値の幅が非常に広い(−1000〜+3000程度)のに対し、人間が一度に識別できる階調は限られているためです。
ウィンドニング(Window/Level) とは、表示するCT値の範囲を限定してコントラストを調整するテクニックです。DICOMファイルに推奨値が格納されていることが多く、WindowCenter と WindowWidth というタグで確認できます。
import matplotlib.pyplot as plt
import matplotlib
matplotlib.rcParams['font.family'] = 'MS Gothic'
def apply_window(image, center, width):
"""ウィンドニングを適用する関数"""
lower = center - width / 2
upper = center + width / 2
windowed = np.clip(image, lower, upper)
# 0〜255にスケーリング
windowed = (windowed - lower) / (upper - lower) * 255
return windowed.astype(np.uint8)
# DICOMに記録されたウィンドウ設定を取得(タグが存在しない場合はデフォルト値を使用)
if hasattr(ds, "WindowCenter") and hasattr(ds, "WindowWidth"):
wc = float(ds.WindowCenter)
ww = float(ds.WindowWidth)
else:
wc = 40 # 軟部組織の一般的な値
ww = 400
print(f"WindowCenter: {wc}, WindowWidth: {ww}")
# ウィンドニングを適用して表示
windowed_img = apply_window(hu_image, wc, ww)
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
axes[0].imshow(hu_image, cmap="gray")
axes[0].set_title("元のCT画像(HU値そのまま)")
axes[0].axis("off")
axes[1].imshow(windowed_img, cmap="gray")
axes[1].set_title(f"ウィンドニング適用 (C={wc}, W={ww})")
axes[1].axis("off")
plt.tight_layout()
plt.show()
左:HU値そのまま表示 右:ウィンドニング適用(C=40, W=400)
左がCT値をそのまま表示した画像、右がウィンドニングを適用した画像です。ウィンドニングを適用すると、注目したい組織のコントラストが大幅に改善されます。
💡 代表的なウィンドウ設定
観察する部位によって、よく使われるウィンドウ設定が決まっています。例えば、肺野を見るなら WC=-600, WW=1500、腹部の軟部組織なら WC=40, WW=400、骨を見るなら WC=300, WW=1500 が一般的です。AIモデルの入力画像を作る際も、適切なウィンドニングを適用するかどうかで精度が変わることがあります。
まとめ ── 次のステップへ
この記事では、Pythonの pydicom ライブラリを使ったDICOM画像の基本操作を解説しました。ポイントを振り返りましょう。
- DICOM は医療画像の国際標準規格で、画像データとメタデータが1つのファイルにまとまっている
- pydicom の
dcmread()でDICOMファイルを簡単に読み込める - メタデータには
ds.PatientNameのように属性名でアクセスできる ds.pixel_arrayで画像のNumPy配列を取得し、matplotlibで表示可能- CT画像は
RescaleSlope / RescaleInterceptでHU値に変換する - ウィンドニングで表示コントラストを調整し、診断に適した画像を生成する
pydicomの基本をマスターしたら、次のステップとして「複数スライスを読み込んで3Dボリュームを再構成する」「画像の前処理パイプラインを構築する」「CNNで画像分類モデルを学習させる」といった応用に進んでいくとよいでしょう。
医療画像AI開発に必要な深層学習の知識については、E資格対策ページで体系的に学べます。特にCNN(畳み込みニューラルネットワーク)は医療画像処理の基盤技術なので、ぜひ押さえておいてください。