![見出し画像](https://assets.st-note.com/production/uploads/images/22552011/rectangle_large_type_2_e71ea162a1dbe473f761431e8ca4af12.png?width=1200)
【体験型】「絵を作るシリーズ」アプリの技術紹介
どうも、インタラクションデザイナーのMIZUTANI KIRIN(@mizutanikirin)です!普段Kinectを中心にいろいろなセンサーを使い体験型ゲーム、インタラクションアプリを作っています。今回は「絵を作るシリーズ」について技術的な話を中心に紹介していきます。
1. 「絵を作るシリーズ」ってどんなもの?
簡単に説明すると体を動かして頭上に絵を作っていくアプリ群です。イオンモール津南でのアプリが好評だったため横展開し、今までに「イオンモール津南」「KOBOSHI-KIDS (会津デジタル未来アート展)」「シャポー市川 あそぶば」3つのアプリを作成しています。3つのアプリを順に追って紹介していきます。
「イオンモール津南」のアプリは国内外で複数のイオンモール店舗(7店舗ほど)に展開されてます。
2. イオンモール津南のアプリ
どんなアプリ?
イオンモールの大きなディスプレイ前でプレイできるアプリで、Webカメラを使って動きを検出させています。手を動かすと手から星屑が出てきて空に上っていき星座を作っていきます。(※動画は開発時のものです。)
開発環境
- Windows 10 Pro
- webカメラ
- Unity 2018.2.0f2
- OpenCV for Unity
開発時に気をつけた点
この案件では手の動きの検出に苦労しました。OpenCVやDlibで顔認識を使えれば手の位置が絞り込めるため楽だったのですが、カメラに映る顔が小さくなり認識してくれなく使用を断念しました。
そのためこのアプリではOpenCVの差分動体検知で動いている部分から手(実際には腕)だろうと思われる部分を検出しています。PCのスペックがさほど高くなかったため処理を速くするために以下(1)~(3)の方法で簡略化してアプリ作成しています。それをどういう方法で実現したかを書いていきます。
(1) ピクセル操作する際Color()でなくColor32()を使う。
Color32()でピクセル処理する方が速いためです。
Color[] pixels = webCamTextureToMatHelper.GetWebCamTexture().GetPixels();
↓
Color32[] pixels = webCamTextureToMatHelper.GetWebCamTexture().GetPixels32();
(2) 処理範囲を絞る
当然のことですが、画面の上半分は映っていないので処理する必要はありません。どこに手の動きがあるかの判別(差分動体検知)についてはこの範囲で取得しています。
(3) 色の検知は3つのライン上で検知しています。
手から出る星屑は服の色にしているため色検知もしています。以下の手順で色判別をしています。
1. 手の場所から胴体がどのあたりにあるか判別する
2. その中心の色を取得する (※胴体の中心と一番近いラインの色を取得しています)
3. 取得した色を鮮やかにする (4の判別で使うため)
4. その色が指定された7色のどの色に近いかを判別し星屑の色を決定する
色検知を「(2) 処理範囲を絞る」の範囲で処理をするとさらにfpsが低くなったため、色の処理範囲をさらに絞り3つのライン(下の画像の青いライン)で色取得することにしました。人がディスプレイを見て星屑を出すとき胴体はほぼ3つのライン上のどこかに入ってきます。
3. KOBOSHI KIDS
どんなアプリ?
シリーズ2つ目は「会津デジタル未来アート展」に設置した「KOBOSHI KIDS」です。手を動かすとアバターの頭の上の風船が大きくなっていき、ある一定の大きさになると飛んで頭上の雲を消していきます。雲をすべて消すと子どもたちが描いた絵が現れていきます。
開発環境
- Windows 10 Pro
- Kinect V2
- Unity 2018.3.14f1
- Kinect v2 Examples with MS-SDK and Nuitrack SDK
開発時に気をつけた点
このアプリはwebカメラではなくKinect V2で人検知をしているためwebカメラと違ってかなり楽でしたが、手が動いたかどうかの判別には気をつけました。
(A)のように指定したフレーム毎に差分で手の位置を見ていると上図のように手の速さによって前と同じ位置に手があることになるため動いたと判別できません。
一方(B)のように一定フレーム間の手の位置を配列に記録しておき、その中で現在の位置と一番離れている距離が離れている場合に手の動きがあると判別させる方法だと、フレームに関係なく手が動いているかどうかの判別ができます。
4. シャポー市川 あそぶばのアプリ
どんなアプリ?
シリーズ3つ目は「シャポー市川 あそぶば」に設置しているアプリです。手を動かすと手から紙吹雪が出て、頭の上の風船に入っていきます。風船が大きくなると上に昇っていき、キャンバスのあるところで破裂して紙吹雪が飛び散り絵が作られていきます。(※動画は開発時のものです。)
開発環境
- Windows 10 Pro
- Kinect V2
- Unity 2018.3.14f1
- Kinect v2 Examples with MS-SDK and Nuitrack SDK
開発時に気をつけた点
シリーズ3つ目ということで、使いまわしできるコードが多かったり、他のシリーズの経験が生かされており、技術的に特別気をつけた点などはありません。が、あえて言うなら手から出る紙が頭に移動する部分です。頭の位置は常に変わるため、違和感なく紙を風船に吸い込ませるために紙1枚のGameObjectに以下のコードを書いています。
void Update(){
// neckPosはKinectで取得した首の位置
float angle = Angle2(transform.localPosition, neckPos);
float moveX = speed * Mathf.Cos(angle * Mathf.Deg2Rad);
float moveY = speed * Mathf.Sin(angle * Mathf.Deg2Rad);
transform.localPosition = new Vector3(
transform.localPosition.x + moveX,
transform.localPosition.y + moveY,
transform.localPosition.z
);
// 首に近いと自身を削除
float distance = Vector2.Distance(transform.localPosition, new Vector2(neckPos.x, neckPos.y));
if (distance < speed) {
Destroy(gameObject);
}
}
// 2点間の角度取得
privte float Angle2(Vector2 p1, Vector2 p2) {
float dx = p2.x - p1.x;
float dy = p2.y - p1.y;
float rad = Mathf.Atan2(dy, dx);
return rad * Mathf.Rad2Deg;
}
最後まで読んでいただきありがとうございます!読んでいただいた方に少しでも参考になれば幸いです。
編集後記
広報のマリコです!今回技術紹介させて頂いた「絵を作るシリーズ」は、MIZUTANIKIRINらしい夢のあるコンテンツでドンドン横展開しながら様々な機能が追加された子供たちに大人気のコンテンツです❗私が見た「KOBOSHI-KIDS」は、親子連れや保育園の先生にも大絶賛されていました✨ちなみにイオンモールさんのコンテンツはまだ未体験なので、県内(私はリモートワークで福島県)のイオンにも導入されないかなぁ、なんて思っていたりします😊ぜひお近くの方は体験してみてくださいね。
この記事が気に入ったらサポートをしてみませんか?