マルチスペクトルサーマル (OV5640)

マルチスペクトルサーマルカメラモジュールの OV5640 バリアントは、5MP のローリングシャッターカラーセンサーと FLIR Lepton サーマルコアを組み合わせており、OpenMV Cam で高解像度のカラービジョンパイプラインとサーマルパイプラインを並行して実行できます。

マルチスペクトルサーマル (OV5640)

完全なデータシート、写真、注文については マルチスペクトルサーマル製品ページ を参照してください。

注釈

OpenMV Cam RT1062 でのみサポートされます。

ハイライト

  • OV5640: より高解像度のカラー向けの 5MP ローリングシャッター

  • FLIR Lepton 1.x / 2.x / 3.x サーマルコアに対応

  • 1 つのモジュール上でサーマルとカラーを同時処理

  • 完全な暗闇でも視認可能、温度測定をサポート

  • カラーセンサーにオートフォーカスと F2.0 絞りを搭載

使い方

カラーセンサーと FLIR Lepton はそれぞれ独自の csi.CSI インスタンスを持ちます。最初の呼び出しはデフォルトでプライマリセンサー (OV5640) になり、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 がアップスケールを滑らかにします。

OV5640 にはボイスコイルアクチュエータ式のオートフォーカスレンズが搭載されています。csi.CSI.ioctlcsi.IOCTL_TRIGGER_AUTO_FOCUS を使ってカラーカメラで単発のオートフォーカスパスをトリガーします。センサーはフォーカスモーターを 1 回スイープし、前にあるものにロックします:

csi0.ioctl(csi.IOCTL_TRIGGER_AUTO_FOCUS)

シーンが変化したときはいつでも ioctl を再発行してください。オートフォーカスは連続ではなく単発です。

温度測定

ラジオメトリック Lepton (Lepton 2.5 / 3.5) は較正済みのピクセルごとの温度データを報告します。csi.CSI.ioctlcsi.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()) に対しても機能します。