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

03-3258-1238

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

Python×スペクトル解析
[1.2]スペクトルデータの画像表示する

スペクトル解析のPythonプログラム_スペクトル画像表示

スペクトルデータの中には対象の特徴や状態を表す重要な情報が隠れています。これを理解するためには、数値をグラフや画像に変換して直感的に把握することが大切です。

例えば、グレースケール画像や偽RGB画像として表示することで、スペクトル画像全体の傾向やノイズの有無、異常な領域の存在などを一目で確認できます。
さらに、特定の波長(バンド)を抽出してヒートマップ表示すれば、強度の違いや局所的な特徴を色で可視化でき、グレースケールでは見落としがちな微妙な強度差や異常点も検出可能です。

本記事では、Python と matplotlib を使って、これらの可視化手法を初心者でも無理なく実践できるよう紹介します。

スペクトル画像グレースケールイメージ

1. データの読み込み(Load)について

ハイパースペクトルカメラで取得したデータは、数百バンドの波長情報を持つ「スペクトルのかたまり」です。
一般的には、 ENVI 形式(.hdr + .raw) で保存され、.hdr には画像サイズ・波長・データ型などのメタ情報、.raw には各ピクセルのスペクトル値が格納されています。解析や可視化を始めるには、この形式を正しく読み込むことが重要です。

Python では、Spectral Python(SPy)を使うと ENVI 形式のスペクトルデータを簡単に読み込むことが可能です。
.hdr ファイルを spectral.open_image() に渡すと、内部で .raw を参照し、(rows, cols, bands) 形状の配列として読み込みます。
後ほど詳しく解説しますが、行は高さ、列は幅、bands は波長チャンネルを示すので、arr[:, :, band] で特定波長の画像、arr[row, col, :] で特定ピクセルのスペクトルを取得可能です。

Spectral Python(SPy)を用いたスペクトルデータの読み込み手順やコード例は、[1.1] Pythonでスペクトルデータを読み込んでみる をご確認ください。

2. matplotlibとは

matplotlib は、Pythonで広く使われているグラフ描画ライブラリの一つで、折れ線グラフ・棒グラフ・散布図・ヒストグラム・画像表示など、多彩な可視化が可能です。
データ解析の分野での標準ツールとなっており、Jupyter Notebook、Pythonスクリプト、GUIアプリケーションなど様々な環境で動作します。

Matplotlib公式ホームページ

matplotlibの基本モジュールである matplotlib.pyplotに含まれているimshow() 関数 は、2次元配列をそのまま画像として表示できる関数で、スペクトルデータの画像表示にも最適です。
matplotlibはカスタマイズ性も高く、カラーマップの指定(例: cmap='gray' や cmap='viridis')、値域の調整(vmin, vmax)、軸ラベルやカラーバーの追加、タイトルや凡例の追加、フォントや線の太さ、背景色の変更なども簡単に行うことが可能です。

また、画像やグラフはPNG、JPEG、SVG、PDFなど様々な形式で保存できる点も便利です。

matplotlibのインストール

インストールは、ターミナルやコマンドプロンプトで以下を実行することで簡単に行えます。

pip install matplotlib

ここから、matplotlibのimshow() を用いてスペクトルデータを見やすく表示する方法を紹介します。

3. スペクトルデータをグレースケール画像で表示

スペクトルデータは、縦(高さ)、横(幅)、波長方向(バンド数)の3次元配列です。
このうち、特定の1波長のみのデータを取り出すと、縦×横の2次元配列になります。この縦x横の配列に格納されている輝度分布を表示することで、特定波長の輝度値の画像を確認することができます。
Pythonの matplotlib ライブラリに含まれる imshow() 関数を使えば、2次元配列をそのまま画像として表示することができます。
この時、カラーマップ(cmap)に 'gray' を指定すると、黒〜白の階調で表すグレースケール画像になり、黒が低値(低反射)、白が高値(高反射)を意味します。

グレースケール画像表示(バンド番号指定)

グレースケール画像表示のサンプルコード

import spectral
import matplotlib.pyplot as plt

# ENVI形式のデータを読み込む
hdr_path = '/path/to/data/image.hdr'  # .hdrファイルのパス
img = spectral.open_im
age(hdr_path)
data = img.load()  # NumPy互換の配列として読み込み

# 表示するバンド番号(0始まり)
band_index = 10

# グレースケール表示
plt.imshow(data[:, :, band_index], cmap='gray')
plt.colorbar(label='Reflectance')  # 値の目安を追加
plt.show()

data[:, :, band_index] は、スペクトルデータ(3次元配列)から 特定のバンド(波長)だけを取り出す書き方 です。

data[:, :, band_index]
 ・最初の”:” →「すべての行(高さ方向)」
 ・2つ目の”:” →「すべての列(幅方向)」
 ・band_index →「指定したバンド番号」

例えば band_index = 10 なら、「全ピクセルの中から10番目の波長データ」を2次元配列として取り出します。

