Deep Insider の Tutor コーナー
>>  Deep Insider は本サイトからスピンオフした姉妹サイトです。よろしく! 
書籍転載:Intel RealSense SDKセンサープログラミング(4)

書籍転載:Intel RealSense SDKセンサープログラミング(4)

Unity+RealSenseで作るノンゲームアプリ「スマイルトレーニング」
― Chapter 8 Unityで作る「ゲーム/ノンゲーム」アプリケーション ―

2015年8月18日

インテル RealSense SDKとUnityを使ったサンプルアプリケーションを実際に作成してみる。

前本 知志
  • このエントリーをはてなブックマークに追加

 前回は、インテル RealSense SDK Unity Toolkitの概要とUnity用機能を紹介しました。

書籍転載について

 本コーナーは、翔泳社発行の書籍『Intel RealSense SDKセンサープログラミング』の中から、特にBuild Insiderの読者に有用だと考えられる項目を編集部が選び、同社の許可を得て転載したものです。

 

 『Intel RealSense SDKセンサープログラミング』の詳細や購入は翔泳社のサイト目次ページをご覧ください。プログラムのダウンロードも、翔泳社のサイトから行えます。

ご注意

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

8-3 ノンゲームアプリ「スマイルトレーニング」

 「Unity」といえばゲームエンジン、ゲームの開発環境として知られていますが、ゲーム以外の領域でもUnityを使うと豊かな表現力を持った生活に役立つアプリケーションを簡単に作ることができます。ここでは、インテル RealSense SDKとUnityを使ったサンプルアプリケーションをご紹介します。

図8.38 スマイルトレーニングアプリケーション

8-3-1 センサーアプリケーションとヘルスケア

 にっこりと笑う「スマイル」は、いろんな面で良い影響があると言われています。免疫機構が活性化して健康や病気の予防になるだけでなく、ストレス解消やメンタル面での健康にも役立つと言われています。あと、やはり笑顔の素敵な人は魅力的で好印象を他の人に与えますよね。

 そんな良いこと尽くしの「スマイル」ですが、笑おう笑おうと思っても自由にすぐできるものでもありません。そこで、毎日少しでもスマイルするトレーニングを行うことで、自然に笑顔が出るようにサポートするアプリケーションを、画像認識が可能なセンサーであるRealSenseを利用して作ってみましょう。

 人の動きを認識する3D認識センサーは医療・ヘルスケア分野と親和性が高く、大きな注目を浴びている分野の一つです。そこにUnityを組み合わせれば、これまで医療・ヘルスケア分野とは無縁と思われていた「楽しさ」を伴った、より継続的で効果的なアプリケーションを手軽に構築することができますので、ぜひその入り口を体験してみましょう。

8-3-2 アプリケーションの概要

 今回構築するアプリケーションは、「毎日短時間で楽しくスマイルの練習をする」という狙いで図8.39のような流れを構築することとします。淡々と進行するだけでなく楽しい要素も盛り込んでいきます。ユーザーの表情とキャラクターの表情を同期させて、スマイルが一定の基準を超えるとエフェクトが表示されるというものにしようと思います。

図8.39 アプリケーションの処理の流れ

図8.39 アプリケーションの処理の流れ

 今回キュートなキャラクターとして、ユニティ・テクノロジーズ・ジャパンが提供する開発者のためのオリジナルキャラクター「ユニティちゃん」を利用することにします。

 ユニティちゃんのデータファイルは「UNITY-CHAN!OFFICIAL WEBSITE」からダウンロードすることができます。利用に際してはライセンス条項に同意し、遵守することが必要です。本サンプルプログラムについても下記クレジットを標記の上、解説を行っていきます。今回は「SDユニティちゃん3Dモデルデータ」をダウンロードして利用します。

このアセットは、『ユニティちゃんライセンス』で提供されています。このアセットをご利用される場合は、『キャラクター利用のガイドライン』も併せてご確認ください。

8-3-3 アプリケーションの構築

>シーン構成

 まずは、Unityで下記のようなシーンを作っていきましょう。オブジェクトの位置は正確でなくても構いませんので、特筆すべき点があるオブジェクトのみ解説していきます。

