スクリプト

pythonでかんたんなDICOMビューアーの作成 matplotlibのSliderを使う

pythonでDICOMって見れるんですね。
でも一枚一枚しかみれないもんなんですか?
連続で見たい時はDICOMビューアーが便利だよ。
でも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フォルダのパス


スライドでスライスが変わります。

スライスを送るという基本機能をいれたのみだけですが、
cmapのカラーのパラメータを変えて濃淡を変更できたり、
関心領域の切り抜きすることもスライダーを増やして行えます。

応用の仕方はたくさんありますね。