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
class | 診療放射線技師がPythonをはじめました。 http://radiology-technologist.info 診療放射線技師のPython日記。解析等で使えるコードを作成、アップしていきたいと思っています。その他いろいろ Sun, 03 Jan 2021 09:03:10 +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 class | 診療放射線技師がPythonをはじめました。 http://radiology-technologist.info 32 32 164362728 画像を読み込みをクラスを使ってやってみた http://radiology-technologist.info/post-770 http://radiology-technologist.info/post-770#respond Thu, 16 Jul 2020 22:56:27 +0000 http://radiology-technologist.info/?p=770 はじめに 私たち診療放射線技師がプログラムを使って […]

The post 画像を読み込みをクラスを使ってやってみた first appeared on 診療放射線技師がPythonをはじめました。.]]>
はじめに

私たち診療放射線技師がプログラムを使って解析を行う時まず初めに画像を読み込むことではないでしょうか。

今まで、私が書いてきたコードは画像読み込みのコードはクラスを使わずに行ってきました。しかし、数回前にクラスの記事を書きましたので、今回はクラスを用いて画像を読み込むコードを書いていきたいと思います。


広告
デル株式会社

コードの流れ

まずは、コードの流れを考えてみましょう。

  1. ファイルを選択
  2. クラスで画像配列を取得

の作業となり、そこで決めなくてはいけないことは以下となります。

  • ファイル選択の方法
  • クラスに持たせる情報
  • ピクセルデータを配列に取り込む方法


ファイル選択の方法

まずはファイルの選択方法です。個別で選択するか、フォルダで選択するか。今回はフォルダで選択する方法をやってみたいと思います。

フォルダで一括の関連記事は以下にありますので興味がある方はご覧ください。

なお、今回も「画像選択のプログラムを使いやすく!!」で作成したモジュールを用います。


クラスに持たせる情報

次にクラスに持たせる情報です。

  • 配列を作成する際に必要な情報として画像の縦、横のピクセル数の情報
  • 適正な条件で画像表示するためにWL,WW

を持たせたいと思います。全て予約タグとなっていますのでほぼすべてのモダリティー画像であるタグです。

ピクセル数のデータは(0028,0010)、(0028,0011)

WW、WLは(0028,1050)、(0028,1051)

に登録されています。

なお、コード中に記載する際は16進数である事を示す”0x”を追加して記載することを忘れずに。


ピクセルデータを配列に取り込む方法

ピクセルデータを画像配列に取り込む作業ですが、今回はフォルダで一括取り込みで行います。以前の記事で記載しましたがフォルダで一括選択の場合は画像番号を文字列とし扱われてしまうので順番に取り込んでいくと画像が途中で飛んでしまいます。

詳しくはこちらの記事でご確認ください(フォルダでファイルを一括選択した時の問題点


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

コードを書いていく

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

ファイルを選択する

まずは、モジュールのインポートです。ファイル選択のモジュールをインポートします。

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

このモジュールは過去の記事で記載していますので以下のリンクよりご確認ください。


インポートしたモジュール内でフォルダでファイル一括選択の関数はfolder_fileselect()で作成してありますので、folder_fileselect()を呼び出しfilenamesの変数で受けとります。(下のコードの5行目になります。)

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

filenames = fs.folder_fileselect()

これで、第1工程のファイルを選択が完了しました。


クラスで画像配列を取得

クラスで画像配列を取得していく工程ですが以下の順に進めていきます。

  1. クラスの宣言
  2. 初期化(初期設定)
  3. ピクセルデータを画像番号順に取得


クラスの設定

まずは、クラスの宣言となりますが、クラスの宣言は関数を書く時と同じで初めを

class

で始めます。その後に名前が続くのですが名前の1文字目を大文字で書くのが通例となっています。

今回の目的は画像の配列を取得することなので名前はPixarrとすることにします。

class Pixarr:

関数の時と違うのはクラスの宣言では引数を受けないという事です。(その後の初期化や、クラス内の関数で引数を受けます。)

ちなみに、クラスの宣言はモジュールや、ライブラリーのインポートの後、コードの初めに書きます。


初期化(初期設定)

初期設定です。初期設定も関数の時と同じですが一つ違うところが関数名は__init__(アンダーバーは前と後ろ2つづつ)で、引数でselfという物が必須という事です。なので

def __init__(self):

という事になります。

当初私は、ここでつまづきました。。。。。selfの意味が分からない。何故こんなことをしなければならないのか。同じように疑問に思われる方は以下の記事に私なりの解釈を記載していますので一読いただければと思います。



話が脱線しました。初期化の話に戻ります。

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

class Pixarr:
    def __init__(self):

filenames = fs.folder_fileselect()

初期化の部分では、それぞれに持たせる情報を設定するところですので持たせたい情報は縦、横のピクセル数、画像番号、WW、WLの5つとなりますので

それぞれ、row、column、ww、wlという変数にしたいと思います。

それぞれのデータは[0028,0010]、[0028,0011]、[0028,1050]、[0028,1051]のタグに登録されています。

ではどの様にしてそのデータを取得するかですが、今回はクラスを呼び出した時(インスタンスを生成するといいます。)にファイルパスを渡し、クラス初期化の時に1枚画像を読み込んでDICOMタグを取得したいと思います。


それでは、コードに足していきたいと思います。

DICOM画像を扱うのでまず、pydicomをインポートします。

そして、引数として受け取ったファイルパスから一番初めの画像を読み込みます。(下記コード8行目)そしてタグを順番に取得します。(下記コード10~14行目)

そして、忘れてはいけないインスタンス生成のコードを足します。(下記コード17行目)

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

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

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

ここまでで、持たせる情報は設定は完了しました。


ピクセルデータを配列に取り込む方法

続いて、ピクセルデータをを配列に取り込んでいく作業に入りたいと思います。

まずは、ピクセルデータを取り込むための0で初期化した配列を生成したいと思います。変数名はpix_arrとします。配列生成はnumpyを使用しますのでライブラリーのインポートをします。(下記コード5行目)

次にピクセルデータを配列に入れていく工程に入るのですが、問題とな事が2つあります。フォルダ内に画像が1枚だけの場合for文で画像取り込みを行うとエラーが出てしまう件。フォルダ内画像が10枚以上になると画像番号を文字列に捉えられてしまい順番に画像が取り込まれない件があります。

まず、画像が一枚の時の対策として、if文で処理を変えていきたいと思います。まずlen関数を用いてfilenamesの数をカウントし、処理を変えることで対策したいと思います。(下記コード19~20)

その次に、画像番号順にピクセルデータを配列に取り込んでいく方法です。

対策としては、画像を込みこんで変数img_noに画像番号を取り込み、画像番号-1の配列にピクセルデータを入れていく感じになります。(下記コード22~25行目)

# -- coding utf-8 --
import fileselect as fs
import pydicom
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)