図8.40 Unityのシーン構成
>Image

 ユーザーの顔の映像をリアルタイムに映し出すSDK Unity ToolkitのImageプレファブのインスタンスです。位置・サイズ以外は変更していません。Main Cameraの子オブジェクトとすることで、カメラが移動することがあっても追従するようにしています。

図8.41 ユーザーの顔の映像を映し出すImageを配置
>SD_unitychan_generic

 SDユニティちゃんのパッケージをインポートしたのち、Assets/UnityChan/SD_unitychan/Prefabs/SD_unitychan_genericプレファブをインスタンス化したものです。図8.42のように、いくつかの設定変更を加えます。

>Directional light for UnityChan

 SDユニティちゃんのパッケージのAssets/UnityChan/Prefabs/Directional light for UnityChanプレファブをインスタンス化したものです。

>Controller

 アプリケーションの進行を管理するコントローラーです。空のGameObjectをひとまず用意しておいてください。詳しくは後述します。

>Particle System

 グッドなスマイルを決めたときに再生されるパーティクルです。一例として図8.43のように設定していますが、好みに合わせて設定を変更してみると楽しめるでしょう。

図8.42 SDユニティちゃんのインスペクター設定

図8.42 SDユニティちゃんのインスペクター設定
図8.43 グッドなスマイル時のパーティクル設定

図8.43 グッドなスマイル時のパーティクル設定
>Canvas

 ガイダンスのテキストやユニティちゃんロゴなどを表示するUIレイヤーです。Unity 4.6からサポートされたuGUIのパーツを配置しています。

図8.44 UIを表示するレイヤー
>表情のシンクロ

 ユーザーの表情の状態とユニティちゃんの表情を同期する処理を作ります。インテル RealSense SDKでは、表情(笑っている、怒っているなど)とその表情の強さのレベルを認識することができます。一方、ユニティちゃんの顔には「ブレンドシェイプ」という、指定する重みレベルに応じて連続的に変形するオブジェクトが用意されています。これらを紐付けることで、表情のシンクロを行います。具体的な処理はFaceSync.csスクリプトを作成し、SD_unitychan_genericにアタッチさせることで行っています。

 まず、Unityとのインタフェースでブレンドシェイプを保持するSkinnedMeshRendererプロパティを作成しています(リスト8.4)。ブレンドシェイプには変形点のリストがあるので、今回操作したい点のインデックスを調べて定数化しておきます。

C#
public class FaceSync : MonoBehaviour {
  public SkinnedMeshRenderer faceMeshRenderer;  //顔のメッシュオブジェクト
  private int mouthSmileIndex = 17;             //口の笑顔ブレンドシェイプ
  private int mouthLeftIndex = 24;              //口の左引っ張りブレンドシェイプ
  private int mouthRightIndex = 25;             //口の右引っ張りブレンドシェイプ
  private int eyeSmileIndex = 1;                //目の笑顔ブレンドシェイプ
  private int browSmileIndex = 2;               //眉の笑顔ブレンドシェイプ
リスト8.4 インタフェース(FaceSync.csより抜粋)

 faceMeshRendererプロパティにはSDユニティちゃんオブジェクト内の_faceというオブジェクトを設定します(図8.45)。これでブレンドシェイプとスクリプトのリンクができました。

図8.45 SDユニティちゃんの顔オブジェクト

図8.45 SDユニティちゃんの顔オブジェクト

 毎フレーム呼び出されるUpdateメソッドでは、インテル RealSense SDK、Unity SDK ToolkitのSenseToolkitManagerのインスタンスから顔の情報を取得します。複数の顔が認識されていても最初に見つかった顔を対象としてQueryExpressionsメソッドで表情の情報ExpressionDataを取得します。

C#
void Update()
{
  if (SenseToolkitManager.Instance.FaceModuleOutput == null)
  {
    return;
  }

  // 検出した顔の一覧を取得する
  var faces = SenseToolkitManager.Instance.FaceModuleOutput.QueryFaces();
  if (faces.Length == 0)
  {
    return;
  }

  // 最初の顔の表情を取得する
  var face = faces[0];
  var expression = face.QueryExpressions();
  if (expression == null)
  {
    return;
  }

  if (this.faceMeshRenderer != null)
  {
    this.SyncMouth(expression);
    this.SyncEye(expression);
  }
}
リスト8.5 フレーム処理(FaceSync.csより抜粋)

