マルチスペクトルサーマル (PAG7936)¶
マルチスペクトルサーマルカメラモジュールの PAG7936 バリアントは、1 MP のグローバルシャッターカラーセンサーと FLIR Lepton サーマルコアを組み合わせており、OpenMV Cam でカラービジョンパイプラインとサーマルパイプラインを並行して実行できます。
完全なデータシート、写真、注文については マルチスペクトルサーマル製品ページ を参照してください。
注釈
OpenMV N6 でのみサポートされます。
ハイライト¶
PAG7936: 1 MP グローバルシャッター
FLIR Lepton 1.x / 2.x / 3.x サーマルコアに対応
1 つのモジュール上でサーマルとカラーを同時処理
完全な暗闇でも視認可能、温度測定をサポート
グローバルシャッターによりローリングシャッターのアーティファクトなしで高速な動きに対応
使い方¶
カラーセンサーと FLIR Lepton はそれぞれ独自の csi.CSI インスタンスを持ちます。最初の呼び出しはデフォルトでプライマリセンサー (PAG7936) になり、2 番目の呼び出しは cid= csi.LEPTON を渡すことで Lepton にバインドされます。csi.CSI.reset (hard=True) でカラーセンサーをハードリセットして電源レールを立ち上げ、Lepton は hard=False で構成して、そのドライバーがリセットを再度トグルせずにチップを再プログラムするだけにします。
csi.CSI.framesize ( csi.QVGA ) は Lepton の出力をカラーカメラに合わせるため、各 snapshot() は 320x240 のフレームを返します。Lepton ドライバーは内部でネイティブの 80x60 (1.x/2.x) または 160x120 (3.x) フレームを要求されたサイズにアップスケールします。QVGA では各 Lepton ピクセルがカラーフレーム上で 4x4 または 2x2 のセルを覆います。
フレームループ全体で 2 つのスクラッチバッファが一定に保たれます。1 つは image.Image として格納された 256x1 のアルファパレットで、これにより冷たい Lepton ピクセルは透明に、熱いピクセルは不透明になります (二次関数のランプは中間域をつぶさずに背景の詳細を抑制します)。もう 1 つは image.Image で事前確保された Lepton フレームバッファで、csi.CSI.snapshot (blocking=False, image=...) が再確保せずに毎回これをその場で埋められるようにします:
import time
import csi
import image
import math
alpha_pal = image.Image(256, 1, image.GRAYSCALE)
for i in range(256):
alpha_pal[i] = int(math.pow((i / 255), 2) * 255)
# Setup the color camera sensor.
csi0 = csi.CSI()
csi0.reset(hard=True) # force hardware reset.
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.QVGA)
csi1 = csi.CSI(cid=csi.LEPTON)
csi1.reset(hard=False) # no hardware reset - just configure lepton
csi1.pixformat(csi.GRAYSCALE)
csi1.framesize(csi.QVGA)
# Optional temperature range controls for the LEPTON.
# csi1.ioctl(csi.IOCTL_LEPTON_SET_MODE, True, False)
# csi1.ioctl(csi.IOCTL_LEPTON_SET_RANGE, 20.0, 40.0)
clock = time.clock()
img1 = image.Image(csi1.width(), csi1.height(), csi1.pixformat())
while True:
clock.tick()
img0 = csi0.snapshot()
csi1.snapshot(blocking=False, image=img1)
img0.draw_image(img1, 0, 0, color_palette=image.PALETTE_IRONBOW,
alpha_palette=alpha_pal,
hint=image.BILINEAR)
print(clock.fps())
各反復ではブロッキングのカラースナップショットと非ブロッキングの Lepton スナップショットを取得します。Lepton は 9 Hz で動作するため、これをブロッキングするとカラーパイプラインが制限されてしまいます。Image.draw_image が次に 2 つを合成します。color_palette= image.PALETTE_IRONBOW は Lepton のグレースケールを FLIR スタイルの暖色ランプにマッピングし、alpha_palette= は二次関数のアルファマップを使って各ピクセルをブレンドし、hint= image.BILINEAR がアップスケールを滑らかにします。
温度測定¶
ラジオメトリック Lepton (Lepton 2.5 / 3.5) は較正済みのピクセルごとの温度データを報告します。csi.CSI.ioctl と csi.IOCTL_LEPTON_SET_MODE を使って測定モードを有効にし、次に csi.IOCTL_LEPTON_SET_RANGE (min_celsius, max_celsius) で温度ウィンドウをクランプします。Lepton ドライバーはグレースケールのピクセル値 0 を min_celsius に、255 を max_celsius に線形マッピングするため、各ピクセルは構成されたウィンドウ内での温度ルックアップになります。min_celsius より冷たいピクセルは 0 で飽和し、max_celsius より熱いピクセルは 255 で飽和します。
csi.IOCTL_LEPTON_SET_MODE は 2 つのフラグを取ります。1 つ目は測定をオンにし、2 つ目はセンサーの温度範囲を選択します:
低範囲 —
(True, False)— センサーのスパンは-10 °Cから+140 °C(室内スケールのシーン)。関心領域にウィンドウをクランプします。たとえば体温トラッキング用に(20.0, 40.0)とします:csi1.ioctl(csi.IOCTL_LEPTON_SET_MODE, True, False) csi1.ioctl(csi.IOCTL_LEPTON_SET_RANGE, 20.0, 40.0)
高範囲 —
(True, True)— センサーのスパンは熱い物体向けに典型的には-10 °Cから~+450 °C(室温では~+400 °C)。たとえば炉や高温部品のトラッキング用に(0.0, 400.0)にクランプします:csi1.ioctl(csi.IOCTL_LEPTON_SET_MODE, True, True) csi1.ioctl(csi.IOCTL_LEPTON_SET_RANGE, 0.0, 400.0)
グレースケールのピクセルを摂氏に戻すには:
def p_to_temp(p, min_t, max_t):
return (p * (max_t - min_t)) / 255.0 + min_t
これは個々のピクセルに対しても、Image.find_blobs で高温/低温領域を特定する際に ROI 内の集約統計 (たとえば Image.get_statistics からの stats.mean()) に対しても機能します。
GPU アクセラレーションによるアライメント¶
Image.draw_image は transform= 引数を受け付けます。これは 2 次元の ulab.numpy 配列としての 3x3 ホモグラフィ行列です。OpenMV N6 では GPU が同じ描画中にピクセルごとの投影を実行するため、別途のワープパスなしで Lepton フレームをカラーカメラの遠近感に対して再アライメントできます。thermal-overlay-calibration tool を使ってカメラごとに行列を較正してください:
import time
import csi
import image
from ulab import numpy as np
import math
# Calibration matrix from the thermal-overlay-calibration tool.
m = np.array([
[3.704807, 0.257018, 37.260564],
[0.052147, 3.609977, -7.831831],
[0.000294, 0.000552, 1.000000],
])
alpha_pal = image.Image(256, 1, image.GRAYSCALE)
for i in range(256):
alpha_pal[i] = int(math.pow((i / 255), 2) * 255)
# Setup the color camera sensor.
csi0 = csi.CSI()
csi0.reset(hard=True) # force hardware reset.
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.VGA)
csi1 = csi.CSI(cid=csi.LEPTON)
csi1.reset(hard=False) # no hardware reset - just configure lepton
csi1.pixformat(csi.GRAYSCALE)
csi1.framesize(csi.QQVGA)
# Optional temperature range controls for the LEPTON.
# csi1.ioctl(csi.IOCTL_LEPTON_SET_MODE, True, False)
# csi1.ioctl(csi.IOCTL_LEPTON_SET_RANGE, 20.0, 40.0)
clock = time.clock()
img1 = image.Image(csi1.width(), csi1.height(), csi1.pixformat())
while True:
clock.tick()
img0 = csi0.snapshot()
csi1.snapshot(blocking=False, image=img1)
img0.draw_image(img1, 0, 0, color_palette=image.PALETTE_IRONBOW,
alpha_palette=alpha_pal,
hint=image.BILINEAR,
transform=m)
print(clock.fps())
このバリアントはカラーカメラを csi.VGA (640x480) で、Lepton を csi.QQVGA (160x120) で動作させることに注意してください。ホモグラフィは描画の一部として小さい Lepton フレームをより大きいカラーフレームに投影するため、アップスケール係数は別途適用されるのではなく行列自体に組み込まれています。