こうして得られた縦×横のデータを imshow() に渡すと、その波長だけの画像として表示できます。

plt.imshowのオプションとして渡しているcmap='gray' は、画像のカラーマップをグレースケールに設定し、黒から白への階調で数値の大小を表します。
これにより、デフォルトのカラーマップよりも明暗差が直感的に分かりやすくなります。
colorbar() は、画像の右側に凡例として色と数値の対応を表示し、引数 label を使うことで単位や説明を付け加えることができます。

グレースケール画像表示の実行結果

スペクトル画像グレースケールイメージ

グレースケール画像表示(波長指定)

ハイパースペクトルデータは配列のため「バンド番号」を指定してアクセスしますが、この番号は単なる配列の位置(0番、1番、2番…)を表すだけです。バンド番号と波長は1対1で対応していますが、バンド番号に波長の情報は含まれていません。

例えば、
バンド0 → 397.2 nm
バンド1 → 401.5 nm
バンド2 → 405.8 nm
というように、バンド番号ごとに波長が割ついています。

ユーザーは「850nmの波長の画像を見たい」と思うのであって、「10番目のバンドの画像を見たい」と思うわけではないと思います。
また、スペクトルカメラの機種やデータ取得時の設定によってバンドと波長の対応は変わります。

そのため、波長を指定して、画像を抽出する機能が必要になります。

以下に「指定した波長に最も近いバンドを自動検索する処理」を追加したサンプルコードを紹介します。

これにより、ユーザーは波長だけを入力するだけで済み、バンド番号を調べる必要がなくなります。

波長情報の取得のサンプルコード

①波長情報の取得
metadata = img.metadata
wavelengths = [float(w) for w in metadata['wavelength']]
wavelengths_array = np.array(wavelengths)

まずは、img.metadata でHDRファイルに記録されたメタデータ(撮影条件やバンド情報など)を辞書形式で取得します。
そして、ENVI形式では wavelength というキーに各バンドの波長がリストとして格納されているため、それをfloat形式(小数を扱うための数値型)で取得します。

②指定した波長に最も近いバンド番号を探す

target_wavelength = 850
band_index = np.argmin(np.abs(wavelengths_array - target_wavelength))
matched_wavelength = wavelengths_array[band_index]

(wavelengths_array - target_wavelength) で全波長と指定波長との差を計算し、np.abs() でその絶対値を取ります。
np.argmin() は配列の中で最も値が小さい要素のインデックス(位置)を返すので、「差が最も小さい=最も近い波長」のバンド番号を取得することができます。このバンド番号を使用することで、指定した波長に最も近い画像を取得することが可能です。

この時の実際の波長を知りたければ、波長リストである wavelengths_array に対するバンド番号を抽出することで確認できます。

これにより、指定波長に最も近い画像バンドを特定できるため、「850nmに近い画像だけ表示したい」といった処理を実現できます。

波長指定でのグレースケール画像出力のサンプルコード

実際に実装すると、次のようになります。
import spectral
import matplotlib.pyplot as plt
import numpy as np

hdr_path = '*.hdr'
img = spectral.open_image(hdr_path)
data = img.load()

metadata = img.metadata
wavelengths = [float(w) for w in metadata['wavelength']]
wavelengths_array = np.array(wavelengths)

target_wavelength = 850
band_index = np.argmin(np.abs(wavelengths_array - target_wavelength))
matched_wavelength = wavelengths_array[band_index]

print(f"指定波長 {target_wavelength} nm に最も近いバンドは {band_index} 番で、波長は {matched_wavelength} nm です。")

plt.imshow(data[:, :, band_index], cmap='gray')
plt.colorbar(label='Reflectance') 
plt.show()

波長指定でのグレースケール画像出力の実行結果


指定波長 850 nm に最も近いバンドは 217 番で、波長は 849.71 nm です。
スペクトル画像グレースケールイメージ850nm

上記のように実際に選択されたバンド数、波長を表示した上で、グレースケール画像が表示されます。

1つ前に行った10バンド目のグレースケール画像と波長が異なるため、若干見え方が異なることがわかります。

ヒートマップ表示

ヒートマップ表示は、強度の差を色の変化として表現する方法です。グレースケールでは明暗の差だけで表現しますが、ヒートマップでは複数の色を使うため、微妙な強弱や局所的な特徴がよりはっきり見えます。特に、数値の差を直感的に把握したいときや、異常値・高強度領域を目立たせたいときに有効です。

グレースケール画像をヒートマップ表示に切り替えるには、plt.imshowcmap オプションを 'gray' からヒートマップ用のカラーマップに変更するだけで実現できます。

plt.imshow(data[:, :, band_index], cmap='viridis')

ヒートマップ”viridis”での表示結果

先ほどグレースケール表示した850nmの波長の画像をカラーマップcmap='viridis' で出力した例を紹介します。
viridis は色の変化が滑らかで見やすく、色覚多様性(色弱など)にも配慮された配色です。青から黄までのグラデーションで、低い値から高い値までの分布を自然に表せます。

