ブラウザから Kinect を操作する(前編)
前回で libfreenect を利用した Kinect の操作方法は大体わかったので、今度はWebカメラらしくブラウザから仰角や表示モードを操作できるようにする。やり方は色々あるが今回は古典的だが一番簡単そうなネームドパイプ(FIFO)を使って cgi から camtest にコマンドを送る。
概念的にはこんな感じになる。
camtest ← FIFO ← CGI ← ブラウザ
双方向の情報伝達も出来なくはないが、ちゃんとやろうとすると非常に面倒なので今回は一方通行にする。
まずは、camtest.c に以下の行を追加してFIFOの生成とオープンを行う。
マルチスレッドにするならブロックモードでも良いが、
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
...
char fifoname[] = "/tmp/kinect";
...
int main(int argc, char** argv)
{
...
int fifo;
if(mkfifo(fifoname, 0666) == 0) { // FIFOの作成
chmod(fifoname, 0777);
} // すでにFIFOがある場合は失敗するだけなので気にしない
if((fifo = open(fifoname, O_RDONLY | O_NONBLOCK)) < 0) { // オープン
printf("Failed to open fifo\n");
return 1;
}
ルート権限で実行すると mkfifo で0777を指定しても umask の影響で一般ユーザーの書き込み権限がなくなってしまうので、わざわざ作った後に chmod で権限を変更している。
この辺もう少し賢く出来ないもんか・・・
んでもってあとはイベントループの中でFIFOからコマンドをリードしてそれに応じて仰角とカメラモードを変更するようにすればよい。
enum video_mode { KINECT_RGB, KINECT_IR, KINECT_DEPTH };
// とりあえず最初はRGBモードでカメラだけ起動しておく
current_mode = KINECT_RGB;
ret = freenect_set_video_mode(fn_dev, freenect_find_video_mode(FREENECT_RESOLUTION_MEDIUM, FREENECT_VIDEO_RGB));
ret = freenect_start_video(fn_dev);
// 起動時の仰角を取得
freenect_update_tilt_state(fn_dev);
p_raw_tilt_state = freenect_get_tilt_state(fn_dev);
current_tilt = freenect_get_tilt_degs(p_raw_tilt_state);
next_tilt = current_tilt;
while (running && freenect_process_events(fn_ctx) >= 0)
{
char cmd;
enum video_mode next_mode = current_mode;
...
while(read(fifo, &cmd, sizeof(cmd)) == sizeof(cmd)) {
switch(cmd) {
case 'p':
next_tilt += 1.0;
if(next_tilt > 30.0)
next_tilt = 30.0;
break;
...
case 'D':
next_mode = KINECT_DEPTH;
break;
}
}
if(current_tilt != next_tilt) {
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, next_tilt);
current_tilt = next_tilt;
}
}
if(current_mode != next_mode) {
set_mode(fn_dev, next_mode);
}
}
コマンドは複数文字にすると送信オーバーフロー時のバッファの処理や終端コードなど色々考える必要が出てくるので、単純化のため今回は全て1文字で p が仰角+1度、P が+5度、m が-1度、M が-5度、R がRGBモード、I が赤外線モード、D が深度モードとした。
set_mode 関数では以下のようにビデオモードの切り替えを行う。
貧乏性なので律儀に使わないモードを止めているが、どれだけ性能に影響するかは不明。
void set_mode(freenect_device* fn_dev, enum video_mode next_mode) {
switch(current_mode) {
case KINECT_RGB:
case KINECT_IR:
freenect_stop_video(fn_dev);
break;
case KINECT_DEPTH:
freenect_stop_depth(fn_dev);
break;
}
switch(next_mode) {
case KINECT_IR:
freenect_set_video_mode(fn_dev, freenect_find_video_mode(FREENECT_RESOLUTION_MEDIUM, FREENECT_VIDEO_IR_10BIT));
freenect_start_video(fn_dev);
current_mode = KINECT_IR;
break;
case KINECT_DEPTH:
freenect_start_depth(fn_dev);
current_mode = KINECT_DEPTH;
break;
case KINECT_RGB:
freenect_set_video_mode(fn_dev, freenect_find_video_mode(FREENECT_RESOLUTION_MEDIUM, FREENECT_VIDEO_RGB));
freenect_start_video(fn_dev);
current_mode = KINECT_RGB;
break;
}
}
無事に出来たところで動作確認を行う。
camtest を実行すると、"/tmp/kinect”というファイルが生成されるので、試しにリダイレクトなどでコマンドを書き込んで動作確認を行う。
# echo p > /tmp/kinect
camtest の方はこれで出来たので、あとは CGI と html を作成する。
0 件のコメント:
コメントを投稿