 ExpressionDataからQueryExpressionメソッドにEXPRESSION_SMILE値を渡して呼び出すとスマイルの情報を取得することができますので、スマイルの強さを表すintensityの値を口元の3点のブレンドシェイプへSetBlendShapeWeightメソッドを呼び出して設定することでSDユニティちゃんの口元がユーザーの口の動きにシンクロして動きます(リスト8.6)。

C#
/// <summary>
/// 口の表情シンクロ
/// </summary>
/// <param name="expression">表情オブジェクト</param>
private void SyncMouth(PXCMFaceData.ExpressionsData expression)
{
  // 口を動かすPXCMFaceData.ExpressionsData.FaceExpressionResult result;
  expression.QueryExpression(PXCMFaceData.ExpressionsData.
    FaceExpression.EXPRESSION_SMILE, out result);
  var level = (int)result.intensity;
  this.faceMeshRenderer.SetBlendShapeWeight(this.mouthSmileIndex, level);
  this.faceMeshRenderer.SetBlendShapeWeight(this.mouthLeftIndex, level);
  this.faceMeshRenderer.SetBlendShapeWeight(this.mouthRightIndex, level);
}
リスト8.6 口のシンクロ処理(FaceSync.csより抜粋)

 目の動きもシンクロしてやると、より自然な雰囲気になりますので、口元と同様に右目と左目の閉じ度合いをシンクロさせます(リスト8.7)。SDユニティちゃんのブレンドシェイプは右目と左目を別々にコントロールすることができないので、左右の平均値を求めて設定をしています。

C#
/// <summary>
/// 目と眉の表情シンクロ
/// </summary>
/// <param name="expression">表情オブジェクト</param>
private void SyncEye(PXCMFaceData.ExpressionsData expression)
{
  PXCMFaceData.ExpressionsData.FaceExpressionResult left;
  expression.QueryExpression(PXCMFaceData.ExpressionsData. 
    FaceExpression.EXPRESSION_EYES_CLOSED_LEFT, out left);

  PXCMFaceData.ExpressionsData.FaceExpressionResult right;
  expression.QueryExpression(PXCMFaceData.ExpressionsData. 
    FaceExpression.EXPRESSION_EYES_CLOSED_RIGHT, out right);

  var level = (int)((left.intensity + right.intensity) / 2);
  this.faceMeshRenderer.SetBlendShapeWeight(this.eyeSmileIndex, level);
  this.faceMeshRenderer.SetBlendShapeWeight(this.browSmileIndex, level);
}
リスト8.7 目のシンクロ処理(FaceSync.csより抜粋)

 ここまでで実行すると、ユーザーの表情に応じてSDユニティちゃんの表情もシンクロして変化するようになりました。

>ステージ進行

 次にアプリケーションのステージ進行を作っていきましょう。ステージ進行をつかさどるのは、シーン内のControllerオブジェクトです。Inspectorは図8.46のようになっています。

図8.46 ControllerオブジェクトのInspectorビュー

図8.46 ControllerオブジェクトのInspectorビュー

 Controller.csスクリプトが、このサンプルアプリケーションのコアになる部分で、中央で全体のコントロールを行うものとなります。Controller.csスクリプトは新規C#スクリプトとして作成し実装を行ったものです。

 まず、Unityとのインタフェース(リスト8.8)ですが、goalGoodSmileCountはトレーニングのゴールとみなす素敵なスマイルの回数です。デフォルトでは5回の素敵なスマイルでクリアすることになっています。

 そのほか、パーティクルやテキストのオブジェクトはシーンから関連付けを行います。

C#
public class Controller : MonoBehaviour {

  /// <summary>
  /// ゴールに必要なグッドなスマイル回数
  /// </summary>
  public int goalGoodSmileCount = 5;

  /// <summary>
  /// スマイル時に再生するパーティクル
  /// </summary>
  public ParticleSystem smileParticle;

  /// <summary>
  /// メッセージ表示用テキスト01
  /// </summary>
  public Text messageText01;

