Deep Insider の Tutor コーナー
>>  Deep Insider は本サイトからスピンオフした姉妹サイトです。よろしく! 
書籍転載:KINECT for Windows SDKプログラミング Kinect for Windows v2センサー対応版(3)

書籍転載:KINECT for Windows SDKプログラミング Kinect for Windows v2センサー対応版(3)

Kinectの座標とUnityの座標を合わせる
― Chapter 6 Kinect for Windows SDK v2をUnityで使う 6.3.5 ―

2015年11月2日

UnityでKinectを使う際にポイントとなる、Kinectの座標系とUnityの座標系を合わせる方法を、実際のサンプルコードを通して説明する。

中村 薫
  • このエントリーをはてなブックマークに追加

 UnityでKinectを活用する方法を紹介します。前回はUnityによるKinect活用の基礎を解説しました。今回はその続きです。

書籍転載について

 本コーナーは、秀和システム発行の書籍『KINECT for Windows SDKプログラミング Kinect for Windows v2センサー対応版』の中から、特にBuild Insiderの読者に有用だと考えられる項目を編集部が選び、同社の許可を得て転載したものです。

 

 『KINECT for Windows SDKプログラミング Kinect for Windows v2センサー対応版』の詳細や購入は秀和システムのサイト目次ページをご覧ください。プログラムのダウンロードも、秀和システムのサイトから行えます。

ご注意

本記事は、書籍の内容を改変することなく、そのまま転載したものです。このため用字用語の統一ルールなどはBuild Insiderのそれとは一致しません。あらかじめご了承ください。

6.3.5 Kinectの座標とUnityの座標を合わせる

 ここで一つコードを触ったサンプルを紹介します。Kinectを使うUnityコンテンツの場合、Kinectのカラー画像とBodyの座標を合わせなければならないことが多いでしょう。KinectにはKinectの座標系が、UnityにはUnityの座標系があるので、どちらか一方に合わせなくてはなりません。ここではKinectの座標系をUnityの座標系に変換して表示します。

 まずKinectとUnityの座標系を確認します。KinectにはBodyのカメラ座標系、Depth(赤外線、BodyIndex)のDepth座標系、カラー画像のカラー座標系の3種類があり、それぞれ相互に変換することができます。

 続いてUnityです。Unityにも3つの座標系があります。Unity内の実際の座標系であるワールド座標系、画面から見たスクリーン座標系、画面の解像度に拠らない2次元のビューポート座標系があり、やはり、それぞれ変換できます。

 KinectとUnityが扱える座標系のうち、いずれか1つずつを互いに変換できれば良いことになります。結論からいうと、Kinectのカラー座標系をUnityのスクリーン座標系に変換します。これによって、Kinectのカメラ座標系(Body)をUnityのワールド座標系(実空間)に移動できるようになります。

 この変換にはKinectのColor/Depthの解像度とスクリーン座標のカメラの座標を合わせる必要がありますが「変換のためのカメラを別に用意する」ことで解決しています。

 より具体的な手順は次の通りです。

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

 では、このシーンを作ってみましょう。必要なGameObjectは次の3つです。

  1. カラー画像表示用のCube(など表示可能なもの)
  2. 変換用のカメラ
  3. Body表示用の空のGameObject

 まず、カラー画像表示用のCubeを配置します。これは先ほどカラー画像の表示で行った手順と同じです。「Hierarchy」ビューにCubeを配置します。Posision、Rorationはすべて0に、ScaleをX=19.2、Y=10.8に設定し、ColorSourceManagerおよびColorSourceViewスクリプトを追加します。

 次に変換用のカメラを配置します。「Hierarchy」ビューに「Camera」を追加します。「Posotion」はX=0、Y=0、Z=−5とします。Z座標の値はCubeが見える位置であれば任意で構いません。「Projection」を「Orthographic」(平行投影)に変更します。「Perspective」ですと座標の変換ができません。最後に「Size」を変更します。「Camera」の画角が「Cube」にぴったり合うように設定します。ここでは5.4に設定しています。1つのシーンに2つのAudio Listenerがあると警告がでるため、Audio Listenerを削除または無効にします(Main Cameraのみ有効になっている状態)。

 最後にBodyのための空のGameObjectを作成します。基本的には先ほどの「Bodyを表示する」と同じ手順です。

 一点だけ異なるのが、先ほどは「BodySourceView」を追加しましたが、今回は「BodySourceView」をベースにコードを変更したものを使用します。

 Unity上ではなく、Windowsのエクスプローラー上でBodySourceView.csファイルをコピーし、ColorBodySourceView.csとします。スクリプトのクラス名も同様にColorBodySourceViewとします。配置先のフォルダーは任意で構いませんが、ここでは「Project」の直下に「Scripts」フォルダーを作成し、そこに配置しています。

 ColorBodySourceViewスクリプトを開きコードを編集します。変数として、変換用のカメラ(ConvertCamera)、Kinectの座標変換オブジェクト(CoordinateMapper)そしてKinectのカラー画像の幅と高さの値を追加します。

C#
public class ColorBodySourceView : MonoBehaviour
{
  public Material BoneMaterial;
  public GameObject BodySourceManager;

  private Dictionary<ulong, GameObject> _Bodies = new Dictionary<ulong, GameObject>();
  private BodySourceManager _BodyManager;

