PyQt5を使ってDICOM画像を表示してみよう
Key word: PyQt5, DICOM,
PyQtとは
PyQtは数あるGUI(Graphical User Interface)ライブラリ中でも人気があり,多くのサンプルプログラムなどがインターネット上に存在しています。
これらを使ってDICOM画像を表示するプログラムを作りながらPyQTの基本を学んでみようとおもいます。
PyQT5はAnacondaの中に含まれているのでAnacondaのインストール後にすぐに利用できます。
DICOM画像をPyQt5を使って表示する
DICOM画像を読み込み,いったんPNGファイルに保存した後,再びPyQTのQPixmapメソッドで読み込みウィンドウに表示します。
こうすることで,読込んだDICOMファイルを正しく読み込めたのかPNG画像で確認できます。
また,DICOM画像を使わないでPNGなどの一般的な画像への応用が容易になります。
DICOM画像はここにあります。実験以外では使用しないでください。
DicomDispayクラスを作成する
DicomDispayクラスは次の3つの関数で構成されている.
init関数:mainの中でDicomDisplayクラスを呼び出した際に初期化するイニシャライザです。
initUI関数:実際にGUIを作成する関数です。
これら2つの関数はPyQTでGUIを作成するための基本的な構成です。
そしてinitUI関数から様々なメソッドや関数を呼び出すことにより,目的に応じたGUIプログラムが作成することができます。
今回initUI関数がから呼び出される関数として,readDicom2png関数を作成します。
この関数はDICOMファイルを読み込みPNG画像に変換して保存する関数です。
プログラムの詳細は後にして,それではプログラムを入力して実行してみましょう。
DICOM画像表示プログラム
dicomDisplay.py
import sys,os
import numpy as np
import cv2
import pydicom
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.Qt import *
class DicomDisplay(QWidget):
def __init__(self, filename):
super().__init__()
self.dcmfnm = filename # DICOMファイル名
self.initUI()
def initUI(self):
#ファイル名を表示するラベルの作成
lblfnm = QLabel(" File Name : \t" + self.dcmfnm)
fnmbox = QVBoxLayout()
fnmbox.addWidget(lblfnm)
#画像読み込みラベルにセットする
self.readDicom2png(self.dcmfnm, './tmp.png') #DICOMを読んでpngに出力
pixmap = QPixmap('./tmp.png')
lblimg = QLabel()
lblimg.setPixmap(pixmap)
print(">>pixmap type :", type(pixmap))
#画像表示レイアウトの設定
imgbox = QVBoxLayout()
imgbox.addWidget(lblimg)
# 各パーツを配置する垂直なボックスを作成
mainVbox = QVBoxLayout()
mainVbox.addLayout(fnmbox)
mainVbox.addLayout(imgbox)
# 垂直ボックスをウィンドウにレイアウトする
self.setLayout(mainVbox)
self.setWindowTitle('DICOM Display')
self.show()
# DICOM画像読み込んでウィンドニング後PNGに保存
def readDicom2png(self, dcmfnm, tmpfnm):
ds = pydicom.read_file(dcmfnm) #DICOM画像を読み込む
wc = ds.WindowCenter #ウィンドウセンター値を代入
ww = ds.WindowWidth #ウィンドウ幅を代入
img = ds.pixel_array #画素値を代入
#表示画素値の最大と最小を計算する
max = wc + ww / 2
min = wc - ww / 2
print("wc =",wc,"ww =",ww,"→ max =",max," min =",min)
#ウインドニング処理
img = 255 * (img - min)/(max - min) #最大と最小画素値を0から255に変換
img[img > 255] = 255 #255より大きい画素値は255に変換
img[img < 0 ] = 0 #0より小さい画素値は0に変換
img = img.astype(np.uint8)
print(">>pixel_array type:", img.dtype, type(img))
cv2.imwrite(tmpfnm, img)
if __name__ == '__main__':
app = QApplication(sys.argv)
filename = "../dcmdir1/Brain01"
ex = DicomDisplay(filename)
sys.exit(app.exec_())
実行結果
実行するとウィンドウが現れ,DICOMファイル名とDICOM画像が表示されます。
$ python␣dicomDisplay.py⏎
プログラム解説
プログラムは実行すると最初に関連するライブラリをインポートしてmain関数から順に実行します。
main関数
最初に,QApplicationクラスはGUIを作成するための準備で最初に記述します。filenameには表示するDICOM画像のファイル名を設定します。
次に,今回作成するDicomDisplayクラスをDICOMファイル名を引数に呼び出します。
最後のsys.exit( app.exec_( ) )はアプリケーションを終了するための処理を記述しています。
init関数は引数にselfとfilenameを受け取る。
この関数では,必要な変数などの初期化を行います。表示するDICOM画像のファイル名を変数self.dcmfnmに代入します。
self.変数名はインスタンス変数と呼ばれ,クラス内で共有して利用できる便利な変数です。
実際にGraphical User Interfaceを作成するinitUI関数を呼び出します。
initUI関数は引数にselfを受け取ります。
この関数はselfを引数にしたので,イニシャライザで宣言したself.dcmfnmが関数内で利用可能です。実際のGUIは2つのLabelと3つのVBoxLayoutを作成して以下の手順で行われます。
- ファイル名を表示するためのLabel,lblfnmを作成する。
- ラベルを配置するためのVBoxLayout,fnmboxを作成する。
- 画像を表示するためのLabel,lblimgを作成する。
- 画像のラベルを配置するためのVBoxLayout,imgboxの作成する。
- ファイル名のfnmboxと画像のimgboxをを配置するVBoxLayoutとmainVboxを作成する。
- 最後にmainVBoxをWindowにレイアウトして表示する。
という流れになります。
readDicom2png関数
この関数は引数にself, dcmfnmとtmpfnmの3つを受け取ります。DICOMファイル(dcmfnm)を読み込み変数dsに代入します。
ウィンドニング処理をして最適な濃度に変換してPNGファイル(tmpfnm)に保存します。
ウィンドニング処理に必要なウィンドウセンターとウィンド幅の値をDICOMのタグから取得し変数wcとwwに代入します。
画素値のデータは変数imgに代入します。
画素値(ここではCT値)の最大値maxと最小値minをwcとwwから計算します。
実際のウィンドニング処理は次のように各画素に処理が行われます。
img = 255 * (img - min)/(max - min)
リストimgの値がを255を超えるとき次のように255に置き換えます。
img[img > 255] = 255
また,imgの値が負のとき,次のように0に置き換えます。
img[img < 0 ] = 0
最後にimgを符号なし8ビットに整えて,OpenCVのimwriteメソッドを使ってファイルに書き込みます。
おわりに
DICOM規格についてはPyゼミ1.01で説明しました。またDICOM画像のウィンドニング処理についても説明を行いましたので,ここでは説明が簡単になっています。
PyQt5は非常に簡単にGUIを作成することができます。
今後,ボタンの作成やマウスクリックのイベントの処理などを学びます。
DICOM画像を表示する際,いったんPNGのファイルに変換して保存してQPixmapに渡す,ファイル渡しの方法で画像表示しています。
filenameにPNGファイル名を指定して,QPixmapがこのファイルを読み込めば,PNG画像などにも容易に対応できることがわかると思います。

0 件のコメント:
コメントを投稿