  /// <summary>
  /// メッセージ表示用テキスト02
  /// </summary>
  public Text messageText02;
リスト8.8 インタフェース(Controller.csより抜粋)

 続いて、状態管理用の内部列挙型、プロパティを定義します(リスト8.9)。CurrentStageプロパティは、トレーニングで現在進行中のステージを表します。今回のサンプルではそれほど利用していませんが、複雑なゲームやアプリケーションになると現在のステージ状況は多くの箇所で参照するので、きちんと管理すべき重要なポイントです。

 そのほかは現在スマイルしているかどうかを表すIsGoodSmiling、トータルのスマイル数を保持するGoodSmileCountプロパティを用意しています。

C#
/// <summary>
/// ステージ定義
/// </summary>
public enum Stage
{
  None, 
  Start, 
  Practice, 
  Goal
}
 
/// <summary>
/// 現在のステージ
/// </summary>
public Stage CurrentStage { get; private set; }
 
/// <summary>
/// グッドなスマイルフラグ
/// </summary>
public bool IsGoodSmiling { get; private set; }
 
/// <summary>
/// グッドなスマイル回数
/// </summary>
public int GoodSmileCount { get; private set; }
リスト8.9 状態管理用プロパティ(Controller.csより抜粋)

 フレーム処理は、リスト8.10のようになります。

 Startメソッドでは、現在のステージプロパティを初期化するだけです。Updateメソッドでは、現在のステージが初期状態ならステージ進行を開始します。

 このサンプルアプリケーションではゴール後ステージ状態は初期状態に戻すようにしますので、繰り返しステージ進行が始まる動きになります。

C#
// Use this for initialization
void Start()
{
  this.CurrentStage = Stage.None;
}
 
// Update is called once per frame
void Update()
{
  if (this.CurrentStage == Stage.None)
  {
    //一連のステージ進行を繰り返す
    this.StartCoroutine(this.ProcessStart());
  }
}
リスト8.10 フレーム処理(Controller.csより抜粋)

 リスト8.11は、素敵なスマイルをインテル RealSense SDKが検出したときにスマイル回数をカウントアップする部分です。カウントアップはトレーニング中のステージ以外は行ってはいけないので、条件判定を行って制御を行っています。また、カウントアップ時にはパーティクルを再生して気分を盛り上げます。

C#
/// <summary>
/// グッドなスマイル検出時
/// </summary>
void OnGoodSmile()
{
  if ((this.CurrentStage == Stage.Practice) && !this.IsGoodSmiling)
  {
    //スマイル回数を増やしてパーティクルを再生
    this.GoodSmileCount++;
    this.smileParticle.Play();
  }
  this.IsGoodSmiling = true;
}
 
/// <summary>
/// グッドじゃないスマイル検出時
/// </summary>
void OnBadSmile()
{
  this.IsGoodSmiling = false;
}
リスト8.11 Action連携部分(Controller.csより抜粋)

 さて、このメソッドとインテル RealSense SDKはどのようにリンクするのでしょうか。それがControllerにアタッチされた2つのSendMessageActionです(図8.47)。

 1つは、表情を検出した際にTriggerを発動するFacialExpressionDetected Ruleを設定しています。Fire Over Intensityを80とすることで、かなり素敵なスマイルをしないとTriggerは発動しないようになっています。そしてTriggerが発動すると、Unityのメッセージング機構が呼び出されController.csのOnGoodSmileメソッドがコールされます。

 もう1つのSendMessageActionは、FacialExpressionLost Ruleを付与して逆の認識をさせることでスマイルをやめたことを検出してTriggerを発動させるようになっています。

図8.47 Unityのメッセージングを使ったActionとスクリプトのリンク

図8.47 Unityのメッセージングを使ったActionとスクリプトのリンク

 あとは、ステージごとの処理をUnityのフレーム処理にブロックをかけないコルーチンとして定義していきます。

