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日記。解析等で使えるコードを作成、アップしていきたいと思っています。その他いろいろ Sat, 05 Sep 2020 07:56:19 +0000 ja hourly 1 https://wordpress.org/?v=6.7.1 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 画像間演算、サブトラクションをやってみる。 http://radiology-technologist.info/post-841 Wed, 02 Sep 2020 21:21:33 +0000 http://radiology-technologist.info/?p=841 はじめに 今回は、業務中によく使用する画像間演算で […]

The post 画像間演算、サブトラクションをやってみる。 first appeared on 診療放射線技師がPythonをはじめました。.]]>
はじめに

今回は、業務中によく使用する画像間演算であるサブトラクションをやってみたいと思います。


広告
デル株式会社

コードの流れ

サブトラクションをやるには最低2枚の画像が必要となりますので、画像の読み込み工程を2つ作成します。その際、どちらの画像からどちらの画像を引き算するのか決めなくてはなりませんが、今回はコードを簡単にするため初めに取り込んだ画像から、2枚目に取り込んだ画像をひき算することにします。


続いて、計算結果を格納する配列を作成します。この配列は、取り込んだ画像と同じサイズの配列を作成します。


画像間演算、引き算のコードを書いていきます。


最後に、画像表示のコードを書いて完成となります。


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

コードを書いていく

画像のピクセルデータを取り込む

まずは、画像を読み込む工程からやっていきます。込みこむ工程は、画像のパスを変数に取り込んでから、それをクラスに渡して画像のピクセルデータを配列に取り込み形になります。

それではコードを書いていきたいと思います。

DICOM画像を使いますので、pydicomのインポートをします。

画像の読み込みは、毎回使用しているfileselectのモジュールを使用します。まだ、ご覧になっていない方はこちら。fileselectのファイルは、今回書いているコードと同じフォルダの中に入れておいてくださいね。

今回もフォルダで一括選択する方法で画像を読み込みたいと思います。

# -- coding utf-8 --
import pydicom
import fileselect as fs

filenames = fs.folder_fileselect()


まずは、fileselectのモジュールを用いてフォルダ内の画像パスをfilenamesの変数に取り込みます。

そして、その変数をClassに渡し画像のピクセルデータを配列に取り込みます。

以前の記事から、Classの部分のコードをコピーします。画像読み込みをクラスを使ってやってみたの記事はこちらの記事を参照ください。

クラスがよくわからない方はこちらを参照ください。

このクラスではnumpyを用いていますのでnumpyのインポートを忘れないようにしましょう。

# -- coding utf-8 --
import pydicom
import fileselect as fs
import numpy as np

class Pixarr:
    def __init__(self,filenames):
        dcm = pydicom.dcmread(filenames[0])
 
        self.row = dcm[0x0028,0x0010].value
        self.column = dcm[0x0028,0x0011].value
        self.ww = dcm[0x0028,0x1050].value
        self.wl = dcm[0x0028,0x1050].value
 
        self.pix_arr = np.zeros((len(filenames),self.row,self.column),
            dtype ='int16')
 
        if len(filenames) == 1:
            self.pix_arr = dcm.pixel_array
        else:
            for i in range(len(filenames)):
                dcm = pydicom.dcmread(filenames[i])
                img_no = dcm[0x0020,0x0013].value    
                self.pix_arr[img_no-1] = dcm.pixel_array

filenames = fs.folder_fileselect()
f0 = Pixarr(filenames)

filenames = fs.folder_fileselect()
f1 = Pixarr(filenames)

読み込んだ画像パスをClassに渡すのですが、ひかれる画像をf0、ひく画像をf1と名前を付けてクラスに渡します。(上記コード28行目)

これで、ひかれる画像のピクセルデータを取り込むことができました。

同様に、引く画像をf1として取り込みます。f0の時と同様にコードを書きます。(上記コード30~31行目)

これで、画像の読み込みは完了です。


画像間演算したデータを格納する配列を作成する

画像間演算のコードを書く前に、計算結果を格納する配列を作成します。

引く画像、引かれる画像と同一サイズの配列を作成します。f0,f1どちらでも構わないのですが同じ大きさの配列f2を作成します。その際に、0で初期化しておきます。

同一サイズの配列を作成するコードは

f2 = numpy.full_like(f0.pix_arr,0)

で作成できます。numpyはインポートする際npの名称でインポートしていますので、実際のコードは下記コード33行目の様にnp.full_likeの形になります。

# -- coding utf-8 --
import pydicom
import fileselect as fs
import numpy as np

class Pixarr:
    def __init__(self,filenames):
        dcm = pydicom.dcmread(filenames[0])
 
        self.row = dcm[0x0028,0x0010].value
        self.column = dcm[0x0028,0x0011].value
        self.ww = dcm[0x0028,0x1050].value
        self.wl = dcm[0x0028,0x1050].value
 
        self.pix_arr = np.zeros((len(filenames),self.row,self.column),
            dtype ='int16')
 
        if len(filenames) == 1:
            self.pix_arr = dcm.pixel_array
        else:
            for i in range(len(filenames)):
                dcm = pydicom.dcmread(filenames[i])
                img_no = dcm[0x0020,0x0013].value    
                self.pix_arr[img_no-1] = dcm.pixel_array

