Loading [MathJax]/extensions/tex2jax.js

[ipywidgets] 16. IntSliderとprofile_lineで画像の任意の位置の強度プロファイルを取得して表示

ipywidgets

はじめに

jupyter notebookの対話的にパラメータを選択できる機能(ipywidgets IntSlider)で、scikit-image measureのprofile_lineを使って、画像の任意の位置の強度プロファイルを取得して表示する方法について説明する。
なお、profile_lineについては下記記事で解説した。

[scikit-image] 71. 画像の強度プロファイルを任意の範囲で表示(skimage.measure profile_line)
skimage.measureのprofile_lineで、任意の範囲の画像の強度プロファイルを表示する方法について説明する。

コード

%matplotlib notebook
import numpy as np
import matplotlib.pyplot as plt
from ipywidgets import interact,interactive,IntSlider,HBox,VBox
from mpl_toolkits.axes_grid1 import make_axes_locatable
from scipy import ndimage
from skimage.measure import profile_line
from IPython.display import display
plt.rcParams['font.size']=12
plt.rcParams['font.family'] = 'sans-serif'
#make data
n = 3
s = 128
im = np.zeros((s, s))
points = (s*np.random.random((2, n**2))).astype(int)
im[points[0], points[1]] = 10000
im = ndimage.gaussian_filter(im, sigma=s/(5.*n))
fig, ax = plt.subplots(ncols=2,figsize=(8,4))
img = ax[0].imshow(im, cmap=plt.cm.gist_earth, interpolation='gaussian',origin='upper',alpha=1)
ax[0].set_xlabel("x")
ax[0].set_ylabel("y")
divider = make_axes_locatable(ax[0])
cax = divider.append_axes("top", size="5%", pad=0.02)
plt.colorbar(img, cax=cax,orientation='horizontal')
cax.xaxis.set_ticks_position('top')
start_, = ax[0].plot([],[],'ro',lw=3)
end_, = ax[0].plot([],[],'ro',lw=3)
line, = ax[0].plot([],[],'r-',lw=3)
pro, = ax[1].plot([],[],'.-')
ax[1].set_xlabel("position")
ax[1].set_ylabel("Intensity")
plt.tight_layout()
x_s = IntSlider(min=0, max=127,step=1,value=0, description="x_start: ",
orientation='horizontal')
y_s = IntSlider(min=0, max=127,step=1,value=0, description="y_start: ",
orientation='horizontal')
x_e = IntSlider(min=0, max=127,step=1,value=127, description="x_end: ",
orientation='horizontal')
y_e = IntSlider(min=0, max=127,step=1,value=127, description="y_end: ",
orientation='horizontal')
def f(x_s,y_s,x_e,y_e):
start_.set_data([x_e,y_e])
end_.set_data([x_s,y_s])
line.set_data([[x_e,x_s],[y_e,y_s]])
profile = profile_line(im,[y_s,x_s],[y_e,x_e],linewidth=1)
pro.set_data([[np.arange(len(profile))],profile])
ax[1].set_xlim(0,len(profile))
ax[1].set_ylim(0,profile.max()+1)
ax[1].set_title('data points = '+str(profile.shape[0])+'')
out =interactive(f,x_s=x_s,y_s=y_s,x_e=x_e,y_e=y_e)
hbox1 = HBox([x_s, x_e])
hbox2 = HBox([y_s, y_e])
ui = VBox([hbox1, hbox2])
display(ui)

解説

モジュールのインポートなど

%matplotlib notebook
import numpy as np
import matplotlib.pyplot as plt
from ipywidgets import interact,interactive,IntSlider,HBox,VBox
from mpl_toolkits.axes_grid1 import make_axes_locatable
from scipy import ndimage
from skimage.measure import profile_line
from IPython.display import display
plt.rcParams['font.size']=12
plt.rcParams['font.family'] = 'sans-serif'

画像データの作成

n = 3
s = 128
im = np.zeros((s, s))
points = (s*np.random.random((2, n**2))).astype(int)
im[points[0], points[1]] = 10000
im = ndimage.gaussian_filter(im, sigma=s/(5.*n))

用いる画像については、下記記事と同様に作成した。

[matplotlib] 57. plt.imshow()で軸を画像から離して表示
matplotlibのplt.imshowで画像を表示する際に、軸を画像から離して表示する方法について説明する。

画像の表示

fig, ax = plt.subplots(ncols=2,figsize=(8,4))
img = ax[0].imshow(im, cmap=plt.cm.gist_earth, interpolation='gaussian',origin='upper',alpha=1)
ax[0].set_xlabel("x")
ax[0].set_ylabel("y")
divider = make_axes_locatable(ax[0])
cax = divider.append_axes("top", size="5%", pad=0.02)
plt.colorbar(img, cax=cax,orientation='horizontal')
cax.xaxis.set_ticks_position('top')

make_axes_locatableでカラーバーを画像の上に表示した。cax.xaxis.set_ticks_position(‘top’)でカラーバーの目盛りが上側に来るようにした。

ipywidgetsの設定

plotの作成

start_, = ax[0].plot([],[],'ro',lw=3)
end_, = ax[0].plot([],[],'ro',lw=3)
line, = ax[0].plot([],[],'r-',lw=3)
pro, = ax[1].plot([],[],'.-')

widgetsで取得した値を用いてプロットを表示するためにデータが空のプロットを作成しておく。

proはskimageのprofile_lineで取得したデータを表示するためにプロットであり、画像の横のax[1]に表示する。

IntSliderの作成

x_s = IntSlider(min=0, max=127,step=1,value=0, description="x_start: ",
orientation='horizontal')
y_s = IntSlider(min=0, max=127,step=1,value=0, description="y_start: ",
orientation='horizontal')
x_e = IntSlider(min=0, max=127,step=1,value=127, description="x_end: ",
orientation='horizontal')
y_e = IntSlider(min=0, max=127,step=1,value=127, description="y_end: ",
orientation='horizontal')

プロファイルの開始点の座標と終了点の座標を取得するためにIntSliderを作成する。

Sliderの値を変えたときに行う処理

def f(x_s,y_s,x_e,y_e):
start_.set_data([x_e,y_e])
end_.set_data([x_s,y_s])
line.set_data([[x_e,x_s],[y_e,y_s]])
profile = profile_line(im,[y_s,x_s],[y_e,x_e],linewidth=1)
pro.set_data([[np.arange(len(profile))],profile])
ax[1].set_xlim(0,len(profile))
ax[1].set_ylim(0,profile.max()+1)
ax[1].set_title('data points = '+str(profile.shape[0])+'')

set_dataで選択した値を用いて、画像上にプロファイルを取得する範囲を点と線で示す。
profile_lineに取得した座標を入れて、プロファイルを得る。得たプロファイルも同様にset_dataでデータをセットすることで表示する。

Widgetsの有効化と表示

out =interactive(f,x_s=x_s,y_s=y_s,x_e=x_e,y_e=y_e)
hbox1 = HBox([x_s, x_e])
hbox2 = HBox([y_s, y_e])
ui = VBox([hbox1, hbox2])
display(ui)

interactiveで関数fを有効にし、ipywidgetsが動作するようにする。
widgetsはHBox とVBoxを用いて、整列させたものを作成して、それをdisplay(ui)で表示した。

IntSliderを変化させたときの強度プロファイルの変化

コードをダウンロード(.pyファイル)

コードをダウンロード(.ipynbファイル)

参考

Using Interact — Jupyter Widgets 8.1.5 documentation
https://ipywidgets.readthedocs.io/en/latest/examples/Widget%20List.html

コメント