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 6114easy-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 6114urvanov-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 6114breadcrumb-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 6114advanced-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 6114lancr
ドメインの翻訳の読み込みが早すぎました。これは通常、プラグインまたはテーマの一部のコードが早すぎるタイミングで実行されていることを示しています。翻訳は init
アクション以降で読み込む必要があります。 詳しくは WordPress のデバッグをご覧ください。 (このメッセージはバージョン 6.7.0 で追加されました) in /virtual/mcu03iphuk/public_html/radiology-technologist.info/wp-includes/functions.php on line 6114プログラムを組んでいる時、マウスを使って何かをしたいという事はとても多いと思います。そこで、今回はそのマウスコントロール(マウスイベント)を紹介したいと思います。
マウスイベントの種類としては、
の3つのイベントがあります。それぞれ
と名前が付けられています。イベントを呼び出すコードは
fig.canvas.mpl_connect('イベント名', イベントが発生した時の動作を記した関数)
で呼び出します。よって、マウスをクリックした時、クリックを離した時、マウスホイールを回した時のイベント呼び出しは以下となります。
#クリック時 fig.canvas.mpl_connect('button_press_event', on_button_press) #クリックを離した時 fig.canvas.mpl_connect('button_release_event', on_button_release) #マウスホイールを回した時 fig.canvas.mpl_connect('scroll_event', wheel_scroll)
マウスには右クリック、マウスホイールクリック、左クリックの3種類があります。
OpenCvの場合は、それぞれが独立していますが、matplotlibでは、一つのイベントとしてまとめられています。
ではどのようにして区別しているかというと、左クリックをした時は”1”、マウスホイールを押した時は”2”、右クリックを押した時は”3”とevent.buttonという変数に番号が返されます。
なので、関数内に下の様なコードを記すことで機能を分けることができます。
def on_button_press(event): # マウスクリック if event.button == 1: ~~~ ~~~ if event.button == 2: ~~~ ~~~ if event.button == 3: ~~~ ~~~
それでは、簡単なコードを紹介します。
左クリックを押すころで背景色を”青”、マウスホイールを押すことで”白”、右クリックを押すことで”赤”に変えるプログラムを紹介します。
# -- coding utf-8 -- import matplotlib.pyplot as plt def on_button_press(event): if event.button == 1: print(event) fig.patch.set_facecolor('blue') if event.button == 2: print(event) fig.patch.set_facecolor('white') if event.button == 3: print(event) fig.patch.set_facecolor('red') fig.canvas.draw() fig = plt.figure() fig.canvas.mpl_connect('button_press_event', on_button_press) plt.show()
上記コードを実行すると以下のようになります。
eventの情報を表示したものになります。中にはダブルクリックの情報もありますので、ダブルクリックしたら背景色が”緑色”になるコードを追加してみたいと思います。(下記コード10行~13行目)
※dbclickではなく、dblclickです。lが入ることに注意してくださいね。
# -- coding utf-8 -- import matplotlib.pyplot as plt def on_button_press(event): if event.button == 1: print(event) fig.patch.set_facecolor('blue') if event.button == 1 and event.dblclick == True: print(event) fig.patch.set_facecolor('green') if event.button == 2: print(event) fig.patch.set_facecolor('white') if event.button == 3: print(event) fig.patch.set_facecolor('red') fig.canvas.draw() fig = plt.figure() fig.canvas.mpl_connect('button_press_event', on_button_press) plt.show()
いかがでしょうか?ダブルクリックの時の動作も指定することができました。
次に、マウスホイールを回した時の処理について書いていきたいと思います。
マウスホイールのイベントは以下で呼び出します。
fig.canvas.mpl_connect('scroll_event', wheel_scroll)
マウスホイールを回した時の関数ないに、eventで返される値を表示するコードを24~25行目に追加します。
# -- coding utf-8 -- import matplotlib.pyplot as plt def on_button_press(event): if event.button == 1: print(event) fig.patch.set_facecolor('blue') if event.button == 1 and event.dblclick == True: print(event) fig.patch.set_facecolor('green') if event.button == 2: print(event) fig.patch.set_facecolor('white') if event.button == 3: print(event) fig.patch.set_facecolor('red') fig.canvas.draw() def wheel_scroll(event): print(event) fig = plt.figure() fig.canvas.mpl_connect('button_press_event', on_button_press) fig.canvas.mpl_connect('scroll_event', wheel_scroll) plt.show()
マウスホイールを回した時の動作はクリック時の時と同じevent.buttonの変数に”up”、”down”で返ってきいることが分かります。
サンプルコードです。
マウスホイールを回した時に背景色が変わるプログラムを作成します。
まずは、カラーリストを作成します。(下記コード28行目)
続いてcolの変数を宣言し(下記コード46行目)、その変数の番号によってリストにある色を背景色として指定します。(下記コード41行目)
colの変数のglobal化をお忘れなく(下記コード25行目)忘れてしまうと、マウスホイールを回しても変数が0でリセットされてしまいます。
後は、マウスホイールを回すことでcolの変数を変えるコードを書きます。(下記コード30~38行目)32~33行目、37~38行目はcolの変数がリストの要素数を超えた場合にリストの最初と、最後に戻すためのものです。
# -- coding utf-8 -- import matplotlib.pyplot as plt def on_button_press(event): if event.button == 1: print(event) fig.patch.set_facecolor('blue') if event.button == 1 and event.dblclick == True: print(event) fig.patch.set_facecolor('green') if event.button == 2: print(event) fig.patch.set_facecolor('white') if event.button == 3: print(event) fig.patch.set_facecolor('red') fig.canvas.draw() def wheel_scroll(event): global col print(event) colorlist = ["r", "g", "b", "c", "m", "y", "k", "w"] if event.button == "up": col -= 1 if col == -1: col = 7 if event.button == "down": col += 1 if col == 7: col = 0 print(col) fig.patch.set_facecolor(colorlist[col]) fig.canvas.draw() fig = plt.figure() col = 0 fig.canvas.mpl_connect('button_press_event', on_button_press) fig.canvas.mpl_connect('scroll_event', wheel_scroll) plt.show()
いかがでしたか?マウスホイールを回すことで背景色が変わるプログラムはできましたか?
今回、クリックを離した時の動作の説明は省略させていただきましたが、クリックした時と同様ですので試してみてください。
マウスコントロールは、画像上でroiを設定したり、WW,WLの変更、マウスホイールは画像を切り替えてみたりと業務上でも常に使っている機能です。
この機能を設定できるようになればプログラムの幅も広がり楽しくなること間違いなしです。
是非、使ってみてください。
次回は、matplotlibで何かのキーを押した時のイベントをやってみたいと思います。
http://radiology-technologist.info/post-1847
ただ、今回切り替えていく画像はDICOM画像ではなくてピング形式や、ビットマップ等の一般的な画像ファイルとします。
右クリック(左クリック)した時の動作や、マウス中央のマウスホイールをクルクルっとした時の動作をマウスイベントと言います。
今回は、そのマウスイベントを使って画像を切り替えていくことをやろうと思っているのですが、Image-Jなどの画像ビューアではマウスホイールで画像切り替えを行っていると思いますので、それを真似してコードを作成していきたいと思います。
まずは、ざっくりと手順を。
といった流れでやっていきます。
マウスイベントは、関数を作って指定していきますので、まずは関数のおさらいです。関数は
def ○○(引数1 ,引数2):
で指定していきます。なお、関数内のコードは字を下げて記載していきます。(Tabキーで文字を下げていきますが、プログラム作成用のソフトを使う場合、大抵初めの一行目を下げれば、それ以降も自動で字下げをやってもらえます。)
それでは、本題のマウスイベントに入ります。関数名はどんな名前でも構わないのですが、マウス動作なのでonMouseとしてみましょう。
def onMouse(event,x,y,flag,param):
def onMouse(event,x,y,flag,param):
マウスイベントには指定しなければならない引数がいくつかあります。ここで引数の説明をします。
引数のeventとは、マウスの操作を指します。
クリックを押した時なのか、クリックを押しながら動かした時なのか、クリックを上げた時なのか、マウスホイールを動かした時なのか等さまざまな指定ができます。
等、いろんなイベントがありますが今回は、マウスホイールの動作なので
cv2.EVENT_MOUSEWHEEL:を使います。
(なお、マウスイベントはOpenCVの動作になりますので、OpenCVをインポートするのを忘れないでくださいね。)
なので、プログラム的に
「もし、マウスホイールを回したら」という構文を作ります。なので
# coding: UTF-8 def onMouse(event, x, y, flag, params): if event == cv2.EVENT_MOUSEWHEEL:
イベントが起こった画像上の座標を指します。
今回は意味はありません。
flagとは、イベントと同時に起こした動作です。
例えば、shiftキーを押しながらとか、ctrlキーを押しながらとか言ったことです。
今回のマウスホイールの場合は、数値が入ってきます。
マウスホイールを回した場合手前に回すか、奥に回すかによって正の数、もしくは負の数が返されます。値も、使っているマウスによってさまざまです。
ちなみに、今回はflagで受けた数値は0以上か、0以下で画像を送るか、戻すかの判断します。
paramとは、event,x,y,flag以外で処理に使いたい値をひっくるめて指定できます。
今回は、画像表示した際のウインドウ名や、ファイルを格納した変数を渡すのに使います。使い方として関数の次の行に以下のように指定します。
i,filenames = params
といった感じです。 (i,filenames は以後のコードの中で使う変数なので今は気にしないでください。)
i,filenamesという変数はparamsの中に入っていますよという意味です。
そいれでは、関数を書いていきたいと思います。
前回の記事で書きましたが、複数の画像をダイアログを使って選択した際、変数にその画像のパスが保存されます。そのパスを一個一個取り出して画像表示をしていかなくてはいけません。
1個目のパスを取り出して 画像を表示した次は、2個目のパスを取り出して表示、次は3個目のパスを取り出して表示と順番にやっていく。
i番目の画像パスを取り出したいときは
filenames[i]といった書き方になると記載しました。(filenamesはファイルパスを入れた変数名です。)
なので、マウスホイールを動かした時にiが変わる処理を書きます。
マウスホイールが動いた時には引数のflagの引数に正、もしくは負の数が入ってきますので
もし、正の数であったら画像を送る(画像番号がiだったらi+1の画像表示)負の数であったら画像を戻す( 画像番号がiだったらi-1の画像表示)
# coding: UTF-8 def onMouse(event, x, y, flag, params): i,filenames= params if event == cv2.EVENT_MOUSEWHEEL: # ホイールを回したときの動作 if flag > 0: #もしflagが正の数だったら画像番号iを1引く i -= 1 # -= とはiの数から1を引いた数をiに代入すること # -=が気に入らなかったらi = i-1でもOK elif flag < 0: #もしflagが負の数だったら画像番号iを1足す i += 1 # += とはiの数から1を引いた数をiに代入すること # +=が気に入らなかったらi = i+1でもOK
13行目
if i < 0: #もし、iが0より小さかったら
となっていたら文字化けしていますので ”<” 部分を ”<” と直してください。
これで、画像番号を示す変数iを変える処理は完成です。簡単でしょ?
しかし、このままではiが負になったり、iが変数の要素(選択したファイル数)以上の数になった際には画像表示できませんとエラーになってしまいます。
今度は、その処理を書いていきます。
内容は、
もしiがマイナスになるようだったらiは0のまま。
もしiが要素数以上になるようだったらiはそのまま
といった処理を付け加えておきます。
# coding: UTF-8 def onMouse(event, x, y, flag, params): wname, img ,i,filenames= params if event == cv2.EVENT_MOUSEWHEEL: # ホイールを回したときの動作 if flag > 0: #もしflagが正の数だったら画像番号iを1引く i -= 1 # -= とはiの数から1を引いた数をiに代入すること elif flag < 0: #もしflagが負の数だったら画像番号iを1足す i += 1 # += とはiの数から1を引いた数をiに代入すること if i < 0: #もし、iが0より小さかったら i = 0 #iは0 if i > len(filenames)-1: #もし、iが要素数以上だったら i = len(filenames)-1 #要素数より1少ない数に
ここでlen(filenames)が出てきましたが、lenとは要素の数を返す関数となるのでファイル選択した数となります。
len(filenames)-1 となっているのはプログラム上、数は0からカウントするからです。(人間は1から数えるので-1しないとずれてしまいます。)
次に、今回は画像表示を何度も繰り返す動作になるので画像表示のコード自体を関数と作成してしまいましょう。
今回はDICOM画像ではなく、一般的な画像形式(png,bitmap,jpg)の画像を表示していきます。(DICOM画像だと、WW,WLの設定もコードに入れなければならない為、簡素化のために一般的画像形式としました。)
使うモジュールはマウスイベントでOpenCVを使っているので、同じOpenCVで開こうと思います。
画像を開く際はまず、画像を変数内に読み込みます。
img = cv2.imread(filenames[i])
そして、画像表示のウインドウ名を決めなければなりません。
今回は、window名なので変数名wnameとしてそこにimgと名付けます。
wname = “img”
最後に、画像表示のコードを付けます。コードは以下となり、引数は
cv2.imshow(ウインドウ名,画像のパス)
となるので
cv2.imshow(wname, img)
となります。
これで画像表示ができるかといえばできません。よく忘れてしまうのですが画像表示後をいつまで続けるのか?といった指定をしなければいけません。忘れてしまうと画像が一瞬開いてすぐに閉じてしまいます。見た目には画像が表示されたことに気が付かず、おかしいな?と思ってしまいます。私はこれに気が付かず苦労しました。
cv2.waitKey()
上記処理は、何かキーが押されるまで待ちます。
cv2.destroyAllWindows()
何か押されたらすべてのウインドウを閉じる処理となります。
def imageshow(filenames,i): img = cv2.imread(filenames[i]) wname = "img" cv2.imshow(wname, img) print(str(i) + " image " + filenames[i]) #確認用。コンソールに変数の番号とイメージパスを表示 cv2.setMouseCallback(wname, onMouse, [i, filenames]) cv2.waitKey() cv2.destroyAllWindows()
マウスイベントと、画像表示、ダイアログを使ってファイルを選択の関数を一つのファイルに入れ、それらを繋げていきましょう。
順番はどうでもいいですが、まずマウスイベントのファイルを入れ、ファイルセレクト、その後に、画像表示の関数を入れていきましょう。
その際、OpenCV、tkinterのimportを忘れないでくださいね。
# coding: UTF-8 import cv2 import tkinter from tkinter import filedialog as tkFileDialog def onMouse(event, x, y, flag, params): i, filenames= params if event == cv2.EVENT_MOUSEWHEEL: # ホイールを回したときの動作 if flag > 0: #もしflagが正の数だったら画像番号iを1引く i -= 1 # -= とはiの数から1を引いた数をiに代入すること elif flag < 0: #もしflagが負の数だったら画像番号iを1足す i += 1 # += とはiの数から1を引いた数をiに代入すること if i <= 0: #もし、iが0より小さかったら i = 0 #iは0 elif i >= len(filenames)-1: #もし、iが要素数以上だったら i = len(filenames)-1 #要素数より1少ない数に imageshow(filenames, i) def fileselect(): root = tkinter.Tk() root.withdraw() fTyp = [('', '*')] iDir = 'C:/Desktop' filenames = tkFileDialog.askopenfilenames(filetypes=fTyp, initialdir=iDir) return filenames # 選択ファイルの絶対パスを返します。 def imageshow(filenames,i): img = cv2.imread(filenames[i]) wname = "img" cv2.imshow(wname, img) print(str(i) + " image " + filenames[i]) cv2.waitKey() cv2.destroyAllWindows()
上記の様になります。ただ、これだけではプログラムは動かないのでそれらを関連付けてあげましょう。
プログラムの流れは、
となります。
filenamesという変数に選択した画像ファイルのパスを入れたいので
初めは
filenames = fileselect()
とし、ダイアログを使ってファイルを選択する関数(fileselect)を呼び出し、returnで返されたリストをfilenamesの変数にいれます。
今度は、そのリストを画像表示(imageshow)の関数で画像表示しましょう。
imageshowの関数にリスト(filenames)を渡してそのリストの中から画像表示をさせます。その際、はじめに表示する画像はリストに入っている初めの画像にしたいので変数iを0に設定します。
i=0
imageshow(filenames,i)
これで、画像表示がでます。
はじめに、マウスホイールの関数を書きましたがそれだけでは、マウスイベントは動きません。
動かすにはマウスイベントを呼び出すコードが必要となります。
マウスイベントを呼び出すにはcv2.setMouseCallbackという関数を使います。
windowとはどのウインドウでのマウスイベントなのかを指定します。
wnameです。
onMouseはどの関数名を呼び出すかという事です。
onMouse関数のparamsの渡す引数を指定します。複数ある場合は[]で指定します。
今回はiとfilenamesを渡しますので[i,filenames]となります。
マウスイベントは、画像が表示されてから閉じられるまでの間になるので上記コードの39行目になります。
cv2.setMouseCallback(wname, onMouse, [i, filenames])
のコードを挿入して終了となります。
# coding: UTF-8 import cv2 import tkinter from tkinter import filedialog as tkFileDialog def onMouse(event, x, y, flag, params): i, filenames= params if event == cv2.EVENT_MOUSEWHEEL: # ホイールを回したときの動作 if flag > 0: #もしflagが正の数だったら画像番号iを1引く i -= 1 # -= とはiの数から1を引いた数をiに代入すること elif flag < 0: #もしflagが負の数だったら画像番号iを1足す i += 1 # += とはiの数から1を引いた数をiに代入すること if i <= 0: #もし、iが0より小さかったら i = 0 #iは0 elif i >= len(filenames)-1: #もし、iが要素数以上だったら i = len(filenames)-1 #要素数より1少ない数に imageshow(filenames, i) def fileselect(): root = tkinter.Tk() root.withdraw() fTyp = [('', '*')] iDir = 'C:/Desktop' filenames = tkFileDialog.askopenfilenames(filetypes=fTyp, initialdir=iDir) return filenames # 選択ファイルの絶対パスを返します。 def imageshow(filenames,i): img = cv2.imread(filenames[i]) wname = "img" cv2.imshow(wname, img) print(str(i) + " image " + filenames[i]) cv2.setMouseCallback(wname, onMouse, [i, filenames]) cv2.waitKey() cv2.destroyAllWindows() filenames = fileselect() i=0 imageshow(filenames,i)
いかがでしょうか?
きちんと動きましたか?