ケイエルブイは、ハイパースペクトルカメラ・光学部品・光源など世界中の光学機器を取り扱う専門商社です。

03-3258-1238

お問い合わせ
KLV大学 ハイパースペクトルカメラコース
spectral-analysis-python-top.jpg

Python×スペクトル解析
[1.3]スペクトルグラフを表示する

スペクトル解析のPythonプログラム_スペクトルグラフ

スペクトルデータの解析では、まず画像を表示して全体の構造を把握することから始めることが一般的です。
まずは、[1.1]で解説した”データの読み込み"[1.2]で解説した”グレースケール画像表示やRGB画像表示”によって、スペクトルデータの対象領域や特徴の大まかな分布を確認することができます。

これらの画像が表示できるようになると、次に「この対象物はどんなスペクトルを持っているのか」、「こことここはどのようにスペクトルが異なるのか」などが気になる場面が多くなってくるかと思います。

そこで、本記事では、画像上でクリックした際に、そのピクセルのスペクトルグラフを表示する機能の実装を紹介します。

スペクトルグラフ表示_複数

1. Matplotlibのグラフ描画機能

グラフの描画には、[1.2]スペクトルデータを画像表示するで使用したMatplotlibを使用します。

Matplotlib は Python の代表的なデータ可視化ライブラリで、折れ線グラフをはじめ、散布図、棒グラフ、ヒストグラム、画像表示など様々なグラフを描画する事も可能です。

今回は、matplotlib.pyplot モジュールの plt.plot() で簡単にスペクトル波形を描画する方法を紹介します。
以下のようなコマンドで、軸ラベルやタイトル、凡例、目盛り、グリッド線の追加、線色やマーカー形状の変更も柔軟に設定できるため、スペクトル情報の可視化にも最適なライブラリです。

機能 コマンド例 説明
タイトル plt.title('タイトル') グラフの上部にタイトルを追加
x軸ラベル plt.xlabel('X軸ラベル') 横軸の説明を追加
y軸ラベル plt.ylabel('Y軸ラベル') 縦軸の説明を追加
凡例 plt.legend() label引数で指定した凡例を追加
グリッド線 plt.grid(True) グラフにグリッド線を追加
線色 plt.plot(x, y, color='red') 線の色を変更
マーカー形状 plt.plot(x, y, marker='o') データ点の形状を変更(例: 'o', '^', 's')
線種 plt.plot(x, y, linestyle='--') 実線、破線などの線種を変更

2. スペクトルグラフの表示

ハイパースペクトル画像の任意の位置を指定して、そのピクセルが持つスペクトル(波長ごとの値)を取り出すと、スペクトルデータをグラフとして可視化できます。
ここでは、そのためのサンプルスクリプトを説明します。

スペクトルグラフの表示のサンプルコード


import spectral
import matplotlib.pyplot as plt
import numpy as np

# データ読み込み
hdr_path = '*.hdr'  #入力スペクトルデータ(.hdr)のファイルパス
img = spectral.open_image(hdr_path)
data = np.asarray(img.load()) 

# スペクトルグラフを表示する座標の指定 
x, y = 320, 270 

# 波長情報の取得
wavelengths = np.array(img.metadata['wavelength'], dtype=float)

# 指定座標のスペクトル情報の抽出
spectrum = np.asarray(data[y, x, :]).squeeze()

# グラフの描画
plt.plot(wavelengths, spectrum, marker='o')
plt.xlabel('Wavelength')
plt.ylabel('Reflectance')
plt.title(f'Spectrum at (x={x}, y={y})')
plt.grid(True)
plt.show()

ハイパースペクトルデータ(ENVI形式)は、.hdrにメタ情報、.rawにスペクトル値が保存されています。Spectral Pythonのopen_image()を用いると、縦(高さ)、横(幅)、波長方向(バンド数)の3次元配列で読み込むことが可能です。
詳しい読み込み手順やコード例は、[1.1] Pythonでスペクトルデータを読み込んでみる をご確認ください。

スペクトルデータを読み込んだ後には、画像中の注目する位置を x, y = 320, 270 のように指定します。x は横方向(列番号)、y は縦方向(行番号)を表します。

x, y = 320, 270

次に、ENVI 形式のヘッダファイル(.hdr)に記録されている波長情報を取得します。

wavelengths = np.array(img.metadata['wavelength'], dtype=float)

