Notice: Function _load_textdomain_just_in_time was called incorrectly. Translation loading for the all-in-one-seo-pack domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early. Translations should be loaded at the init action or later. Please see Debugging in WordPress for more information. (This message was added in version 6.7.0.) in /virtual/mcu03iphuk/public_html/radiology-technologist.info/wp-includes/functions.php on line 6114

Notice: Function _load_textdomain_just_in_time was called incorrectly. Translation loading for the easy-fancybox domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early. Translations should be loaded at the init action or later. Please see Debugging in WordPress for more information. (This message was added in version 6.7.0.) in /virtual/mcu03iphuk/public_html/radiology-technologist.info/wp-includes/functions.php on line 6114

Notice: Function _load_textdomain_just_in_time was called incorrectly. Translation loading for the urvanov-syntax-highlighter domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early. Translations should be loaded at the init action or later. Please see Debugging in WordPress for more information. (This message was added in version 6.7.0.) in /virtual/mcu03iphuk/public_html/radiology-technologist.info/wp-includes/functions.php on line 6114

Notice: Function _load_textdomain_just_in_time was called incorrectly. Translation loading for the breadcrumb-navxt domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early. Translations should be loaded at the init action or later. Please see Debugging in WordPress for more information. (This message was added in version 6.7.0.) in /virtual/mcu03iphuk/public_html/radiology-technologist.info/wp-includes/functions.php on line 6114

Notice: Function _load_textdomain_just_in_time was called incorrectly. Translation loading for the advanced-ads domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early. Translations should be loaded at the init action or later. Please see Debugging in WordPress for more information. (This message was added in version 6.7.0.) in /virtual/mcu03iphuk/public_html/radiology-technologist.info/wp-includes/functions.php on line 6114

Notice: 関数 _load_textdomain_just_in_time が誤って呼び出されました。lancr ドメインの翻訳の読み込みが早すぎました。これは通常、プラグインまたはテーマの一部のコードが早すぎるタイミングで実行されていることを示しています。翻訳は init アクション以降で読み込む必要があります。 詳しくは WordPress のデバッグをご覧ください。 (このメッセージはバージョン 6.7.0 で追加されました) in /virtual/mcu03iphuk/public_html/radiology-technologist.info/wp-includes/functions.php on line 6114

Warning: Cannot modify header information - headers already sent by (output started at /virtual/mcu03iphuk/public_html/radiology-technologist.info/wp-includes/functions.php:6114) in /virtual/mcu03iphuk/public_html/radiology-technologist.info/wp-content/plugins/all-in-one-seo-pack/app/Common/Meta/Robots.php on line 87

Warning: Cannot modify header information - headers already sent by (output started at /virtual/mcu03iphuk/public_html/radiology-technologist.info/wp-includes/functions.php:6114) in /virtual/mcu03iphuk/public_html/radiology-technologist.info/wp-includes/feed-rss2.php on line 8
ウインドウ調整 | 診療放射線技師がPythonをはじめました。 http://radiology-technologist.info 診療放射線技師のPython日記。解析等で使えるコードを作成、アップしていきたいと思っています。その他いろいろ Wed, 25 Mar 2020 13:36:09 +0000 ja hourly 1 https://wordpress.org/?v=6.7 https://i0.wp.com/radiology-technologist.info/wp-content/uploads/2018/09/cropped-logo5.png?fit=32%2C32 ウインドウ調整 | 診療放射線技師がPythonをはじめました。 http://radiology-technologist.info 32 32 164362728 MRI画像をスライダーを使ってウインドウ調整2(OpenCv編) http://radiology-technologist.info/post-463 Sat, 21 Mar 2020 13:30:17 +0000 http://radiology-technologist.info/?p=463 それでは、コードを組み立てていきたいと思います。 […]

The post MRI画像をスライダーを使ってウインドウ調整2(OpenCv編) first appeared on 診療放射線技師がPythonをはじめました。.]]>
それでは、コードを組み立てていきたいと思います。

前回のコードの流れにそってやっていきたいと思います。

コードの流れ


画像パスの取得

画像パスの取得です。以前やって「画像選択のプログラムを使いやすく」で作成したモジュールを使用したいと思います。複数の画像を選択したいので使用する関数は multi_fileselect を指定します。(今回は、画像を切り替えるプログラムは組み込みません。)

import fileselect as fs   #ファイルパス取得のモジュールをインポート

