pythonでDICOMって見れるんですね。
でも一枚一枚しかみれないもんなんですか?
でも一枚一枚しかみれないもんなんですか?
連続で見たい時はDICOMビューアーが便利だよ。
でもPythonのmatplotlibでも見れる機能はあるよ。
でもPythonのmatplotlibでも見れる機能はあるよ。
ここではpythonでCTシリーズのDICOMを見ようと思います。
pythonのツールであるmatplotlibを用いて、CTのDICOMデータを流して見る方法を記載します。
内容は前のページのpythonでDICOMデータを見るの発展編になります。
必要なツール
- matplotlib
- pandas(並べ替えにラムダ関数使うなら不要)
- pydicom
ここではグラフを書くツール matplotlibのSliderという機能を使います。
イメージとしては図のような感じです
Sliderのカーソルを動かすと①、②の処理が行われ、CTの画像が切り替わります。
コードで書くと下のようになります。
"""dicom_viewer.py"""
import os
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider
import pandas as pd
import pydicom
print('Dicom Folder Name ?? :')
folder_name = input() #DICOMファイルのフォルダを入力で得る
file_list = [] #フォルダ内すべてのファイル
dicom_list = [] #フォルダ内のDICOMファイル
slice_parameter = [] #DICOMファイルのSliceLocationの値
#フォルダ内のDICOMデータをリストにして取得する関数。DICOMのSliceLocationタグの値で並びかえる
def get_dicom_file_list(folder_name):
"""Return the dicom file list sorted by SliceLocation
Args
arg(str): folder_name of the dicom_files
Returns
return(list): dicom_file list sorted by SliceLocation
Note
Check if the dicom file has .SliceLocation attribute
"""
for file_name in os.listdir(folder_name):
file_absname = os.path.join(folder_name, file_name)
try:
ds = pydicom.read_file(file_absname)
slice_parameter.append(ds.SliceLocation)
dicom_list.append(file_absname)
except:
pass
df = pd.DataFrame(zip(dicom_list, slice_parameter), columns=['filename', 'slicelocation'])
df_sorted = df.sort_values('slicelocation')
sorted_dicom_list = list(df_sorted['filename'])
return sorted_dicom_list
# 並べ替え。慣れてる人はラムダ関数のほうが短く書けます。
sorted_dicom_list = get_dicom_file_list(folder_name)
file_number = len(sorted_dicom_list)
init_slice = int(file_number / 2) #真ん中のスライスを初期値に設定
fig, (ax0, ax1) = plt.subplots(2, 1, gridspec_kw={'height_ratios': [20, 1]})
# 2行からなるfigを定義。ax0がDICOM画像の表示、ax1がスライダーの位置
# DICOMデータからピクセルデータを得る関数を定義
def get_pixel(dcm_index):
"""get the pixel_array from DICOM file
arg(int): index of the dicom_file in the dicom_list
return(ndarray) : pixel_array of the dicom_file
"""
ds = pydicom.read_file(sorted_dicom_list[dcm_index])
return ds.pixel_array
# 初期の画像を表示する
image_table = ax0.imshow(get_pixel(init_slice), cmap='gray')
# Sliderの属性を定義する
slice_slider = Slider(
ax=ax1, #subplotのax1にスライダーを設置
label="Slice Number", #「Slice Number」というタイトル
valinit=init_slice, # 初期値の設定 ここでは真ん中
valmin=0, # 最小値の設定
valmax=len(dicom_list), # 最大値の設定(ファイル数 - 1)
valfmt='%d', # int型
orientation="horizontal" # 水平方向にスライドする
)
# Sliderの値が変わった時に行う動作
def update(val):
"""Set the valuable to the slider value"""
image_table.set_data(get_pixel(int(slice_slider.val)))
fig.canvas.draw_idle() # pltのfigをリニューアルする
return
#Sliderの動きに合わせてアップデートする
slice_slider.on_changed(update)
plt.show()
このpythonスクリプトを実行すると、
「Dicom Folder Name ?? :」
と聞かれますので、Dicomの入ったフォルダのパスを入力すると、簡易ビューアーが立ち上がります。
% python dicom_viewer.py # 上記のスクリプトdicom_viewer.pyをpythonで実行
Dicom Folder Name ?? :
/Desktop/dicom_data/dicom_folder # dicomフォルダのパス
Dicom Folder Name ?? :
/Desktop/dicom_data/dicom_folder # dicomフォルダのパス
スライドでスライスが変わります。
スライスを送るという基本機能をいれたのみだけですが、
cmapのカラーのパラメータを変えて濃淡を変更できたり、
関心領域の切り抜きすることもスライダーを増やして行えます。
応用の仕方はたくさんありますね。