SyntaxHighlighter

2011-05-29

WebSocket勉強会に行ってきた

タイトル通り、5/28に開催されたWebSocket勉強会に行ってきました。内容自体は、リンク先の発表資料(29日時点では歯抜け状態ですけど)やUstの録画、はたまたTogetterを見れば良いとして、折角なので自分なりの感想を書いておくことにしよう。

  • 最初のコマにWebSocketのプロトコル内容を中心とた発表がありました。どんどん内容が変わっているようで、いつ策定されるんだろうというのがとにかく気になります。自分アプリケーションの開発屋さんじゃなくて、サーバとかインフラ寄りの人なので、プロトコルは気になるところです。とりあえず時間のある時にプロトコルの仕様書に挑戦してみようかと思いました。
  • その後いくつか事例紹介が続きましたが(と一括りにしてしまって、発表者さんごめんなさい><)、よく出てくる組み合わせがnode.jsとさくらのVPS。
    • HTML5とかに興味ある人って基本Javascript好きな人っていう勝手な先入観があるので、サーバのjavascriptで書きたいのかなあ。まあ単純にWebSocketと相性が良いのかも知れない(その辺がよく分からない)。C10Kってのも話は聞いたことあるだけで細かいことは知らないので、この辺も勉強しておきたいところ。サーバ関係の仕事してるなら、知っとけって言われるかも知れないし。
    • node.jsも折角なんで使ってみたい。
    • さくらのVPSは個人ユーザ向けサーバでは鉄板なのだろうか。確かに1ヶ月1000円未満でサーバ使えるのは魅力。
  • ブラウザとハードウェアをつなげる話も出てきました。ブラウザでハードウェア操作は自分も興味ある部分です。遠い過去の昔に対抗心だけでこんなブログも書いたことあるし。。。そういう自分も今や完全にkinectの軍門に下ったわけだけど。
    • node.jsがあれば、機器がTCPを喋れれば(喋れなかったらさらにプロキシ 見たいなものを挟む)websocketで通信が出来るらしい。面白い。
    • しかし、@ndrugerさんのこの分野への投資額は相当なものだなあ。kinectにHMD、しかも対戦ゲームを作ってるってことなので、もう一セットあるのかしら。。。
  • 最後の方は、どちらかと言うとサーバに寄った話だったような気がする。node.js以外にJetttyという選択肢もあるとか。
    • 数あるHTML5関係の機能の中でWebSocketはサーバ機能が必須、というのが敷居を高くしている要因の一つらしい。アプリケーションの仕様や設計に依ることが大きいと思うけど、クライアント側のコードを書くよりサーバ側のコードを書く方が圧倒的に難しい気がする。単純なウェブアプリケーションではなくて、コネクションを管理したりと正にサーバを作成するような感じな気がする(まあ、実際はWebSocketサーバがその辺よしなにやってくれるとは思うけど)。個人的には、サーバ側の開発パターンが確立、整理されるようになると、もう少し敷居が下がるのかなあと思ったりします。
    • まあ、WebSocketが使えるサーバのサービスがほとんどない(だからさくらVPSが流行る)っていう状況も何とかなると、って思います。クライアント側のネットワーク(プロキシとかプロキシとかプロキシとか。。。)とサーバ側のネットワーク(通信に影響を与えるかも知れない機能を許可するのは、インフラ屋さん的にはとっても嫌がるってのは、身にしみて感じております。。。)がネックになりそう。
    • あと、WebSocketのサーバサービスが増えるにはWebSocketは儲かる匂いがしないと、、、そんな匂いを漂わせるにはWebSocket対応サービスが増えないと、、、というジレンマ。
    • だからしばらくはLAN内での使用に限定されるのかも。
    • iPhoneで操作できるプレゼン機能、欲しい。。。
なかなか、濃縮されて深い勉強会だったと思いました。次回までにもう少しWebSocketについて勉強して、参加できればなあと思いました。
なんか、勉強したいことがどんどん増えていくな、時間は有限なのに。。。

# WebSocketなのかWebsocketなのかwebsocketなのか、正式名はなんでしょう。。。?

2011-05-06

kinectで遊んでみる 再び

大型連休にも関わらず、自分は何やっているんだろうと思いつつ、またkinectを触っています。
今回はARっぽいものを作ろうとしたけど、結論から言うと、(例によって)あまり実りの無い実装をしてしまったようです。なので、反面教師的な意味を込めて記録しておきます。