filenames = fs.multi_fileselect

上記コード2行目でfileselectのモジュールをインポートしています。そして、そのモジュールを使う時はfsという名前で使えるように設定。(前回作成したfileselectのファイルを今回作成するプログラムと同じフォルダに入れておいてください。)

4行目でfileselectモジュール内のmulti_fileselectの関数を呼び込み、その結果をfilenamesという変数の中に入れています。

モジュール化しておくことで、たった2行で画像ファイルのパスを取得できるようになっています。とても便利ですね~~。


画像表示用の配列を作成

画像表示用の配列を作成します。 初めは0で埋めた配列を作成します。 (このページから読んだ方は前回の「MRI画像をスライダーを使ってウインドウ調整1(OpenCv編)」を一度読んでいただくと意味が理解できると思います。)

作成の際には、画像の縦、横のピクセル数、画像枚数の3次元の配列を作成しますので、とりあえず、1枚画像を読み込んで縦横のピクセル数を取得します。画像の枚数は変数filenamesの要素数を取得することでわかります。

それでは作成していきますが、配列操作はnumpyを用いるのが便利なのでまずはnumpyをnpという名前で使えるようにインポートしましょう

0で初期化した配列を作成するのは以下のコードでできます。

np.zeros((z, y, x),dtype ,order)

1個の目の引数は配列の軸の設定です。zは画像の枚数、yは画像の縦方向のピクセル数、xは画像の横方向のピクセル数となります。

2個目の引数は格納される値の型となります。整数型か、小数点付きか、文字列なのか等の設定をします。今回は整数型となります。

3個目の引数は他次元配列の際に、行を優先するか、列を優先するかの設定です。オプションの設定となりますので今回は指定しません。


画像のピクセル数を取得してみましょう。

まずは、 pydicomのモジュールをインポートして画像を読み込みます。

読み込んだ画像の横方向を変数row、縦方向を変数columnsとして取得します。

import fileselect as fs   #ファイルパス取得のモジュールをインポート
import numpy np
import pydicom

filenames = fs.multi_fileselect

dcm = pydicom.dcmread(filenames[0])
row,columns = dcm.pix_array.shape[0],dcm.pix_array.shape[1]
       #読み込んだ画像の横方向を変数row、縦方向を変数columnsとして取得します。

dcm_copy = np.zeros((len(filenames), row, columns),dtype = int)
       #dcm_copyという名前で0で初期化した配列を作成


作成した配列に画像のピクセルデータを入れる

0で初期化した配列の中に画像のピクセルデータを入れていきます。

これは繰り返しの作業となりますのでfor文で処理していきたいと思います。

import fileselect as fs   #ファイルパス取得のモジュールをインポート
import numpy np
import pydicom

filenames = fs.multi_fileselect

dcm = pydicom.dcmread(filenames[0])
row,columns = dcm.pix_array.shape[0],dcm.pix_array.shape[1]
       #読み込んだ画像の横方向を変数row、縦方向を変数columnsとして取得します。

dcm_copy = np.zeros((len(filenames), row, columns),dtype = int)
       #dcm_copyという名前で0で初期化した配列を作成

for i in range(len(filenames)):
    dcm = pydicom.dcmread(filenames[i])
    dcm_arr = dcm.pixel_array
    dcm_copy[i] = dcm_arr.astype(np.int64) 
      #np.int64としてデータの型を指定しておきます。

これで、dcm_copyに選択した画像全てのピクセルデータが入りました。


スライダーの作成

スライダーを作成するには画像表示のウインドウ名が必要となりますので、まずは画像表示のウインドウの設定をします。

cv2.namedWindow(name,type)

第一引数のnameはウインドウ名です。

第二引数には表示形式をしていします。形式は以下の2種類です。

cv2.WINDOW_AUTOSIZE:デフォルト。ウィンドウサイズ固定表示

cv2.WINDOW_NORMAL:ウィンドウのサイズを変更可能にする

今回は、ウインドウサイズを変更できるようにしたいのでcv2.WINDOW_NORMAL を指定します。

import fileselect as fs   #ファイルパス取得のモジュールをインポート
import numpy np
import pydicom

filenames = fs.multi_fileselect

dcm = pydicom.dcmread(filenames[0])
row,columns = dcm.pix_array.shape[0],dcm.pix_array.shape[1]
       #読み込んだ画像の横方向を変数row、縦方向を変数columnsとして取得します。