スペクトル画像ヒートマップイメージ850nm_viridis

ヒートマップ”jet”での表示結果

また、jet も青から緑・黄・赤へと急激に色が変化するためコントラストが強く、差が強調されて分かりやすいという特徴があります。
ただし、色の変化が均等でないため、データの連続性を誤解させる可能性がある点に注意が必要です。

スペクトル画像ヒートマップイメージ850nm_jet

カラーマップは他にも、 coolwarm(青⇔赤)、plasma(紫⇔黄)、inferno(暗赤⇔黄)などが利用できます。
目的や見やすさに応じて選ぶことで、データの特徴がより効果的に表現できます。

4. スペクトルデータを偽RGB画像で表示

偽RGB画像とは

グレースケール表示は、単一の波長(バンド)の強度分布を直感的に確認できる便利な方法ですが、複数の物質が混在している場合や、人間の見た目に近い色で対象を把握したい場合には十分ではありません。

そこで、複数のバンドを組み合わせて作成する偽RGB表示が有効です。R・G・B にそれぞれ任意のバンドを割り当てることで、色の情報を含めた複合的な観察が可能になります。

通常のRGB画像は、人の目が感知できる可視光の赤(約620〜750nm)、緑(約495〜570nm)、青(約450〜495nm)の波長に対応する3つの成分を組み合わせて表示されています。
これにより、人が自然に見ている色合いを再現できます。

一方、偽RGB画像では、人の目が感知するR・G・Bの波長とは異なる波長をR・G・Bに割り当てることで、肉眼では見えない波長の情報情報を人の目に見える情報にすることができます。
つまり、偽RGBは「人の目には見えない波長の情報を色として可視化する」手法であり、スペクトル解析に対しては非常に有用です。

偽RGB画像表示

偽RGB画像表示のサンプルコード

以下に、ENVI(.hdr)データから偽RGB画像を表示する簡単なコードを紹介します。
以下のコードでは、人の目の RGB に近い 3 つの波長バンドをそれぞれ R/G/B に割り当てて合成し、通常の写真のような見た目(実彩色に近い表示)にしています。

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

hdr_path = '/Users/.../strawberryjamwithleafvis.bil.hdr'
img = spectral.open_image(hdr_path)
data = img.load()

r_band, g_band, b_band = 129, 77, 28

R = data[:, :, r_band]
G = data[:, :, g_band]
B = data[:, :, b_band]
rgb = np.dstack([R, G, B])

plt.imshow(rgb)
plt.title(f'Fake RGB (R={r_band}, G={g_band}, B={b_band})')
plt.axis('off')
plt.show()

print("=== バンドと波長一覧 ===")
for i, wl in enumerate(wavelengths):
   print(f"{i:3d} : {wl} nm")

偽RGB表示の最初の手順は、グレースケール表示と同じです。
まずは、.hdr ファイルを spectral.open_image() で開き、img.load() により NumPy互換配列 (rows, cols, bands) としてデータを取得します。

ここからが偽RGB特有の処理です。
まず、表示したい3つのバンドを指定します。写真と同じような画像にするには、赤・緑・青の波長帯を指定し、Rチャンネル用、Gチャンネル用、Bチャンネル用 の配列に割り当てます。

次に np.dstack() を使って、この3つの2次元配列を結合し、(rows, cols, 3) の配列を作成します。

最後に plt.imshow() で表示すると、選んだ波長バンドを組み合わせたカラー画像が得られます。

偽RGB画像の表示結果

スペクトル画像偽RGB表示

カメラ側でリファレンス(白基準・黒基準)による補正が行われていない画像では、バンド間の明るさや色のバランスが大きく異なる場合があります。
このようなスペクトルデータに対してそのまま偽RGBを作成すると、実際の見た目と大きく異なる色再現になったり、特定の色が強調されすぎることがあります。
偽RGBによる色表現や比較を行う場合は、事前に白基準・黒基準データを用いた補正を行っているかを確認することも重要です。

5. まとめ

本記事では、matplotlib を用いてスペクトルデータを可視化する方法を紹介しました。
スペクトルデータの視覚化は、データ解析の入り口として非常に重要であり、データの傾向や異常の有無を直感的に把握する手法として有効です。
今回紹介した画像表示を状況に応じて使い分け、組み合わせることで、スペクトルデータの持つ情報を確認してください。

  • グレースケール表示

    単一バンドの強度分布を確認し、ノイズや全体のパターンを素早く把握できる

  • ヒートマップ表示

    色を使って強度差を強調し、微妙な差や局所的な異常を見つけやすくできる

  • 偽RGB表示

    複数バンドを組み合わせることで、対象の状態や構造をより多面的に理解できる
    (見た目に近い色を再現することも可能)

次の記事では、画像表示で気になった箇所に対する、スペクトル波形の表示方法を紹介します。

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

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

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