ブログ@kaorun55

HoloLensやKinectなどのDepthセンサーを中心に書いています。

Kinect v2の座標をUnityの座標に変換する

ぼくのUnityの使い方は、ゲームよりもセンサーなどを使ったコンテンツが多いので、センサーの座標系とUnityの座標系の変換方法が前からの課題でした。Unityユーザー助け合い所でやっと実現できる回答をもらったので、やってみました。

できたことは

「UnityにKinectのColor画像を表示させて、その上にBodyの関節位置を表示させる」

ことです。

プロジェクト一式はこちらに置いておきます

f:id:kaorun55:20151014102021p:plain

最終的には次の手順となりました。

  • KinectのBodyの座標を取得する
  • KinectのColorの座標系に変換する
  • Unityのスクリーン座標系に変換する
  • Unityのワールド座標系に変換する

f:id:kaorun55:20151014102111p:plain

それぞれの座標系をおさらいすると、Kinectは

  • 3次元のCamera座標系
  • 2次元のColor座標系
  • 2次元のDepth座標系

の3つがあり、相互に変換できます。

f:id:kaorun55:20151014102158p:plain

Unityは

  • 3次元のワールド座標系
  • 2次元のスクリーン座標系
  • 2次元のビューポート座標系

の3つで、やはり相互に変換できます。

f:id:kaorun55:20151014102242p:plain

ここで2次元のColor/Depth座標系とスクリーン座標系の変換ができれば、相互に座標を変換することができそうです。

しかし、KinectのColor/Depthの解像度とスクリーン座標のカメラの座標を合わせる必要があるため、悩んでいたのですが「変換のためのカメラを別に用意する」というアイデアをもらいました。

というわけで、変換用のカメラを用意しました。これで

  • KinectのBody(Camera座標)を取得する
  • Kinect SDKのCoordinateMapper.MapCameraPointToColorSpace()でCamera座標をColor座標に変換する
  • Kinectのカラー座標(1920x1080)をUnityのスクリーン座標(Screen.width,Screen.height)に比率変換する
  • Untiyのスクリーン座標をCamera.ScreenToWorldPoint()でワールド座標に変換する

ことができました。

f:id:kaorun55:20151014102111p:plain

なお、ScreenToWorldPointするためのカメラはProjectionをOrthographicにする必要があります。

f:id:kaorun55:20151014102452p:plain

コード的にはこんな感じです

BodySourceView.cs · GitHub

今回はKinect v2でやりましたが、Webカメラでの顔検出などにも使えるかと思います。

Depthの座標を変換する場合にはMapCameraPointToColorSpaceをMapCameraPointToDepthSpaceにしてください。

同じようなことをLeap Motionもやっていますが、座標変換自体は、Leap Motionの原点に相当するHandControllerを用意し、Local->World座標の変換を行っているようです。カメラ画像との位置合わせのやり方まで終えてませんが、もっとよい方法がありそうです。