dcm_copy = np.zeros((len(filenames), row, columns),dtype = int)
       #dcm_copyという名前で0で初期化した配列を作成

for i in range(len(filenames)):
    dcm = pydicom.dcmread(filenames[i])
    dcm_arr = dcm.pixel_array
    dcm_copy[i] = dcm_arr.astype(np.int64) 
      #np.int64としてデータの型を指定しておきます。

cv2.namedWindow('dcm_image',cv2.WINDOW_NORMAL)
      #ウインドウ名を'dcm_image'とし、ウインドウサイズを変更できるように設定

画像表示ウインドウの設定が終わったので、いよいよスライダーの設定に入ります。以下のコードで指定します。

cv2.createTrackbar( name , window_name , initial_value , max_value , definition )

作成するスライダーは2つ。WWとWLの2つです。それぞれ最大値をピクセルデータの最大値としたいので画像のピクセルデータが入っているdcm_copyの中の最大値を調べたいと思います。最大値は以下のコードで取得できます。

maxvalue = dcm_copy.max().astype(np.int64)

最後の .astype(np.int64) は取得した値の型を指定しておきます。(後の処理で型が違うとエラーが出てしまうので取得の段階で型の指定しておきます。)

スライダーの初期値はとりあえず、WLは画像最大値の半分、 WWは画像最大値の4分の1として設定してみましょう。

