Pythonを使ってDICOMやNIfTIといった医療画像を読み込む
はじめに
この記事ではPythonを使った医療画像処理の方法について紹介しています。
初めてPythonに触れる方でも学びやすいようにGoogle Colaboratoryを使った例を示しています。
Google Colaboratoryの基本的な使い方については、たくさん解説記事があると思うのでそちらを参考にしてみてください。
また、今回の記事の内容については無料でNotebookをDLできるようにしているので、よければ使ってみてください。
Pythonを使って医療画像データを読み込む
ここではPythonを使った医療画像データ(DICOMとNIfTI)の読み込み方法について紹介します。
以下の例では"Structural MRI datasets"のデータを利用しています。
お持ちのデータを利用する場合はファイルの読み込みの箇所を変えるといったように適宜修正してお使いください。
準備
以下のようなフォルダの階層構造のもとで行っています。
自分で追加しているものはすべて"Structural MRI datasets"のものです。
home(デフォルトのフォルダ)
┗ sample_data(デフォルトで読み込まれるもの)
┗ DICOM(自分で追加したもの)
┗ FLAIR(自分で追加したもの)
┗ T1(自分で追加したもの)
┗ T2(自分で追加したもの)
┗ ROI(自分で追加したもの)
┗ NIfTI(自分で追加したもの)
Colaboratoryのデフォルト環境では、医療画像を処理するのに必要なパッケージがインストールされていません。
そのため、まずは必要なパッケージをインストールします。
!pip install pydicom
うまくいくと"Successfully …"という表示がでます。
こういった表示が出なかった場合は失敗していて、これ以降の処理を実行することができないので注意してください。
# パッケージ読み込み
import glob
from matplotlib import pyplot as plt
import cv2
DICOMデータ
import pydicom
# DICOM/FLAIR以下にある拡張子".dcm"のファイルをすべて取得
files_flair = glob.glob('DICOM/FLAIR/*.dcm')
# ファイル名順にきちんと並ぶようにソート
files_flair = sorted(files_flair)
print(files_flair)
print(len(files_flair))# ファイル数を確認
ファイル数が0になってしまうときはファイルのパスがきちんとあっているか確認しましょう。
DICOMデータの読み込み
# 例えば先頭のデータを1つ読み込んでみましょう
# 0を他の数字に変えると違うファイルになります
data = pydicom.dcmread(files_flair[0])
# ColaboratoryなどいわゆるNotebook上ならDICOMのデータがたくさん表示されます
data
一覧表示された各データ項目は、例えば"xxx.ProtocolName"のようにスペースなしで項目名を後ろにつけてあげることで参照できるようになっています。
自分で用意したDICOMファイルを使用する場合、どのファイルがどの方法で撮像したものかわからなくて困る場合があると思います。
そういったときは
各ファイルのプロトコル名を表示させてみる
撮像時の設定やビュワーで一度どのようなプロトコル名になっているのかを確認
といったことをして、対象となるものを探すと良いです。
name_protocol = []
for x in files_flair:
data = pydicom.dcmread(x)
name_protocol.append(data.ProtocolName)
# プロトコル名一覧の表示
# set型にすることで重複したものは省かれています
print(set(name_protocol))
この例ではファイルが既に整理されているため、'sT2W/FLAIR SENSE'のみしか表示されません。
欲しいファイルのプロトコル名がわかったらif文を使って、それだけを抜粋すると良いです。
# 例えば"FLAIR"が入っているものだけを取得する場合myfiles = []
for x in files_flair:
data = pydicom.dcmread(x)
if 'FLAIR' in data.ProtocolName:
myfiles.append(x)
print(myfiles)
各情報の書き換えと保存
患者名(PatientName)や患者ID(PatientID)を匿名化した上でファイルを利用したくなることはよくあると思います。
そういった場合は該当箇所の情報を書き換えた上で保存することができます。
# 各情報を表示
print('Patient Name: ', data.PatientName)
# 各情報を書き換え
data.PatientName = 'XXXXX'
# 書き換えたDICOMファイルを保存
data.save_as('changed.dcm')
# 書き換えられているのを確認
changed = pydicom.dcmread('changed.dcm')
print('Changed Name: ', changed.PatientName)
Notebook上での画像表示
# 例えば1番目の画像を見る場合
data = pydicom.dcmread(files_flair[0])
img = data.pixel_array # これで画像情報だけを抜き出せます
# Notebook上で画像を表示
plt.imshow(img, cmap='gray')# cmap='gray'とすると、グレースケールになる
plt.show()
print('画像サイズ: ', img.shape)
医療画像を深層学習モデルにインプットとして渡すためにJPEGやPNGといった一般的な画像に変換したい場合があると思います。
そのようなときはOpenCVの機能を使って保存するのが楽だと思います。
# 保存するファイル名を.pngにすればPNGで保存されます
cv2.imwrite('flair.jpg', img)
ただ、上記の方法で簡単に保存できるものの、元画像と何か違う、あるいは真っ暗な画像になってしまう、といったことがあるかもしれません。
そのようになってしまうのは、
DICOMと保存先の画像との階調の違い
ウインドウ処理の有無
といったことが原因として考えられます。
今回のDICOMデータには"Window Center"や"Window Width"といった情報が含まれているため、ウインドウ処理を行った上でPNG形式で保存する例を以下に示しておきます。
wc = data.WindowCenter
ww = data.WindowWidth
# ウィンドウ処理
w_max = wc + ww/2
w_min = wc - ww/2
img_w = 255*(img - w_min)/(w_max - w_min)
img_w[img_w > 255] = 255 # 255より大きいところを255にする
img_w[img_w < 0] = 0 # 0未満を0にする
cv2.imwrite('flair_w.png', img_w)
これで保存したものは先ほどのもののような違和感はなくなっていると思います
NIfTIデータ
import nibabel as nib
ここでは例としてFLAIR画像を読み込んでみます
data = nib.load('NIfTI/BRAINIX_NIFTI_FLAIR.nii.gz')
img_list = data.get_data()#これで画像一覧を取り出せます
NIfTIのデータは、DICOMと違って1ファイル中に複数画像が含まれているときがあります。
get_data()のあとはshapeを使って、どういった行列になっているのかを確認するのがおすすめです。
print(data.shape)
今回の場合、288×288の画像が22枚入っていることがわかります。
目的の1枚の画像を取得するときはnumpyの行列操作を応用すれば大丈夫です。
# i番目の画像を抜き出すとき(ここでは例えばi = 0)
i = 0
img = img_list[:,:,i]
plt.imshow(img, cmap='gray')
plt.show()
画像を表示させるとわかるように画像が90度回転しているので、回転させたいときは以下のように角度をそのまま引数に渡せるscipyを使うのが直感的にできておすすめです。
from scipy import ndimage
img_rotated = ndimage.rotate(img, 90, reshape=False)
plt.imshow(img_rotated, cmap='gray')
plt.show()
以上の処理が書かれたNotebookです。
よければ使ってみてください。
簡単な使い方についてはこの記事を参考にしてください。
他にもこういった記事が読みたい!これを解説してほしい!などご意見がありましたら、アンケートフォームからご意見をいただけるとうれしいです。
この記事が気に入ったらサポートをしてみませんか?