これで、コードは完了です。

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

確認作業

さて、きちんとクラスを用いて配列内にピクセルデータが取り込まれたか確認作業に入りたいと思います。

まずは、ピクセル数の確認です。コード30行目にprint文で表示してみましょう。

# -- coding utf-8 --
import fileselect as fs
import pydicom
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)

print('画像の縦方向のピクセル数は\t' + str(f0.row))
print('画像の横方向のピクセル数は\t' + str(f0.column))
print('画像のウインドウレベルは\t' + str(f0.wl))
print('画像のウインドウ幅は\t' + str(f0.ww))

いかがでしたか?情報はきちんと表示されましたか?

続いてmatplotlibを用いて画像表示をしてみたいと思います。

まずは、matplotlibのライブラリーをインポートします。(下記コード6行目)

表示する画像番号の変数を指定します。slとして初期値0を指定します。(下記コード36行目)

画像を表示するウインドウ、figの設定をして(下記コード38行目)画像を表示する領域の設定をします。(下記コード39行目)

表示する画像の指定をします。(下記コード41行目)

画像表示のコードを42行目に記載します。

# -- 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)

print('画像の縦方向のピクセル数は\t' + str(f0.row))
print('画像の横方向のピクセル数は\t' + str(f0.column))
print('画像のウインドウレベルは\t' + str(f0.wl))
print('画像のウインドウ幅は\t' + str(f0.ww))

sl =0

fig = plt.figure()
ax = fig.add_subplot()

ax.imshow(f0.pix_arr[sl],cmap= 'bone')
plt.show()

どうですか?画像移動のコードを記載していないので1枚目の画像が表示されましたか?

最後に、トラックボールで画像を変えるコードを書きます。

ここに関しては、今回は長くなっているので詳細を省きたいと思います。(下記コード28~43行目)

とマウスイベントに繋げるコード59行目を記載して完了です。

# -- 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

    ax.imshow(f0.pix_arr[sl], cmap='bone')

    fig.canvas.draw()

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

print('画像の縦方向のピクセル数は\t' + str(f0.row))
print('画像の横方向のピクセル数は\t' + str(f0.column))
print('画像のウインドウレベルは\t' + str(f0.wl))
print('画像のウインドウ幅は\t' + str(f0.ww))

sl =0

fig = plt.figure()
ax = fig.add_subplot()

ax.imshow(f0.pix_arr[sl],cmap= 'bone')
fig.canvas.mpl_connect('scroll_event', wheel_scroll)
plt.show()

いかがでしたか?きちんとトラックボールで画像変更できましたでしょうか?


最後に

クラスを用いて画像ピクセルデータ、DICOMタグの情報を取り込む方法を行いました。画像間演算や、画像比較等2つ以上の画像ファイルを用いて解析をやる時にクラスを用いた方法というのは大変便利です。

是非ともマスターして自分なりに使ってみてください。

お疲れ様でした。


環境

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