cv2.createTrackbar(“WL”, “dcm_image”, (maxvalue // 2), maxvalue, make_LUT)
cv2.createTrackbar(“WW”, “dcm_image”, (maxvalue // 4), maxvalue, make_LUT)

ここで、 maxvalue // 2 と maxvalue // 4 の’//’は間違いではなく、計算結果が少数にならないようにする演算子です。これにより小数点以下は切り捨てられます。

ちなみに、第5番目の引数はしていしないとエラーになってしまうので何もしない”make_LUT”という関数を作成しておきます。作成した関数で受ける引数は最低一つはないとこれもエラーとなってしまうので適当にvalという受けを書いておきます。

import fileselect as fs   #ファイルパス取得のモジュールをインポート
import numpy np
import pydicom

filenames = fs.multi_fileselect

dcm = pydicom.dcmread(filenames[0])
row,columns = dcm.pix_array.shape[0],dcm.pix_array.shape[1]
       #読み込んだ画像の横方向を変数row、縦方向を変数columnsとして取得します。

dcm_copy = np.zeros((len(filenames), row, columns),dtype = int)
       #dcm_copyという名前で0で初期化した配列を作成

for i in range(len(filenames)):
    dcm = pydicom.dcmread(filenames[i])
    dcm_arr = dcm.pixel_array
    dcm_copy[i] = dcm_arr.astype(np.int64) 
      #np.int64としてデータの型を指定しておきます。

cv2.namedWindow('dcm_image',cv2.WINDOW_NORMAL)
      #ウインドウ名を'dcm_image'とし、ウインドウサイズを変更できるように設定

maxvalue = dcm_copy.max().astype(np.int64)

cv2.createTrackbar("WL", "dcm_image", (maxvalue // 2), maxvalue, make_LUT)
cv2.createTrackbar("WW", "dcm_image", (maxvalue // 4), maxvalue, make_LUT)

def make_LUT(val):
    pass #何もしない


画像表示

いよいよ画像表示です。画像表示はスライダーをいじるたびに画像を変更しなくてはいけないのでループ構文whileを用いて作成します。

画素値255を超える画像はopenCVでは表示できないので、その処理をやっていきます。

まずは、WLよりWW/2より高いピクセル値を255、 WW/2より低いピクセルを0とした後に、その間のピクセル値を256階調に落とし込んでいく作業が必要になります。その作業をピクセルごとに計算して算出すると非常に処理に時間がかかってしまうのでルックアップテーブルという物を作成します。ルックアップテーブルとは、この数値はこの値という表を作成し、それをピクセルごとに参照することで計算処理を省く処理となります。

ルックアップテーブルを0で初期化した配列を作成します。ルックアップテーブルの最大値は画像の最大値となりますのでスライダーの最大値を取得した時に一緒に作成してしまいましょう。その際、要素数を最大値+1として指定しておきます。 (下のコード30行目)

import fileselect as fs   #ファイルパス取得のモジュールをインポート
import numpy np
import pydicom
import math
import copy

filenames = fs.multi_fileselect

dcm = pydicom.dcmread(filenames[0])
row,columns = dcm.pix_array.shape[0],dcm.pix_array.shape[1]
       #読み込んだ画像の横方向を変数row、縦方向を変数columnsとして取得します。

dcm_copy = np.zeros((len(filenames), row, columns),dtype = int)
       #dcm_copyという名前で0で初期化した配列を作成

for i in range(len(filenames)):
    dcm = pydicom.dcmread(filenames[i])
    dcm_arr = dcm.pixel_array
    dcm_copy[i] = dcm_arr.astype(np.int64) 
      #np.int64としてデータの型を指定しておきます。

dcm_main = copy.deepcopy(dcm_copy)
      #深いコピーで複製します。

cv2.namedWindow('dcm_image',cv2.WINDOW_NORMAL)
      #ウインドウ名を'dcm_image'とし、ウインドウサイズを変更できるように設定

maxvalue = dcm_copy.max().astype(np.int64)
lookup_tbl = np.zeros(maxvalue+1, dtype=np.int64)
      #作成要素数を最大値+1としておく。

cv2.createTrackbar("WL", "dcm_image", (maxvalue // 2), maxvalue, make_LUT)
cv2.createTrackbar("WW", "dcm_image", (maxvalue // 4), maxvalue, make_LUT)

while 1:
    wl = cv2.getTrackbarPos('WL', 'dcm_image')
    ww = cv2.getTrackbarPos('WW', 'dcm_image')

    ww_low = wl - ww // 2
    ww_high = wl + ww // 2
    lookup_tbl[0:ww_low] = 0
    lookup_tbl[ww_high:maxvalue] = 255
    for i in range(ww_low, ww_high, 1):
        lookup_tbl[i] = math.ceil((i - ww_low) * (256 / (ww_high - ww_low)))

    dcm_copy = lookup_tbl[dcm_main]

    dcm_copy =cv2.convertScaleAbs(dcm_copy, alpha=255/dcm_copy.max())
    cv2.imshow('dcm_image', dcm_copy[0])

    k = cv2.waitKey(1)
    if k == ord('q'):
        break

def make_LUT(val):
    pass #何もしない

スライダーの値を取得し、WLよりWW/2より高いピクセル値を255に WLよりWW/2より低いピクセル値を0にします。(上のコード42~43行目)

WWの間は1階調がどのくらいに当たるかを計算します。上記コード45行目の計算で求めます。ceil は小数点以下切り上げる構文となります。ちなみに、mathというライブラリの構文となりますのでmathもインポートしておいてください。

ルックアップテーブルの作成はこれで完了です。では画像のピクセル値をルックアップテーブルの値に当てはめる作業になるのですが、 ピクセルデータをそのまま変更してしまうと次にスライダーを動かした時、ルックアップテーブルを適応したピクセルデータにスライダーの設定が反映され画像表示がおかしくなってしまいますので画像ピクセルデータをdcm_mainとして複製しておきましょう。その際、普通に dcm_main =dcm_copyとしてもコピーされません。上記コードは参照という意味になってしまいます。これはpythonでは、浅いコピーということであり、今回は深いコピーという方法をつかって別の配列として作成してあげる必要があります。

深いコピーをしていきます。まず、copyというライブラリをインポート(5行目)します。その後、深いコピーをします。(上記コード23行目)

それでは、ルックアップテーブルを反映していきます。47行目のコードで反映されますが、 反映する配列は dcm_mainとし結果をdcm_copyとします。

いよいよ画像表示に入っていくのですが、実は 先ほどのceil関数は計算結果を切り上げ処理している関係で255階調をオーバーすることがありますのでここでまた255階調に落とし込む作業が必要になります。

cv2.convertScaleAbs(dcm_copy, alpha=255/dcm_copy.max())

cv2.convertScaleAbs はエッジ処理でよく使われるコードです。興味がある方は調べてみてください。

後は、忘れがちな待機処理(コード52行目から54行目)を書いて終了です。

正直、画像表示はImage-Jなど使えば簡単に表示できるのですが。これからいろいろと画像処理をしていこうと考えると避けては通れない道ですね。頑張っていきましょう!!
長くなりました。。。。。お疲れ様です。



広告
デル株式会社

環境

  • windows10
  • python3.6.1
  • Anaconda custom(64-bit)
  • PyCharm2020.2(Communication Edition)

広告
上新電機 パソコン買取サービス
The post MRI画像をスライダーを使ってウインドウ調整2(OpenCv編) first appeared on 診療放射線技師がPythonをはじめました。.]]>
463
MRI画像をスライダーを使ってウインドウ調整1(OpenCv編) http://radiology-technologist.info/post-450 Sat, 21 Mar 2020 13:02:27 +0000 http://radiology-technologist.info/?p=450 以前「CT画像のWW、WLをスライダーを使って調整 […]

The post MRI画像をスライダーを使ってウインドウ調整1(OpenCv編) first appeared on 診療放射線技師がPythonをはじめました。.]]>
以前「CT画像のWW、WLをスライダーを使って調整」の記事を書きましたが、こちらはmatplotlibを用いた記事でした。

今回はOpenCVを用いた記事を書いていこうと思います。

ちなみに、タイトルに「MRI画像」と記載していますが 、画像表示においては、CT画像の時と考え方は同じです。 何が違うのかというと、MRI画像の信号はCT値の様に水を0、空気を‐1000といった明確な基準は無く、生体から受信した信号値となりRFの送信時のゲインにより同一組織であっても信号値が変動するところがCTと違います。


スライダーを表示するには?

CpenCVを用いて画像表示し、そこにスライダーを表示するのは、

cv2.createTrackbar( name , window_name , initial_value , max_value , definition )

で作成します。

第1引数の’name’はスライダーの名前です。

第2引数の’window_name’スライダーを表示する画像表示のウインドウの名前です。

第3引数の’ initial_value ‘は初期値です。ちなみに、スライダーの最小値は0で変えることはできません。

第4引数の’max_value’は最大値です。

第5引数の’ definition ‘は関数を指定できます。

今回はウインドウレベルとウインドウ幅を指定したいのでww,wlという名前のスライダーを2つ用意します。

cv2.createTrackbar(“WL”, “dcm_image”, (maxvalue // 2), maxvalue, make_LUT)
cv2.createTrackbar(“WW”, “dcm_image”, (maxvalue // 4), maxvalue, make_LUT)

上記のコードでは、WLとWWという名前のスライダーを用意しました。それぞれ “dcm_image” という名前の画像表示に設置。

WLの初期値は最大値の半分の値に、 WWの初期値は最大値の4分の1の値に指定しました。( maxvalue は私自身がコード内で指定した 変数です。) 最大値はそれぞれ、 maxvalue 。スライダーを動かした時の関数は make_LUT という事になります。


広告
デル株式会社

スライダーの値を取得するには?

スライダーを動かした時の値の取得は以下のコードで行います。

cv2.getTrackbarPos(name, image_name)

第一引数のnameはスライダー名です。

第二引数は画像表示ウインドウの名前です。


広告
HP Directplus -HP公式オンラインストア-

matplotlibとopenCVの違い

以前、matplotlibを用いて「CT画像のWW、WLをスライダーを使って調整」をやった時は、最大のピクセル値と最小のピクセル値を指定しカラーマップを指定して表示するという形でしたが、openCVでは画像表示の最大値と最小値を指定して表示という事ができませんので、工夫が必要となります。

その対策として、ルックアップテーブルを作成します。このルックアップテーブルとは信号値1のピクセルデータはルックアップテーブル1に格納されている値。信号値500のピクセルデータはルックアップテーブル500に格納されている値と、信号値とルックアップテーブルの要素番号に格納されている値を対応させ、その値を画像サイズと同じ配列を作成し対応する場所にルックアップテーブルの対応する値を入れてあげ、その配列を表示する必要があります。


広告
BTOパソコン・パソコン関連商品がお買い得!パソコン工房のセール

コードの流れを考える

それでは、コードを書いていくための流れを組み立てたいと思います。

  1. 画像パスの取得( 「画像選択のプログラムを使いやすく」 のモジュール使用)
  2. 画像表示用の配列を作成
  3. 作成した配列に画像のピクセルデータを入れる
  4. スライダーの作成
  5. 画像表示

といった流れになります。

次はコードを書いていきたいと思います。


続きはこちら


広告
上新電機 パソコン買取サービス
The post MRI画像をスライダーを使ってウインドウ調整1(OpenCv編) first appeared on 診療放射線技師がPythonをはじめました。.]]>
450