filenames = fs.folder_fileselect()
f0 = Pixarr(filenames)

filenames = fs.folder_fileselect()
f1 = Pixarr(filenames)

f2 = np.full_like(f0.pix_arr,0)


画像間演算、サブトラクションのコード

サブトラクションはピクセル同士の引き算ですので本来であれば

f2[i] = f0.pix_arr[i] – f1.pix_arr[i]

のコードをfou文で繰り返すと考えるかもしれませんが、実はpythonでの配列計算はとても簡単で

f2 = f0.pix_arr – f1.pix_arr

の一文だけで済んでしまいます。もちろん、引き算だけでなく足し算でも使えますし、掛け算、割り算でも使用可能です。

for文でピクセルごとに計算しているよりも全然高速です。

ここまでのコードは以下となります。

# -- coding utf-8 --
import pydicom
import fileselect as fs
import numpy as np

class Pixarr:
    def __init__(self,filenames):
        dcm = pydicom.dcmread(filenames[0])
 
        self.row = dcm[0x0028,0x0010].value
        self.column = dcm[0x0028,0x0011].value
        self.ww = dcm[0x0028,0x1050].value
        self.wl = dcm[0x0028,0x1050].value
 
        self.pix_arr = np.zeros((len(filenames),self.row,self.column),
            dtype ='int16')
 
        if len(filenames) == 1:
            self.pix_arr = dcm.pixel_array
        else:
            for i in range(len(filenames)):
                dcm = pydicom.dcmread(filenames[i])
                img_no = dcm[0x0020,0x0013].value    
                self.pix_arr[img_no-1] = dcm.pixel_array

filenames = fs.folder_fileselect()
f0 = Pixarr(filenames)

filenames = fs.folder_fileselect()
f1 = Pixarr(filenames)

f2 = np.full_like(f0.pix_arr,0)

f2 = f0.pix_arr - f1.pix_arr


画像表示のコード

画像表示はmatplotlibを使用したいと思いますので、まずはmatplotlibをインポートします。

# -- coding utf-8 --
import pydicom
import fileselect as fs
import numpy as np
import matplotlib.pyplot as plt

class Pixarr:
    def __init__(self,filenames):
        dcm = pydicom.dcmread(filenames[0])
 
        self.row = dcm[0x0028,0x0010].value
        self.column = dcm[0x0028,0x0011].value
        self.ww = dcm[0x0028,0x1050].value
        self.wl = dcm[0x0028,0x1050].value
 
        self.pix_arr = np.zeros((len(filenames),self.row,self.column),
            dtype ='int16')
 
        if len(filenames) == 1:
            self.pix_arr = dcm.pixel_array
        else:
            for i in range(len(filenames)):
                dcm = pydicom.dcmread(filenames[i])
                img_no = dcm[0x0020,0x0013].value    
                self.pix_arr[img_no-1] = dcm.pixel_array

filenames = fs.folder_fileselect()
f0 = Pixarr(filenames)

filenames = fs.folder_fileselect()
f1 = Pixarr(filenames)

f2 = np.full_like(f0.pix_arr,0)

f2 = f0.pix_arr - f1.pix_arr

画像表示は引かれる画像、引く画像、計算後の画像の3画像表示したいと思います。

まずは、画像を表示設定からです。matplotlibで画像や、グラフ等を表示する際にまずはfigの設定をし、その後にaxの設定をします。ここが、よくわからないところかもしれませんが、考え方としては何もないところで絵を描こうとするときにまずは、画板や机を準備すると思います。それがfigにあたります。その後、その上に絵を描く紙を準備すると思います。それがaxにあたると考えやすいと思います。

figの設定は

fig = plt.figure()

チュートリアルはこちら

axの設定は

ax = fig.add_subplot()

で設定していきます。チュートリアルはこちら

figの大きさの設定をします。引数の中にfigsize =(横、縦)で設定をします。

fig = plt.figure(figsize=(15, 5))

どこに画像を表示するかはaxの括弧の中に引数として指定します。

ax0 = fig.add_subplot(1,3,1) #一番左に表示
ax1 = fig.add_subplot(1,3,2) #真ん中に表示
ax2 = fig.add_subplot(1,3,3) #一番右に表示

括弧内の初めの引数は縦方向の画像数を、2個目の引数は横方向の画像数、3個目の引数を何番目に画像を表示するかという設定になります。


続いて、axにどの画像を表示するかの設定に入ります。

引かれる画像をax0に、引く画像をax1に、演算後の画像をax2として設定していきます。

ax0.imshow(f0.pix_arr[sl],cmap= 'bone')
ax1.imshow(f1.pix_arr[sl],cmap= 'bone')
ax2.imshow(f2[sl],cmap= 'bone')

これで、画像表示の設定は完了です。

# -- coding utf-8 --
import fileselect as fs
import pydicom
import numpy as np
import matplotlib.pyplot as plt