  public Camera ConvertCamera;

  private Kinect.CoordinateMapper _CoordinateMapper;

  private int _KinectWidth = 1920;
  private int _KinectHeight = 1080;
  ... 
}

 続いてUpdate()でCoordinateMapperの設定を行います。なお、BodyManagerのSensor(KinectSensorクラス)がpublicになっていないため、BodySourceManagerにプロパティを追加します。

C#
void Update ()
{
  ...
  if ( _CoordinateMapper ==null ) {
    _CoordinateMapper = _BodyManager.Sensor.CoordinateMapper;
  }

 BodySourceManagerを開き、次のプロパティを追加します。

C#
public KinectSensor Sensor
{
  get
  {
    return _Sensor;
  }
}

 最後に座標変換用のコードを追加します。ColorBodySourceViewクラスに戻り、GetVector3FromJoint()メソッドを変更します。staticメソッドになっているので、staticを削除します。KinectのBodyから取得できるJoint(関節)座標はKinectのカメラ座標系となっているので、MapCameraPointToColorSpace()メソッドでカラー座標系に変換します。

 続いてScreen.widthおよびScreen.heightを使ってKinectのカラー座標系をUnityのスクリーン座標系に変換します。

 最後にUnityのカメラ(Camera)のScreenToWorldPoint()メソッドでワールド座標系に変換します。このときY座標が上下逆になるので−1を掛けて反転、Z座標は単一でよいので—1(Cubeの少しカメラ側)に設定します。

C#
private Vector3 GetVector3FromJoint(Kinect.Joint joint)
{
  var valid = joint.TrackingState != Kinect.TrackingState.NotTracked;
  if ( ConvertCamera != null || valid ) {
    // KinectのCamera座標系(3次元)をColor座標系(2次元)に変換する
    var point =_CoordinateMapper.MapCameraPointToColorSpace( joint.Position );
    var point2 = new Vector3( point.X, point.Y, 0 );
    if ( (0 <= point2.x) && (point2.x < _KinectWidth) && 
         (0 <= point2.y) && (point2.y < _KinectHeight) ) {

      // スクリーンサイズで調整(Kinect->Unity)
      point2.x = point2.x * Screen.width / _KinectWidth;
      point2.y = point2.y * Screen.height / _KinectHeight;

      // Unityのワールド座標系(3次元)に変換
      var colorPoint3 = ConvertCamera.ScreenToWorldPoint( point2 );

      // 座標の調整
      // Y座標は逆、Z座標は-1にする(Xもミラー状態によって逆にする必要あり)
      colorPoint3.y *= -1;
      colorPoint3.z = -1;

      return colorPoint3;
    }
  }

  return new Vector3( joint.Position.X * 10, 
                      joint.Position.Y * 10, 
                      -1 );
}

 以上でスクリプトの変更は完了です。

 空のGameObjectにBodySourceManagerとColorBodySourceViewを配置します。ColorBodySourceViewのBone MaterialにBoneMaterialを、Body Source ManagerにGameObject自身を設定します。Convert Cameraには先ほど追加した変換用のCmaeraを設定します。

 これを実行すると、Kinectのカラー画像の上に関節のオブジェクトが表示されるようになります。関節のオブジェクトはUnity上のものですので、当たり判定を設定すれば、Unity内のGameObjectに対して干渉するようになります。

 次回は、実際の活用例として、Kinectでユニティちゃんを動かす方法を説明します。

※以下では、本稿の前後を合わせて5回分(第1回~第5回)のみ表示しています。
 連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。

書籍転載:KINECT for Windows SDKプログラミング Kinect for Windows v2センサー対応版(3)
1. Kinect開発者のための、Unityの基礎知識とインストール

UnityでKinectを活用しよう。Unityのインストール方法と、Kinectを使うためのパッケージの導入方法、Visual Studio Tools for Unityの概要を解説する。

書籍転載:KINECT for Windows SDKプログラミング Kinect for Windows v2センサー対応版(3)
2. UnityでKinectを使う(カラー画像/赤外線画像/Depthデータ/Body)

Unity+Kinectの開発環境が整ったら、実際にUnityからKinectの機能を使ってみよう。UnityによるKinect活用の基礎を解説。

書籍転載:KINECT for Windows SDKプログラミング Kinect for Windows v2センサー対応版(3)
3. 【現在、表示中】≫ Kinectの座標とUnityの座標を合わせる

UnityでKinectを使う際にポイントとなる、Kinectの座標系とUnityの座標系を合わせる方法を、実際のサンプルコードを通して説明する。

書籍転載:KINECT for Windows SDKプログラミング Kinect for Windows v2センサー対応版(3)
4. Kinectでユニティちゃんを動かす

Kinect+Unityの面白さを体感! Kinectで得られた全身骨格の動きを、コードを書かずに、3Dモデルのユニティちゃんに反映させてみよう。

書籍転載:KINECT for Windows SDKプログラミング Kinect for Windows v2センサー対応版(3)
5. Kinect WPF ControlsでWPFアプリでもジェスチャーを活用しよう

WPFアプリにKinectを操作するための機能を実装する場合にはKinect WPF Controlsが便利だ。その機能概要を紹介する。

サイトからのお知らせ

Twitterでつぶやこう!