広告
上新電機 パソコン買取サービス
The post 画像を読み込みをクラスを使ってやってみた first appeared on 診療放射線技師がPythonをはじめました。.]]>
http://radiology-technologist.info/post-770/feed 0 770
”クラス”って何? http://radiology-technologist.info/post-731 Sat, 27 Jun 2020 01:38:14 +0000 http://radiology-technologist.info/?p=731 はじめに Pythonを使い始めて、なんとも理解し […]

The post ”クラス”って何? first appeared on 診療放射線技師がPythonをはじめました。.]]>
はじめに

Pythonを使い始めて、なんとも理解しにくかったのが”クラス”なるもの。

まずは、インスタンスの生成、イニシャライズ、selfを使わなくてはいけないとか何が何だか、なんでこんなことをしなくてはならないのか・・・・・

まったく理解できませんでした。

クラスなんて使わなくてもリストで対応できるじゃん!!

なんて思っていたのですが、苦労しながらも使っているとクラスって本当に便利な物だなと分かってきました。

今回は、そのクラスなるものの説明をしたいと思います。

ただ、自分なりの解釈なので間違っていたらごめんなさん。


広告
デル株式会社

そもそも、クラスってなんで使うの?

何かの書籍に、同じ属性をもったものを複数扱う時に使うと書いてあった気がします。

同じ属性?単語の意味はわかっても、イメージできない。プログラミングの中で使うものの属性?

わからない。。。。

答えは簡単でした。

職場のスタッフを例えに説明したいと思います。

スタッフは複数人いて、それぞれに名前、性別、年齢、担当モダリティー、所有資格等様々な情報があります。それは、全員が持ち合わせている情報となります。その情報をクラスを使わずに使おうとするとそれぞれに変数名を割り当てるか、リストを作成して対応する場所に情報を格納しなくてはいけません。

変数が増えると、その管理がとても煩雑になりますし、変数を用いた計算をしたい時にそれぞれの変数に対してコードを書く必要ができコードが長くなってしまう事があります。

Aさん、Bさん、Cさん、Dさんを考えましょう。それぞれに変数名を作成してみると

A_name、 A_sex、 A_age、 A_moda、 A_capa

B_name、 B_sex、 B_age、 B_moda、 B_capa

C_name、 C_sex、 C_age、 C_moda、 C_capa

D_name、 D_sex、 D_age、 D_moda、 D_capa

と合計20個の変数が必要になってきます。


リストを使った場合は、何番目にどの情報を入れたか管理しなくてはならなくてとても面倒です。(私は、クラスが分からずにこの方法を取っていましたがすごく煩わしかったです。。。。)

しかし、クラスを使うことで同じ変数名の使いまわしができるようになります。ここから先は、使い方の方で説明していきたいと思います。


私は、以下の本で理解することができました。(Python関連の書籍ではないですが・・・・)クラスの部分だけ理解するのであれば本屋さんで立ち読みでも十分です。オブジェクト指向プログラミングの概要を簡単に知りたければお勧めの書籍です。


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

クラスの使い方

まずは、コードを

class Staff:
    def __init__(self,name,sex,age,moda,capa):
        self.name = name
        self.sex = sex
        self.age = age
        self.moda = moda
        self.capa = capa

staff1 = Staff('A','man','30','MRI','MRI technologist')
staff2 = Staff('B','female','25','Mammo','Mammo technologist')
staff3 = Staff('C','female','50','CT','CT technologist')
staff4 = Staff('D','man','60','Angio','Angio technologist')


クラスを使用するにはまず、インスタンス(staff1やstaff2)といって箱のようなものを作成します。上記コードの10~13行目となります。今回の例では人物を設定します。その設定に名前、性別、年齢、担当モダリティー、所有資格等様々な情報を追加していきます。その作業が初期化にあたり

def __ini__():

の部分にあたります。

私は、ここでつまずきました。何故、selfを使うのか。

答えは簡単で、クラスは同じような物を複数個作成します。なので、同じ変数名も複数個作成されることになるので、自分自身の変数名と示しているのだと思います。ここは、おまじない的に覚えてしまうのがいいと思います。


後は、それぞれの値を使いたい時にインスタンス名(staff1やstaff2)に変数名

インスタンス名.変数名

で呼び出すことができます。例えば以下のようになります。

print(staff2.name + ' さんの所有資格は '+ staff2.capa)
⇒ B さんの所有資格は Mammo technologist

print(staff4.name + ' さんの年齢は '+ staff4.age)
⇒ D さんの年齢は 60

いかがですか?


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

最後に

クラスを使うことで、同じ変数名を使用できる事はすごくすっきりしていいと思いませんか?

また、個人作成でのプログラミングではあまり大きな効果はないかもしれませんが数人でコードを作成していく時にはとても効果があるみたいです。

是非とも、クラスを使いこなして効率よくプログラミングをしていきましょう。

お疲れ様でした。


環境

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

広告
上新電機 パソコン買取サービス
The post ”クラス”って何? first appeared on 診療放射線技師がPythonをはじめました。.]]>
731