内容は4月にあったkinectハッカソンvol.2 +そのとき構想だけのことろを実際に作ってみたらこうなった、という部分です。

やろうとしたこと
ちょっと前に(今も??)ARってのが流行ってたけど、基本、画像にとあるモデルをオーバーラップさせて表示させているけど、kinect使うと3次元空間上(細かい人だと2.5次元と言ったりするらしい。。。)に(3次元復元した)画像データとモデルを(比較的簡単に、というか、先人たちの情報を使って)表示出来そうなので、頑張ってみようと思いました。
従って、やるべきことは、RGB画像からモデルを表示する領域(以下対象領域)を取得して、その点を3次元上にプロットして、そこにOpenGLでモデルを表示させる、と言うことになります。

まあ、誰かがどこかでやってそうな内容だけど、気にしない、気にしない(あまりそういう調査をしない人なので)。。。

構成
流れはこんな感じ。
  1. RGB画像から、モデルを表示する対象領域を切り出す(手とか、方眼紙とか。。。)
  2. 1.で求めた領域に対応するdepth画像の領域を取り出す
  3. 2.で取り出した領域を3D点に復元する
  4. 3D点から平面を推定して、位置とx,y,z軸を頑張って計算する
  5. 4.で求めた座標上にモデルを表示する
  6. その他の領域を3Dに復元して表示する
使ったツールは、kinect制御にlibfreenect、画像処理ツールとしてOpenCV2.2、描写にOpenGLを使った。言語はCです。

RGB画像の領域を切り出す
調べていないので、とっても推測ですけど、OpenNIとかのボーン検出って、depth画像を元にやっていそうな気がするけど、あまのじゃくな自分としては、RGB画像から領域を取得することにしました。単純しごくな方法で、kinectのRGBカメラ画像から色情報(HSV)を使って切り出すことにしました。
  1. RGBからHSVに変換
  2. 各ピクセルについてしきい値内にあるものを取得
  3. オープニングとクロージングを使ってノイズを削減
  4. 輪郭抽出をして、最も面積が大きいものを対象領域とする
あまりに単純なため、色の明るさが自動で調節されてしまう上に、パラメータが職人的でそのわりに、精度も良くない。あくまでkinectのRGBカメラは表示用なんだなあと思います。
RGB画像
対象領域候補の抽出:上のパラメータを変えて色の範囲を決めます。。。

depth画像の領域を切り出す
RGB画像から取得した対象領域を3次元上に表示する為には、対象領域の対応するdepth画像上の点を取得する必要があります。
そのやり方は単純に、
img_rgb.x = img_depth.x, img_rgb.y = img_depth.y
では無いです。depth画像のある(dx, dy)に対応するRGB画像の(cx, cy)を求める計算方法は、http://nicolas.burrus.name/index.php/Research/KinectCalibration とか http://graphics.stanford.edu/~mdfisher/Kinect.html に詳しいです。これをパラメータ値も含めて、参考にしました。本当はキャリブレーションしないといけないところなんですが、、、

3次元点の復元
depth画像から3次元点の復元が出来ます。これも、上記の2つのリンクに詳しいです。libfreenectのサンプルコードや、ofxKinectにもやり方があります。

抜粋:
 img_depth : depth画像のなまデータ
 mask_hand : RGB画像から抽出した対象領域(名前は昔の名残。。。)
 img_targetarea : RGB画像から抽出した対象領域に対応したdepth領域
 map_3d : depth画像の各点の3次元点を記憶
 map_image : depth画像の各点に対応するRGB画像の座標値を記憶 

cvSetZero(img_targetarea);
 cvSetZero(map_3d);
 cvSetZero(map_image);
 for (int i=0; i<DISPLAY_SIZE_H; i++) {
  for (int j=0; j<DISPLAY_SIZE_W; j++) {
   float tx, ty, tz;
   float w, h;
   uint16_t d = CV_IMAGE_ELEM(img_depth, uint16_t, i, j);
   if (0 < d && d < 2047) {
    transformDepthTo3D(j, i, d, &tx, &ty, &tz);
    CV_IMAGE_ELEM(map_3d, float, i, j*3)     = tx;
    CV_IMAGE_ELEM(map_3d, float, i, j*3 + 1) = ty;
    CV_IMAGE_ELEM(map_3d, float, i, j*3 + 2) = tz;
    transform3DToRGBImage(tx, ty, tz, &w, &h);
    CV_IMAGE_ELEM(map_image, float, i, j*2)     = w;
    CV_IMAGE_ELEM(map_image, float, i, j*2 + 1) = h;
    int rw = cvRound(w);
    int rh = cvRound(h);
    if (0<= rw && rw<DISPLAY_SIZE_W && 0 <= rh && rh < DISPLAY_SIZE_H) {
     uint8_t c = CV_IMAGE_ELEM(mask_hand, uint8_t, rh, rw);
     if (c > 0) {
      // 対象領域
      CV_IMAGE_ELEM(img_targetarea, uint8_t, i, j) = 255;
     }
    }
   }
  }
 }