spectral.open_image() で読み込んだオブジェクト img には、.hdr に記載された情報が metadataとして格納されます。
各バンドの波長は img.metadata['wavelength'] で取得でき、これを np.array(..., dtype=float) とすることで、matplotlib の plot() にそのまま渡せる NumPy 配列に変換できます。
dtype=float を指定すると、"400.0" のような文字列も浮動小数点数に変換されます。変換後は array([400., 410., 420., ...]) のようになります。

続いて、指定座標のスペクトルを 1 次元配列として取り出します。

spectrum = np.asarray(data[y, x, :]).squeeze()

スペクトル情報を格納した data は形状 (高さ, 幅, バンド数) の NumPy 配列です。
":"は全バンドを意味するため、data[y, x, :] で「画像中の (x, y) ピクセルが持つ全波長の値」を取得できます。
np.asarray(...) は元が配列なら不要なコピーを作らず NumPy 配列として扱えるため、メモリ効率に優れます(np.array(...) は新しい配列を作る場合があります)。
さらに .squeeze() でサイズ 1 の次元を削除し、確実に 1 次元(バンド数)の配列に整えます。

最後に、波長を横軸、スペクトル値を縦軸とした折れ線グラフを描画します。

plt.plot(wavelengths, spectrum, marker='o')

plt.plot()の第一引数が グラフのx座標、第二引数が y座標となるため、x座標に波長の配列、y座標にスペクトルデータの配列を指定します。
marker='o'は、各データに丸印(○)を表示するための関数です。

また、以下のように軸ラベルやタイトル、グリッド線を加えることで視認性を高め、plt.show() でグラフを表示します。

plt.xlabel('Wavelength') # グラフのX軸ラベルを「Wavelength」に設定
plt.ylabel('Reflectance') # グラフのY軸ラベルを「Reflectance」に設定
plt.title(f'Spectrum at (x={x}, y={y})') # グラフのタイトルに座標情報を表示
plt.grid(True) # グラフにグリッド線を表示
plt.show() # グラフを画面に表示

これにより、特定ピクセルのスペクトル形状を直感的に把握でき、物質判別や異常検出の手がかりになります。

スペクトルグラフの表示結果

スペクトルグラフ表示

3. 画像のクリックした箇所のスペクトルグラフを表示

これまでに、特定の座標 (x, y) を指定して、そのピクセルのスペクトルグラフを描画する方法を説明しました。

ただし、どの座標のスペクトルを見たいかは、実際に画像を見ないと判断できないことが多くあります。
そこで、画像表示とスペクトル抽出を組み合わせ、表示した画像上でクリックした位置のスペクトルを表示する方法を紹介します。
これにより、コードに座標を入力することなく、視覚的に位置を選びながら解析が可能になります。

画像のクリックした箇所のスペクトルグラフを表示するサンプルコード


import spectral
import matplotlib.pyplot as plt
import numpy as np

# --- データ読み込み ---
hdr_path = '/path/to/data/image.hdr'
img = spectral.open_image(hdr_path)
data = np.asarray(img.load())

# --- 波長 ---
wavelengths = np.array(img.metadata['wavelength'], dtype=float)

# --- 画像表示 ---
band_index = 10
fig, ax = plt.subplots()
im = ax.imshow(data[:, :, band_index], cmap='gray')
plt.colorbar(im, label='Reflectance')
ax.set_title(f'Band {band_index} (Click to add spectrum)')

# --- スペクトル画像の表示 ---
fig_spec, ax_spec = plt.subplots()
ax_spec.set_title('Spectra (click on image to add)')

# --- スペクトルグラフの描画関数 ---
def plot_spectrum(ax, wavelengths, spectrum, x, y, color):
    ax.plot(wavelengths, spectrum, marker='o', color=color, label=f'({x},{y})')
    ax.legend(loc='best')
    ax.set_xlabel('Wavelength' if wavelengths.dtype.kind == 'f' else 'Band index')
    ax.set_ylabel('Reflectance')
    ax.grid(True)
    ax.figure.canvas.draw_idle()

# --- クリックイベント関数 ---
def onclick(event):
    if event.inaxes is not ax or event.xdata is None or event.ydata is None:
        return
    x, y = int(event.xdata), int(event.ydata)
    if not (0 <= x < data.shape[1] and 0 <= y < data.shape[0]):
        return
    color = plt.cm.tab10(len(ax_spec.lines) % 10)
    spectrum = np.asarray(data[y, x, :]).squeeze()
    plot_spectrum(ax_spec, wavelengths, spectrum, x, y, color)
    ax.plot(x, y, marker='+', color=color, markersize=10, mew=1.5)
    fig.canvas.draw_idle()