class Pixarr:
    def __init__(self,filenames):
        dcm = pydicom.dcmread(filenames[0])

        self.row = dcm[0x0028,0x0010].value
        self.column = dcm[0x0028,0x0011].value
        self.ww = dcm[0x0028,0x1050].value
        self.wl = dcm[0x0028,0x1050].value

        self.pix_arr = np.zeros((len(filenames),self.row,self.column),
            dtype ='int16')

        if len(filenames) == 1:
            self.pix_arr = dcm.pixel_array
        else:
            for i in range(len(filenames)):
                dcm = pydicom.dcmread(filenames[i])
                img_no = dcm[0x0020,0x0013].value
                self.pix_arr[img_no-1] = dcm.pixel_array

filenames = fs.folder_fileselect()
f0 = Pixarr(filenames)

filenames = fs.folder_fileselect()
f1 = Pixarr(filenames)


f2 = np.full_like(f0.pix_arr,0)

f2 = f0.pix_arr - f1.pix_arr

fig = plt.figure(figsize=(15, 5))
plt.subplots_adjust(left=0, right=1, bottom=0, top=1, wspace=0.05, hspace=0.05)
ax0 = fig.add_subplot(1,3,1)
ax1 = fig.add_subplot(1,3,2)
ax2 = fig.add_subplot(1,3,3)

ax0.imshow(f0.pix_arr[sl],cmap= 'bone')
ax1.imshow(f1.pix_arr[sl],cmap= 'bone')
ax2.imshow(f2[sl],cmap= 'bone')


axに画像の設定をした際に [sl] とありますが、これは、何枚目の画像を表示するかの変数になります。マウスホイールを回すことで画像を切り替えるための変数です。(上記コードの38行目 sl = 0 とコードを追加してください。)

その機能を実装していきます。

これは、マウスイベントと言って右クリックや、左クリック、マウスホイールを回す、または押す等のイベントで何をするか決められます。

マウスホイールのイベントは

fig.canvas.mpl_connect('scroll_event', wheel_scroll)

動作設定はdefで関数を作成して決めます。今回はwheel_scrollという名前で設定しますが、次回matplotlibのマウスイベントで詳しく説明したいと思いますので今回はコードの提示だけとします。

# -- coding utf-8 --
import fileselect as fs
import pydicom
import numpy as np
import matplotlib.pyplot as plt

class Pixarr:
    def __init__(self,filenames):
        dcm = pydicom.dcmread(filenames[0])

        self.row = dcm[0x0028,0x0010].value
        self.column = dcm[0x0028,0x0011].value
        self.ww = dcm[0x0028,0x1050].value
        self.wl = dcm[0x0028,0x1050].value

        self.pix_arr = np.zeros((len(filenames),self.row,self.column),
            dtype ='int16')

        if len(filenames) == 1:
            self.pix_arr = dcm.pixel_array
        else:
            for i in range(len(filenames)):
                dcm = pydicom.dcmread(filenames[i])
                img_no = dcm[0x0020,0x0013].value
                self.pix_arr[img_no-1] = dcm.pixel_array

def wheel_scroll(event):
    global sl

    if event.button == 'down':
        sl += 1
        if sl > len(filenames)-1:
            sl =0

    if event.button == 'up':
        sl -= 1
        if sl < 0:
            sl = len(filenames)-1

    ax0.imshow(f0.pix_arr[sl], cmap='bone')
    ax1.imshow(f1.pix_arr[sl], cmap='bone')
    ax2.imshow(f2[sl], cmap='bone')

    fig.canvas.draw()

filenames = fs.folder_fileselect()
f0 = Pixarr(filenames)

filenames = fs.folder_fileselect()
f1 = Pixarr(filenames)

f2 = np.full_like(f0.pix_arr,0)

f2 = f0.pix_arr - f1.pix_arr

sl =0

fig = plt.figure(figsize=(15, 5))
plt.subplots_adjust(left=0, right=1, bottom=0, top=1, wspace=0.05, hspace=0.05)
ax0 = fig.add_subplot(1,3,1)
ax1 = fig.add_subplot(1,3,2)
ax2 = fig.add_subplot(1,3,3)

ax0.imshow(f0.pix_arr[sl],cmap= 'bone')
ax1.imshow(f1.pix_arr[sl],cmap= 'bone')
ax2.imshow(f2[sl],cmap= 'bone')

fig.canvas.mpl_connect('scroll_event', wheel_scroll)

plt.show()

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

最後に

いかがでしたか?お持ちのDICOM画像でサブトラクションできましたでしょうか?

上記コードで実行した結果です。マンモのMRI Dynamic画像、一番左が単純、真ん中が動脈相、一番左がサブトラクション画像となります。

正常乳腺は引き算され、腫瘍は濃染されているのが確認できると思います。

皆さんも試してみてください。

お疲れ様でした。

広告
上新電機 パソコン買取サービス
The post 画像間演算、サブトラクションをやってみる。 first appeared on 診療放射線技師がPythonをはじめました。.]]>
841