この辺のコードが出てきたから、自分のやり方がどうもうまく行かない気がしてきました。。。
四角い青いカード
四角い青いカードに対応するdepth画像を切り出したところ

前段の画像処理がうまくないせいか、プログラムが間違っているせいか、キャリブレーションをちゃんとやっていないせいか、はずれ値データが沢山取れてしまいます(そもそも構想から問題があった、が正解のような気がします)。

対象領域の位置とx,y,z軸を計算する
モデル表示の為に、対象領域の3次元上の位置と3軸が必要になります。そのために対象領域の3次元上の平面推定をします(平面が推定できればあとは適当な条件をつけてやれば、位置と3軸が求まります、きっと。。。)。
ところで、3次元点列からの平面推定ってどうやるんでしょう。私は一般的な方法を知りません。あったとしてもとても面倒そう。
z軸の誤差を最小にするする方法なら、例えばこんな感じらしいけど、ある点から平面への垂線の距離を最小にする場合、面倒らしい。このQAページによると、主成分分析を使うといいらしい、とのことで、OpenCVの cvCalcPCA 関数を使って、固有値の大きい順にx, y, z軸を決めることにしました(位置も一緒に求められます)。なので頑張らなくても計算できました。

でも、計算した軸はかなりふらついてしまって、その結果、きれいに物体が表示できないのが正直なところです(主成分分析のせいではなくて、前段の画像処理の部分の制度の問題と思われます)。あまりのふらつき具合に、座標軸なんて推定するだけ無駄のような気になってきます。

座標上にモデルを表示する
対象領域の3次元上の位置と軸を求めたので、そこから、OpenGL上でのMODEL_VIEW変換行列が計算できます。座標変換してお望みのモデルなり何なりを表示出来ます。
抜粋:
 hand_X_axis : 対象領域の各軸
 hand_center : 対象領域の中心

void loadHandPositionMatrix() {
 GLfloat mat[16] = {
  hand_x_axis[0], hand_x_axis[1], hand_x_axis[2], 0,
  hand_y_axis[0], hand_y_axis[1], hand_y_axis[2], 0,
  hand_z_axis[0], hand_z_axis[1], hand_z_axis[2], 0,
  hand_center[0], hand_center[1], hand_center[2], 1
 };
 glMultMatrixf(mat);

その他の領域を3次元に復元して表示
3次元上に生成した点にRGB画像をテクスチャとして貼る方法も、libfreenectのサンプルコードにあります。

結果
対象領域の3次元点
対象領域にモデル表示、その他領域も表示
ちなみに処理の速度を測ってみると、7FPSくらい。かなり微妙。。。

感想と反省
  • RGB画像上で画像処理するのはやはり、あまり賢い選択ではないようです。折角のdepth画像を有効に使って領域を取得した方がいいんだなあと思います。
  • となると、RGBの画像処理を使わずに、OpenNIのボーン検出をして、そこから特徴点の3次元を取得、3次元点を使ってモデルを表示した方が精度が高くなるような気がします。また、きっとそっちの方がkinectらしい気もします。。。
  • あくまでRGB画像処理派なら、ARToolkitを使うということも考えられます。それはどこかの誰かがやっていたような気がしますが。。。
  • OpenCV1.xを少し触ったことあるけど、2x、ヘッダファイルとか変わり過ぎでしょ。関数はそれほど変わってないけど、引数の増えた関数もあった。ウェブ上にもまだあまり日本語情報が無い。。。
  • OpenCVもC++の方が情報が多いような気がするので、C++使えるならそっちを使った方が良いのでしょう(今更勉強する気にはあまりなれないけど)。
  • まあOpenCVとかOpenGLの勉強になったので良しとしよう。。。
  • 例によって自己満足な誰得?な内容です。
Related Posts Plugin for WordPress, Blogger...