1. このレッスンの読み方
ここからUnit 3では医用画像AIを扱います。画像の深層学習はPyTorchで書きますが、
PyTorchはブラウザ内のPython(Pyodide)では動きません。
そのため本UnitはE資格コーディング対策コースと同じく、
コードを実行せず「読み解く」形式で進めます。
このレッスンのコードには実行ボタンがなく、代わりに「実行したらどう出るか」を「▼ 出力」として下に示します
(出力は pydicom に同梱された公開テストデータで実際に確認した値です)。
💡 なぜ画像は「別扱い」なのか: テーブルデータ(レッスン3〜6)は数値がそのまま特徴量でした。 しかし医用画像は、ファイルを開いて画素にする・値を意味のある単位に直す・見たい部位が見えるよう調整する—— AIに入れる前の前処理が一段深いのです。まずはその入口、DICOMを知りましょう。
2. DICOMとは — 画像とカルテ情報が一体のファイル
DICOM(ダイコム)は、CT・MRI・レントゲンなどの医用画像の標準フォーマットです。 ふつうの画像(JPEGやPNG)と決定的に違うのは、1つのファイルの中に「画像」と「メタデータ(タグ)」が同居していること。 タグには患者情報・撮影条件・画素を意味に直すための係数などが詰まっています。 ファイルの中身は「タグ・型・長さ・値」からなる要素がタグの番号順に並んだ構造で、画像本体(画素データ)もその最後の要素の1つです。
Pythonでは pydicom というライブラリで読み込みます。まずはファイルを開いて、主要なタグを見てみましょう。
import pydicom
# DICOMファイルを読み込む(1ファイル=CTの1スライス)
ds = pydicom.dcmread("ct_slice.dcm")
# 主要なタグ(メタデータ)を見る
print("モダリティ:", ds.Modality)
print("画像サイズ:", ds.Rows, "x", ds.Columns)
print("画素間隔(mm):", ds.PixelSpacing)
print("Rescale係数:", ds.RescaleSlope, ds.RescaleIntercept)
モダリティ: CT
画像サイズ: 128 x 128
画素間隔(mm): [0.661468, 0.661468]
Rescale係数: 1.0 -1024.0
ds.Modality で「これはCT画像」、ds.PixelSpacing で「1画素=約0.66mm四方」——
画像を実寸で扱えるのがDICOMの強みです。属性名(Modality など)でタグを読めるので、
辞書のように直感的に扱えます。
3. 画素を取り出す — pixel_array
画像本体(画素の数値)は ds.pixel_array で、NumPy配列として取り出せます。
ここから先は、あなたがNumPyコースで学んだ配列操作の世界です。
arr = ds.pixel_array # NumPy配列として取り出す
print("shape:", arr.shape) # (高さ, 幅)
print("dtype:", arr.dtype) # 整数型
print("生の画素 min/max:", arr.min(), arr.max())
shape: (128, 128)
dtype: int16
生の画素 min/max: 128 2191
⚠ この「生の画素値」はまだ意味を持たない:
min 128・max 2191 という数字は、そのままでは「空気」や「骨」といった組織の意味に対応していません。
CT画像を正しく読むには、この生の値をHU値(次の§)に変換する必要があります。
生の pixel_array をそのままAIに入れてしまうのは、医用画像でよくある初歩のミスです。
4. HU値変換 — 画素を「組織の意味」に直す
CT画像の生の画素値は、装置ごとの都合で保存された数字にすぎません。
これをHU値(ハウンスフィールド単位)に直すと、組織の種類と結びついた世界共通の物差しになります。
変換式はシンプルで、タグに入っている RescaleSlope と RescaleIntercept を使います。
🩺 HU値のめやす: 空気 ≒ -1000/肺 ≒ -500〜-900/脂肪 ≒ -100/水 = 0/軟部組織 ≒ +40/骨 ≒ +400〜+1000。 この物差しがあるから、「HU=-800付近は肺」「HU=+700は骨」と組織を数値で狙い撃ちできるのです。
# HU値 = 生の画素値 × RescaleSlope + RescaleIntercept
hu = arr * ds.RescaleSlope + ds.RescaleIntercept
print("HU min/max:", hu.min(), hu.max())
HU min/max: -896.0 1167.0
変換後は -896〜1167。最小値がおよそ -900 で「空気〜肺」、最大が +1167 で「骨」と、
HU値のめやすと一致します。RescaleSlope=1, RescaleIntercept=-1024 なので、
実質「生の値から1024を引く」変換でした。この一手間で、画像が解剖学的に意味のあるデータになります。
5. ウィンドウ処理 — 見たい組織を浮かび上がらせる
HU値は約 -1000〜+1000 の広い範囲を持ちますが、人の目やモデルが一度に見分けられる濃淡は限られます。 そこで、見たい組織のHU範囲だけを切り出して白黒に割り当てるのがウィンドウ処理です。 中心をWL(ウィンドウレベル)、幅をWW(ウィンドウ幅)で指定します。
import numpy as np
def apply_window(hu, wl, ww):
# WL=中心, WW=幅。範囲外は0〜255に丸める
lo, hi = wl - ww / 2, wl + ww / 2
img = np.clip(hu, lo, hi)
return ((img - lo) / (hi - lo) * 255).astype(np.uint8)
lung = apply_window(hu, wl=-600, ww=1500) # 肺野条件
med = apply_window(hu, wl=40, ww=400) # 縦隔条件
print("肺野条件 min/max:", lung.min(), lung.max())
print("縦隔条件 min/max:", med.min(), med.max())
肺野条件 min/max: 77 255
縦隔条件 min/max: 0 255
⚠ AIにとってのウィンドウ処理: どのウィンドウで前処理するかで、モデルに見える情報が変わります。 肺の病変を探すAIなら肺野条件、というようにタスクに合ったウィンドウを選びます。 さらに訓練と本番で同じウィンドウ設定をそろえることも重要—— 違う設定の画像を混ぜると、レッスン11で扱う分布のズレの原因になります。
6. 匿名化 — AIに入れる前の必須作業
レッスン2で学んだとおり、 医療データは要配慮個人情報です。DICOMのタグには患者名・生年月日・IDなどが含まれるため、 研究やAI開発に使う前に匿名化(個人が特定できないようにする)が欠かせません。
# 個人を特定できるタグを消す・置き換える
ds.PatientName = "ANONYMOUS"
ds.PatientID = "0000"
# 不要な識別タグは削除(存在すれば)
for tag in ["PatientBirthDate", "PatientAddress"]:
if tag in ds:
del ds[tag]
print("匿名化後:", ds.PatientName)
匿名化後: ANONYMOUS
⚠ タグを消すだけでは足りないことも: 匿名化は「名前タグを消せば終わり」ではありません。 頭部CTのように画素そのものから顔を再構成できる画像もあり、その場合は画像側の処理(顔のぼかし等)も検討します。 また、実際の匿名化は施設のルール・研究倫理審査に従って行うもので、 ここで学んだのは仕組みの理解です。運用の基準はレッスン10で扱います。
7. 練習問題
コードと出力を読んで答えを選び、「答えと解説を見る」で確認しましょう。
HU値変換の式は?
生の画素値からHU値を求める正しい式はどれですか(slope=1, intercept=-1024 のとき)。
- A.
hu = arr * intercept + slope - B.
hu = arr * slope + intercept - C.
hu = (arr - intercept) / slope
答えと解説を見る
正解:B. hu = arr * slope + intercept
RescaleSlope を掛けて RescaleIntercept を足す、が定義です。
今回は slope=1・intercept=-1024 なので「生の値から1024を引く」ことになり、
生の min 128 → HU -896、max 2191 → HU 1167 と、出力と一致します。
骨を白く見たいときのウィンドウは?
骨(HU ≒ +400〜+1000)をはっきり見たいとき、ウィンドウレベル(WL)の設定として最も適切なのはどれですか。
- A. WL = -600(肺野条件)
- B. WL = 40(縦隔条件)
- C. WL = 500 前後(骨に合わせる)
答えと解説を見る
正解:C. WL = 500 前後
ウィンドウレベル(WL)は「注目したいHU値の中心」です。骨はHU +400〜+1000あたりなので、 その中心の500前後にWLを合わせ、幅(WW)を広めに取ると骨がよく見えます(骨条件)。 WL=-600は肺、WL=40は軟部組織向けで、骨は白飛びして見分けにくくなります。 見たい組織のHUにWLを合わせるのが基本です。
前処理の順序
CT画像をAIに入れるまでの前処理を、正しい順に並べてください。
(ア)ウィンドウ処理 (イ)DICOM読み込み (ウ)HU値変換 (エ)pixel_array取り出し
答えと解説を見る
正解:(イ)→(エ)→(ウ)→(ア)
まず DICOMを読み込み(イ)、pixel_arrayで画素を取り出し(エ)、 HU値に変換(ウ)して意味のある物差しにし、最後にウィンドウ処理(ア)で見たい組織を浮かび上がらせます。 この後さらに「リサイズ・0〜1正規化」を経てモデルに入ります——その全体像は次のレッスン8で読み解きます。
8. まとめ
このレッスンのポイント
- DICOMは「画像+メタデータ(タグ)」が一体のフォーマット。
pydicom.dcmreadで読む ds.pixel_arrayでNumPy配列として画素を取り出す。ただし生の値はまだ意味を持たない- HU値変換(
arr * RescaleSlope + RescaleIntercept)で組織の物差しに直す(空気-1000・水0・骨+1000) - ウィンドウ処理(WL/WW)で見たい組織を浮かび上がらせる。訓練と本番で設定をそろえる
- AIに入れる前に匿名化が必須。タグだけでなく画素からの再特定にも注意
画像を「AIに入れられる形」に整える前処理ができました。 次のレッスンでは、この前処理を土台に、CT画像を分類するCNNの実装コードを読み解きます。 患者単位分割やデータ拡張の是非など、医用画像ならではの注意点が主役です。
完了するとコース一覧に進捗が記録されます