2015年12月5日土曜日

Kinect + Raspberry Pi 2 で監視カメラを作る(5)

Depth と IR 画像の取得

Depth は depth_cb の data 引数から取得できる。
ただし、データは 11bit 形式なので、8bit のグレイスケールに変換する必要がある。
最初は律儀に RGB 各色に同じ値を入れていたが、JPEG のオプションを調べたら 1byte のグレイスケールでも出力できるようだった。

    JSAMPLE jpg_line[640];
    ・・・
    jpg_cinfo.input_components = 1;
    jpg_cinfo.in_color_space = JCS_GRAYSCALE;
    ・・・
    for(i = 0; i < 480; i++) {
        int j;
        for(j = 0; j < 640; j++) {
                unsigned short tmp;
                tmp = ((unsigned short)buf[i * 640 * 2 + j * 2 + 1] << 8)
                          + ((unsigned short)buf[i * 640 * 2 + j * 2] & 0xff);
                jpg_line[j] = (tmp >> 3) & 0xff;
        }
        jpg_row[0] = jpg_line;
        jpeg_write_scanlines(&jpg_cinfo, jpg_row, 1);
    }

IR の方は、最初に freenect_set_video_mode で FREENECT_VIDEO_RGB の代わりに FREENECT_VIDEO_IR_8BIT を指定する必要がある。
10BIT精度にも出来るが、どうせグレイスケールに変換するのでここでは 8bit で十分。こうすれば切り出したバッファをそのまま JPEG のライブラリに食わせられる。
このあたりからあまりまとまった解説が見当たらくなってきたので、わからなかったらlibfreenect のヘッダのコメントを見て解決している。

    freenect_set_video_mode(fn_dev,  freenect_find_video_mode(FREENECT_RESOLUTION_MEDIUM, FREENECT_VIDEO_IR_8BIT));
    ・・・
   
    ・・・
    for(i = 0; i < 480; i++) {
        jpg_row[0] = (JSAMPROW)&buf[i * 640];
        jpeg_write_scanlines(&jpg_cinfo, jpg_row, 1);
    }

動作中の RGB と IR の切り替え方法については、正式なドキュメントは見当たらなかったが、とりあえず以下のように一旦止めてから、モードを変更して再度スタートしたら無事に動いたので、とりあえずはこのやり方で行くことにした。

    freenect_stop_video(fn_dev);
    freenect_set_video_mode(fn_dev, freenect_find_video_mode(FREENECT_RESOLUTION_MEDIUM, FREENECT_VIDEO_IR_8BIT));
    freenect_start_video(fn_dev);

もしかしたら止めなくても良いのかもしれないが、なんとなく気分的にやってしまう。

Tilt(傾き) の操作

Tilt の操作は freenect_set_tilt_degs を呼べば良いはずなのだが、ベースとした camtest.c にこれを組み込んでもさっぱり反応してくれない。
コードを読み返したら一カ所怪しいところがあったので、ヘッダのコメントをみたら案の定これが悪さをしていた。というわけで、以下の一行をコメントアウト。

    //freenect_select_subdevices(fn_ctx, FREENECT_DEVICE_CAMERA);

これは、アプリで使用するキネクトのデバイスを指定するオプション。キネクトは、カメラ、モーター、LEDの3つのデバイスから構成されており、この関数を利用することで個別に指定して開くことが出来る。
例えば、アプリ A でカメラを操作し、アプリ B でチルトの制御を行うときなどはこれを使うと便利だが、今回はアプリを分けるつもりは無い。指定なしの場合は全部のデバイスをオープンするそうなので、コメントアウトしてしまうのが手っ取り早い。

傾きの角度は浮動小数点で自由に指定できるが、サンプルを見た限りだと ±30度 の範囲がデバイスとしての限界っぽい。(API 側で制限かけていないのは、将来的に新型 Kinect が出たときに動作範囲が変わることを想定してるんだろうな)
角度の指定は動いているときでも出来るようだが、気分的に以下のように止まっていることを確認してから行うようにする。

    freenect_raw_tilt_state* p_raw_tilt_state;
    freenect_tilt_status_code tilt_status;
    double tilt_deg = 10.0;

    freenect_update_tilt_state(fn_dev);
    p_raw_tilt_state = freenect_get_tilt_state(fn_dev);
    tilt_status = freenect_get_tilt_status(p_raw_tilt_state);
    if(tilt_status != TILT_STATUS_MOVING) {
        freenect_set_tilt_degs(fn_dev, tilt_deg);
    }

なお、±30度を超える角度を指定した場合は状態は TILT_STATUS_LIMIT になる。なのであえて TILT_STATUS_STOPPED ではなく !TILT_STATUS_MOVING で動作中かどうかを判定している。

これで必要な機能の使い方は一通りわかったので、後はこれをどうやってブラウザから制御するかってことになる。

0 件のコメント:

コメントを投稿