 練習スタートステージではキー入力待ちをし、キー入力があったら練習ステージへ移行します(リスト8.12)。

C#
/// <summary>
/// スタートステージ
/// </summary>
/// <returns></returns>
private IEnumerator ProcessStart()
{
  this.CurrentStage = Stage.Start;
  this.GoodSmileCount = 0;
  this.messageText01.color = Color.white;
  this.messageText02.color = Color.white;
  this.messageText01.text = "スマイルの練習を始めるよ! ";
  this.messageText02.text = "Enterを押したらスタートだよ! ";
  while (!Input.GetKeyDown(KeyCode.Return)
      && !Input.GetKeyDown(KeyCode.KeypadEnter))
  {
    yield return 0;
  }
  yield return this.StartCoroutine(this.ProcessPractice());
}
リスト8.12 スタートステージ(Controller.csより抜粋)

 練習ステージでは、スマイル回数がゴール条件を満たすまでループします(リスト8.13)。

C#
/// <summary>
/// 笑顔練習ステージ
/// </summary>
/// <returns></returns>
private IEnumerator ProcessPractice()
{
  this.CurrentStage = Stage.Practice;
  this.messageText01.color = Color.white;
  this.messageText02.color = Color.yellow;
  while (this.GoodSmileCount < this.goalGoodSmileCount)
  {
    this.messageText01.text = string.Format("あと{0}回", this.goalGoodSmileCount - this.GoodSmileCount);
    this.messageText02.text = this.IsGoodSmiling? "素敵なスマイルだね! " : "にっこり笑って! ";
    yield return 0;
  }
  yield return this.StartCoroutine(this.ProcessGoal());
}
リスト8.13 練習ステージ(Controller.csより抜粋)

 最後にゴール時のステージです(リスト8.14)。お礼を伝えて少し待機したら、ステージを初期状態に戻します。

C#
/// <summary>
/// 笑顔練習ステージ
/// </summary>
/// <returns></returns>
private IEnumerator ProcessPractice()
{
  this.CurrentStage = Stage.Practice;
  this.messageText01.color = Color.white;
  this.messageText02.color = Color.yellow;
  while (this.GoodSmileCount < this.goalGoodSmileCount)
  {
    this.messageText01.text = string.Format("あと{0}回", this.goalGoodSmileCount - this.GoodSmileCount);
    this.messageText02.text = this.IsGoodSmiling? "素敵なスマイルだね! " : "にっこり笑って! ";
    yield return 0;
  }
  yield return this.StartCoroutine(this.ProcessGoal());
}
リスト8.14 練習ステージ(Controller.csより抜粋)

 以上で、スマイルトレーニングアプリケーションをUnityとインテル RealSense SDKを組み合わせて作成することができました。さらに音楽を付けたり、ステージクリア時の表現を豊かにしたりするなど、簡単なカスタマイズでもっと楽しいものにできると思いますので、ぜひトライしてみて頂ければと思います。

 次回は、インテル RealSenseを活用したサンプルアプリケーション開発の第2弾として、Visual Studio(WPFデスクトップ)とRealSenseを組み合わせる方法を紹介します。

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

書籍転載:Intel RealSense SDKセンサープログラミング(4)
1. インテル RealSenseテクノロジーとは? 構成要素/SDK/動作環境

インテル RealSenseテクノロジーが登場するまでの流れ、RealSenseの仕様やSDKの概要について紹介する。

書籍転載:Intel RealSense SDKセンサープログラミング(4)
2. インテル RealSense SDKの機能概要(手・顔の検出から音声機能まで)

インテル RealSense SDKで利用できる機能を、実際の使用例を示しながら分かりやすく紹介する。

書籍転載:Intel RealSense SDKセンサープログラミング(4)
3. RealSense SDK Unity ToolkitによるUnityアプリ開発の基礎

インテル RealSense SDK Unity Toolkitの概要と、それがUnity向けに用意している各種機能を紹介する。

書籍転載:Intel RealSense SDKセンサープログラミング(4)
4. 【現在、表示中】≫ Unity+RealSenseで作るノンゲームアプリ「スマイルトレーニング」

インテル RealSense SDKとUnityを使ったサンプルアプリケーションを実際に作成してみる。

書籍転載:Intel RealSense SDKセンサープログラミング(4)
5. WPF(Visual Studio)+RealSenseで作る表情感知アプリ

インテル RealSenseを活用したサンプルアプリケーション開発の第2弾として、Visual StudioとRealSenseを組み合わせる方法を紹介する。

サイトからのお知らせ

Twitterでつぶやこう!