fig.canvas.mpl_connect('button_press_event', onclick)
plt.show()

このスクリプトの最大のポイントは、画像をクリックした際に座標を取得し、その座標を用いてスペクトルを描画する点です。

①クリック時に座標を取得する方法

クリック時に座標を取得する部分のコードを説明します。

fig.canvas.mpl_connect('button_press_event', onclick)
plt.show()

まずは、グレースケール画像を描画している fig.canvas に対して mpl_connect を使い、マウスボタンのクリックイベント('button_press_event')が発生したら onclick 関数を呼び出すよう登録します。

この登録を行ったうえで plt.show() を実行すると、Matplotlib はウィンドウを開いてイベントループ(マウスクリック、キーボード入力、ウィンドウ移動などを監視する状態)に入ります。

続いて、マウスクリック時に呼び出される onclick 関数で、次の処理を実行します。

・event.inaxes で「画像上のクリック」以外を除外
if event.inaxes is not ax or event.xdata is None or event.ydata is None:
    return

カラーバーなど画像を描いた ax 以外の領域でのクリックや、xdata/ydata が None の場合(座標が取得できないケース)は処理を return で打ち切ります。

・ クリック座標を取得(配列の範囲外は無視)
x, y = int(event.xdata), int(event.ydata)
if not (0 <= x < data.shape[1] and 0 <= y < data.shape[0]):
    return

クリック座標は event.xdata, event.ydata で取得できるため、int() で整数化します。その上で if を用いて、取得した座標が配列の範囲内であることを確認します。

②指定座標のスペクトルグラフを描画する方法

クリック座標を取得に続いて、取得した座標のスペクトルグラフを描画するコードを追加していきます。

・グラフの線色を設定
color = plt.cm.tab10(len(ax_spec.lines) % 10)

既に描かれている曲線の本数に応じて tab10(10色)を利用します。
スペクトルグラフの描画だけであれば自動的に色を割り振れば十分ですが、画像上の十字マークとスペクトル線の色を合わせるため、あらかじめ color を決めておきます。

・指定座標のスペクトル抽出とスペクトルグラフの描画
spectrum = np.asarray(data[y, x, :]).squeeze()
plot_spectrum(ax_spec, wavelengths, spectrum, x, y, color)

data は形状 (高さ, 幅, バンド数) の配列です。data[y, x, :] で(x, y) ピクセルの全バンドを取り出し、plot_spectrum 関数でスペクトルグラフを描画します。
(この流れは「1.2 スペクトルデータ画像表示」で説明した内容と同じです)

・画像上に十字マークを描画
ax.plot(x, y, marker='+', color=color, markersize=10, mew=1.5)
fig.canvas.draw_idle()

最後に、どの位置のスペクトルか分かるよう、画像上のクリック位置に十字マークを追加します。
fig, ax = plt.subplots() で作成したスペクトル画像の描画領域 ax にマークを描くため、ax.plot(x, y, marker='+', ...) と記述します。
オプションとして、color で色、markersize でサイズ、mew(markeredgewidth)で線の太さを指定できます。
fig.canvas.draw_idle() でグレースケール画像の再描画を行えば、設定した十字マークを含む画像が再表示されます。

画像のクリックした箇所のスペクトルグラフの表示結果

スペクトルグラフ表示_複数

クリックした箇所それぞれの、スペクトルグラフが表示されていることがわかります。

4. スペクトルグラフの表示のまとめ

ハイパースペクトル画像では、任意のピクセルが持つ波長ごとの値(スペクトル)を取得し、グラフとして表示することで、物質の特性や状態を解析できます。
Python の Spectral Python(SPy)を使えば、ENVI 形式のデータから簡単に (高さ, 幅, バンド数) の配列を取得でき、data[y, x, :] で特定座標のスペクトルを抽出可能です。

抽出したデータは NumPy 配列に変換し、Matplotlib の plot() 関数で波長を横軸、反射率などの値を縦軸にした折れ線グラフを描画します。
さらに、軸ラベル、タイトル、グリッド線などを設定することで視認性を高められます。

この方法により、特定位置のスペクトル形状を直感的に把握でき、分類や異常検出、材料判別など、スペクトル解析の出発点として非常に有用です。

ハイパースペクトルカメラコース

ご質問・ご相談お気軽にお問い合せください

お電話でのお問合せ 03-3258-1238 受付時間 平日9:00-18:00(土日祝日除く)
Webでのお問い合わせ