Intel RealSense D400シリーズを赤外線カメラとして使う

intel RealSense™ Depth Camera D435

intel RealSense™ Depth Camera D435

Kinect後継として指名されているIntelのRealSenseシリーズだが、距離をセンシングするIRステレオカメラ部は、単体の赤外線カメラとして利用可能だ。性能、値段、入手性のバランスが優れた赤外線カメラと言える。D415とD435の2種類あり、後者のほうが広角なのだが、センサからして違うので、どちらを選ぶかの参考になるように記事をまとめた。

赤外線カメラとしてのD400シリーズの仕様

  • D415とD435ではIRステレオカメラ部分が違う
    • D415はIRカットフィルムのない通常の可視光にピークを合わせたカメラ
    • D435は赤外線領域にピークを合わせているカメラ
  • 可視光カットフィルムを使うことでほぼ問題なく可視光カット可能
  • 画角が異なるため赤外線プロジェクターも異なる
  • Intel公式ではなくMouserにあったデータシートが良かった

f:id:miso_engine:20181126173607p:plain

librealsenseのPythonラッパーで赤外線カメラを使うコード

librealsenseはIntel公式のようで公式ではないらしいSDK。特に問題なく使えるが、コメントで書いた通り、カメラ側に設定を反映させるのに変なコツがいる。

# coding: utf-8

import pyrealsense2 as rs
import numpy as np
import cv2

# Stop Laser Emitter
context = rs.context()
sensor = context.sensors[0]
sensor.set_option(rs.option.emitter_enabled, 0.0)

# pipelineを一度start()しないと最初の接続時に設定が反映されない
pipeline = rs.pipeline()
pipeline.start()
pipeline.stop()

config = rs.config()
config.enable_stream(rs.stream.infrared, 1, 1280, 720, rs.format.y8, 30)

pipeline.start(config)
cv2.namedWindow('pysense', cv2.WINDOW_AUTOSIZE)

try:
    while True:

        frames = pipeline.wait_for_frames()
        ir_frame = frames.get_infrared_frame()
        if not ir_frame:
            continue

        ir_image = np.asanyarray(ir_frame.get_data())
        
        cv2.imshow('pysense', ir_image)
        k = cv2.waitKey(1)
        if k == 27:
            break
            
finally:
    pipeline.stop()
    cv2.destroyAllWindows()

f:id:miso_engine:20181126175749p:plain
D415の赤外線カメラ画像

バイイングガイド

赤外線カメラとして利用する場合、D435の方が、

  1. センサが赤外線にピークを合わせている
  2. D415よりも広角
  3. 1280x800で30fps出せる(D415は1280x720)

といった値段相応の機能性と使いやすさがあるため、ケチケチしたプロジェクトでない限りはD435がオススメだ。

micro:bitのmbedでカスタムのMicrobitEventを実装する

micro:bitのmbed、MicrobitEventなるものでメッセージをオブジェクト間で送り合うように設計されている。例えば、ボタンが押された時のコールバック、シリアル通信が来た時のコールバック、センサーの値が一定以上になった時のコールバックなどなど。そうすると、カスタムでMicrbitEventを実装したくなるのだが、公式リファレンスにはなぜかそれに関する言及が無かったので調べて実装した。

MicrobitEventの仕様

Eventの発行元ID、Valueの2つがあればよい。Eventの発行元IDは9000番台以降ならデフォルトのID(Buttonなど)と被らない模様*1Valueはuint16_tで自由に使って良い。下記一行だけですぐEventは発行される。

MicroBitEvent evt(uint16_t 発行元ID, uint16_t value);

Eventのコールバック先の指定もボタンなどと一緒。Valueに0をいれると、その発行元からのすべてのEventを受け取る。今回は数字を送るのに利用してみた。

uBit.messageBus.listen(uint16_t 発行元ID, uint16_t value, コールバック先の関数名);

サンプル

Aボタンを押すとランダムで0-9までの数字を表示する。Aボタンを押した時にランダムで数字を生成し、EventのValueにして発行、イベントハンドラーで受け取って表示。

#include "MicroBit.h"

MicroBit uBit;

const int CUSTOM_EVENT_HANDLER = 9001;

void onCustomEvent(MicroBitEvent e)
{
    uBit.display.printAsync(e.value);
}

void onButtonA(MicroBitEvent)
{
    uint16_t ev = uBit.random(9);
    MicroBitEvent evt(CUSTOM_EVENT_HANDLER, ev);
}

void onButtonB(MicroBitEvent)
{
    uBit.display.clear();
}

int main()
{
    uBit.init();
    
    uBit.messageBus.listen(MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_CLICK, onButtonA);
    uBit.messageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonB);
    uBit.messageBus.listen(CUSTOM_EVENT_HANDLER, 0, onCustomEvent);

    uBit.display.printAsync("Q");
    release_fiber();
}

micro:bit(マイクロビット)

micro:bit(マイクロビット)

*1:詳しく調べてはないです

micro:bitのBluetoothペアリングモードに入る方法

公式の方法はABボタンを同時押ししながらリセットボタン。

しかし実際の実装は「起動時にABボタンを一定時間同時押しされている」と入るようになっている。リセットボタンは必須ではないので、電池の出し入れやその他電源供給側のスイッチ等で電源のオンオフができるなら、それらの方法でもペアリングモードに入ることが可能だ。

ケースによってリセットボタンが押せないので試行錯誤してたら発見した。

micro:bit(マイクロビット)

micro:bit(マイクロビット)