• 検索結果がありません。

平成 25 年度卒業研究中間レポート 拡張現実 (AR) を用いた 3D シミュレーションアプリの開発 - Kinect で実現するナチュラルユーザーインターフェース - 近畿大学工学部 情報システム工学科 太田雄介 提出

N/A
N/A
Protected

Academic year: 2021

シェア "平成 25 年度卒業研究中間レポート 拡張現実 (AR) を用いた 3D シミュレーションアプリの開発 - Kinect で実現するナチュラルユーザーインターフェース - 近畿大学工学部 情報システム工学科 太田雄介 提出"

Copied!
26
0
0

読み込み中.... (全文を見る)

全文

(1)

平成 25 年度 卒業研究中間レポート

 

拡張現実(

AR)を用いた 3D シミュレーションアプリの開発

Kinect で実現するナチュラルユーザーインターフェース

-近畿大学工学部 情報システム工学科

1010960077 太田雄介

2013.08.09 提出

(2)

目次 1. 研究の背景と目的...1 1.1 Kinect の概要... 1.1.1 Kinect の仕組み... 1.1.2 Kinect の機能...1-2 1.2 Kinect の実用例...2 2. 開発環境...2-3 2.1 Kinect for Windows SDK...3 2.1.1 Kinect for SDK のアーキテクチャ...4 2.1.2 NUI API... 2.1.3 Audio API...5 2.2 OpenCV... 3. 研究計画... 3.1 役割分担...6 4. 研究の現状... 4.1 トラブル 1(ビルドエラー)...6-9 4.2 トラブル 2(デバッグエラー)...9-11 5. 考察...12 6. 参考文献...13 7. ソースコード(スケルトンの認識)...14-24

(3)

1.研究の背景と目的  今日の情報通信技術の発展は,iPhone や Wii など様々な形態のデバイスを生み出した.特に Kinect は何も持たず,何にも触れずに体の動きや声でコンピュータと情報のやり取りを行うこと ができるので,あらゆる分野に応用され今後も更なる発展が期待されるデバイスである.  コンピュータを操作する際のデータ入力の操作感(ユーザーインターフェース)は,よりユー ザに優しいものに移り変わってきている.元々は全ての操作をキーボードからのコマンド入力に よって行ってきたもの(Character-based User Interface : CUI)が,マウスなどのポインティングデバ イスによって基礎的な操作を行うことができる(Graphical User Interface : GUI)までに進化した.そ してKinect のように直感的な人間の動作で操作できるインターフェースは,Natural User Interface (NUI)と呼ばれ,次世代のユーザーインターフェースとして注目されている.本研究では Kinect の特徴を活かした拡張現実空間を構築することで,これまで実現できなかった効果を生み出す視 覚的シミュレーションアプリを開発したいと考えている. 1.1 Kinect の概要 Kinect(キネクト)とは,Microsoft 社が発売している Xbox360 用の新デバイスのことであり,ユーザーは Kinect の前で物理コントローラーを使わずにゲーム操 作を行うことが出来る,この操作をを可能にしているの は,Kinect 本体に搭載されている RGB カメラ・距離カ メラ・深度センサー・4 つのマイクアレイ,チルトモー ターであり,カラー情報やプレイヤーの身長・骨格・ 三次元的位置を認識,追跡しモーションキャプチャー を合成することが出来る.また,マイクを搭載してい るため,音源位置特定・音声認識をすることも出来る ので,声によるゲーム操作も可能にしている.[1] 現在Microsoft 社は,Kinect を Windows 上で動作させる ためのKinect for Windows SDK を一般公開しており, Windows(Windows7 以降)上で Kinect を用いたアプリ ケーションの開発が可能となっている. 1.1.1 Kinect の仕組み Kinect の内部には以下のが搭載されている. ・距離カメラ ・RGB カメラ(赤外線プロジェクタ) ・深度カメラ ・マイクアレイ(×4) ・チルトモーター 1.1.2 Kinect の機能[2] 赤外線プロジェクタによって照射されたレーザは対象物にぶつかることで歪み,距離が離れれば 図 -1  Kinect カメラ 図 -2  Kinect の内部 [2]

(4)

及び深度を取得している.さらにその情報を基に関節の位置を推定して人間の骨格を形成(骨格 追跡)することができる.つまり,Kinect が人の骨格と動きを検出するのは距離カメラと深度セ ンサの機能であり,その画角(視野)に対応したカラー画像を撮影するのが RGB カメラである. 従ってKinect が認識できるのは赤外線プロジェクタのレーザが届く範囲内であるといえる.また、 赤外線を用いるので暗い場所でも認識可能であるが,逆に対象物が明るすぎたり反射率の高い素 材である場合には認識できない. Kinect 内部にマイクが 4 つある理由は,それぞれのマイクで収集した音声を分析することで音の ずれ具合などから音源の位置を割り出すためである.音源位置は左右に±50°の範囲で検出可能 であり,複数のプレイヤーがKinect の前にいたとき誰が発声しているのかを判別できる.(上限 7 人まで)また,マイクにはエコー・キャンセラ機能が備えられており,発する声とソフトウェ ア内の音源は分離する。 1.2 Kinect の実用例 Kinect は様々な分野で活躍できる可能性を秘めている. ・医療現場 : 手術中の執刀医が患者の情報をコンピュータ上で閲覧する際,従来は衛生状態を 保つために自らの操作が不可能であるため,情報の即時提示が困難なことや,集中力低下のリス クがあったが,Kinect を用いて片手または声だけで容易に操作をすれば,衛生状態を保ちながら 執刀医が直感的に操作をすることができるようになる.[3] ・リハビリテーション : 患者がKinect を用いたリハビリテーションを行えば,直感的な操作で 比較的簡単にできる上,患者自身のモチベーションの維持が期待できる。[4] ・アパレル : 服屋には服の種類だけでなく,それぞれのサイズや色など数多くのバリエーショ ンの服が並べられている.これらの服の中から客が納得して購入するまで試着を繰り返すのは, 多くの手間や時間がかかるだけでなく商品である服自体が汚れたり傷んでしまう可能性がある. そこでKinect を用いてバーチャルな試着をすることができれば,手軽に何度も購入予定の服を 着るシミュレーションをすることができる.[5] 2. 開発環境[6] [7]

・OS: Microsoft Windows 7,8 または Microsoft Windows Embedded Standard 7

Kinect を動作させる Kinect for Windows SDK は Windows7 以前の OS には対応していない.32bit に も 64bit にも対応しているが,今回の研究では 64bit 版の Windows7 を使用する.

・CPU: デュアルコア 2.66GHz 以上(推奨)

詳しい処理は後述するが,Kinect はハードウェアですべての処理を行うわけではなく,PC 側でも 処理を行うのである程度のスペックを求められる.今回の研究ではデュアルコア 3.30GHz のプ ロセッサを用いる.

(5)

・USB 2.0 ポート

・グラフィック・ボード: DirectX 9.0 以上をサポート

インストール

・Kinect for Windows SDK(ソフトウェア開発キット)

ドライバとNUI(Natural User Interface)API を含む NUI ライブラリを提供する開発キットで, Kinect の各センサー(イメージ・ストリーム,深度ストリーム,オーディオ・ストリーム)から の情報をNUI API 経由でアプリケーションから利用することができる.NUI API はデバイスから のイメージ情報を受信するもので,NUI ライブラリは C++または.NET 言語から利用することが できる.

・Microsoft Visual C++ 2010 Express (32bit)

既述のNUI ライブラリに命令を出すための統合開発環境.Microsoft Visual C++ 2010 Express は 32bit のみであり,プロジェクトを作成する際 32bit/64bit でインクルードファイルやライブラリ のパスを通す時に指定するフォルダが異なるので注意する.

・OpenCV (ライブラリ)

画像認識・解析に関する機能のライブラリであり,Windows の C++に対応している.

2.1 Kinect for Windows SDK [8]

Kinect は、ハードウェアで全ての処理を行っているわけではない.環境構築の段階で,ある程度の CPU のスペックが必要であると既述したように,PC のソフトウェア内で行われる処理もある.

(6)

2.1.1 Kinect for Windows SDK のアーキテクチャ[8][9]

Kinect for Windows SDK ドライバの特徴は,スケルトントラッキングに初期ポーズが不要なこと, 他のドライバにはない音声処理 API がそろっていることである.最大 2 人までという制約がある が、スケルトントラックも速く、高速に動作する.

図-4 Kinect for Windows SDK の仕組み

2.1.1 NUI API

Kinect for Windows SDK に含まれる NUI API は以下のようなモーションキャプチャ系の機能を提 供する.

・ビデオカメラの像・深度画像の取得 ・ユーザー検知

・スケルトントラッキング ・ハードウェアの操作

(7)

2.1.2 Audio API

Windows コンポーネントに含まれる Audio API は以下のようなオーディオ機能を提供する. ・音源位置推定 ・ビームフォーミング…一定方向からの音声のみを認識する機能  (4 つのマイクアレイを搭載している Kinect ならではの機能) ・ストリームの保存 ・ノイズの除去 2.2 OpenCV OpenCV は、オープンソースのコンピュータビジョンライブラリである. 以下のような画像認識・解析に関する機能を提供する. ○画像処理  ・ヒストグラム  ・フィルタリング  ・特徴点検出  ・画像変換 ○物体追跡  ・オプティカルフロー ○パターン認識  ・物体検出 ○カメラキャリブレーション  ・三次元再構成 ○GUI  ・画像・ビデオの表示,読み込み,書き込み  ・図形、文字の描画  ・キー入力の受け付け ○機械学習  ・学習データの作成  ・学習データによる物体認識

(8)

3. 研究計画 以下の計画で研究を進める. 8 月 現在発生している,VC++のエラーを解決する 9 月 スケルトン(骨格)の認識・音声の取得 10 月 シミュレーションのための模範動画再生機能取得 11 月 動画録画機能取得 12 月 模範動画再生機能との比較を行うフィードバック機能取得 1 月 シミュレーションアプリの調整・テスト 2 月 シミュレーションアプリの調整・最終確認 3.1 役割分担  AR アプリケーションが広く普及するためには,用途によって様々に異なるユーザの要求に対 し最適な機能を備えている必要がある.例えば,仮想世界を眼前の光景に融合するアプリケー ションのユーザとしては,いつでもAR を利用することができる環境が整っており,手軽な操作 で実行可能であることが自然な要求である.また,Kinect を利用したアプリケーションのユーザ としては,直感的で思い通りに操作が可能であることと,これまでには実現できなかった効果を 生み出すことが自然な要求である.  そこで,より多くのユーザの要求に答えるためのAR アプリケーションを共同研究者(森岡) と協力して開発する.森岡はスマートフォン上で手軽にAR を実現するアプリの作成,筆者(太 田)はKinect を用いたシミュレーションアプリの作成を行う.AR は特殊な用途に利用されるこ とが多いので,どのような機能が確実にユーザの要求を満たすものであるのか,AR アプリケー ションの普及率が上がる(より身近な存在になる)ためには具体的にどのように手軽で,どのよ うな真新しい効果を生み出すことが出来るものであるべきかを検討する. 4

.

研究の現状  上記の開発環境を整え研究にあたる際,思いがけないコンピュータの環境が原因でエラーが発 生した.最初に発生したビルドエラー(トラブル1)は,現在はコンピュータの初期化によって 解決されたが,その後新たに発生したデバッグエラー(トラブル2)は本論文執筆中の現在でも 解決されていない.  この章で解説する内容は論旨とは直接的な関係はないが,開発環境の構築の段階で忘れてはな らない重要なことであると思われるので,研究を進めるにあたり有益な情報であると判断し記載 した. 4.1トラブル1(ビルドエラー)[10]  現在筆者が使用しているコンピュータは過去に研究室に所属していた先輩から引き継いだもの であるが,開発環境をインストールしてシステム環境変数を設定する段階で確認すべきことを 怠っていた.その後作成したプログラムでデバッグエラーが起きてしまうのは,環境変数で指定 されているパスに原因があるのではないかと考えた.

(9)

 OpenCV の導入後,環境変数で指定するパスとファイルは以下のとおりである.(32bitアプリ ケーション) C:\OpenCV2.3.1\build\x86\vc10\bin; C:\OpenCV2.3.1\build\common\tbb\ia32\vc10; 以下は,図-5 の各 dll ファイルが示す機能を表にしたものである. calib3d231 カメラキャリブレーション, 姿勢設定,ステレオ highgui 高レベルgui とメディア入出力 contrib231 顔認識アルゴリズム imgproc231 画像処理 core231 主要な機能(描画関数 等) legacy231 過去のバージョンの古い機能 features2d231 特徴検出とディスクリプタ抽出 ml231 機械学習 ffmpeg 音声・動画ファイルのフォー マットを変換 objdetect231 オブジェクト検出 flann231 クラスタリングと多次元空間探 索 ts231 トランスポート・ストリーム※

gpu231 GPU を利用する機能 video231 ビデオ解析 図-5  環境変数で指定するファイル

(10)

※トランスポート・ストリーム…MPEG(画像の中の動く部分だけを検出し,保存するデータを 圧縮する)方式を用いて,映像・音声・静止画・文字など様々な形式のデータをまとめて一つの 流れとして扱うことができるもの. irml 拡大縮小可能なメモリ割り当て タスクスケジューリング tbb 関数処理の並列化・高速化  このトラブルは,エラーメッセージでは”include ファイルを開けません”と表示されたが,環 境変数で新しく通したパスはinclude ファイルではないので問題はないと考えられる.  また,作業のプロセスが前後するが,このコンピュータは後に初期化する.そこで,初期化前 に環境変数で指定していたパスと,初期化後に環境変数で指定したパスを比較し,システム環境 変数の設定にトラブルの原因があるか否かを確認することができた.比較対象となる二つの表は 以下のとおりである. 初期化後の現在,環境変数で指定しているパス C:\OpenCV2.3.1\build\x86\vc10\bin; C:\OpenCV2.3.1\build\common\tbb\ia32\vc10;

C:\Program Files\Common Files\Microsoft Shared\Windows Live; C:\Program Files (x86)\Common Files\Microsoft Shared\Windows Live; %SystemRoot%\system32;

%SystemRoot%;

%SystemRoot%\System32\Wbem;

%SYSTEMROOT%\System32\WindowsPowerShell\v1.0\; C:\Program Files (x86)\Windows Live\Shared

初期化前に環境変数で指定していたパス C:\OpenCV2.3.1\build\x86\vc10\bin;

C:\OpenCV2.3.1\build\common\tbb\ia32\vc10;

C:\Program Files\Common Files\Microsoft Shared\Windows Live; C:\Program Files (x86)\Common Files\Microsoft Shared\Windows Live; %SystemRoot%\system32;

(11)

%SystemRoot%\System32\Wbem;

%SYSTEMROOT%\System32\WindowsPowerShell\v1.0\; C:\Program Files (x86)\Windows Live\Shared

C:\Program Files (x86)\Microsoft ASP.NET\ASP.NET Web Pages\v1.0\; C:\Program Files\Microsoft SQL Server\110\Tools\Binn\;

C:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\; C:\Program Files (x86)\Microsoft SQL Server\100\DTS\Binn\;  

上記の2 つを見比べると,初期化前に以前のユーザーが新しく環境変数で指定していたパスは以 下の4 つである.

C:\Program Files (x86)\Microsoft ASP.NET\ASP.NET Web Pages\v1.0\; C:\Program Files\Microsoft SQL Server\110\Tools\Binn\;

C:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\; C:\Program Files (x86)\Microsoft SQL Server\100\DTS\Binn\;

しかし,これらのファイルが環境変数で指定されていることがinclude ファイルを開くことがで きない直接的な理由であるとは考えられないので,環境変数にも問題は見られなかった. 問題は解決できない状況のまま,作業を中断してから多くの時間を要したため,この問題の解決 よりもKinect を実行させることが最優先であると判断し,原因の追究を中止してコンピュータを 初期化し,作業をもう一度始めからやり直した. 4.1.2 トラブル 2(デバッグエラー)  トラブル1 はコンピュータを初期化し,デフォルト設定に戻すことでプログラムを実行するこ とができたが,実際にKinect を接続し「RGB カメラから得られた画像データを表示するサンプ ルプログラム」→「距離カメラを用いてカメラから一定以上離れた所の画像が表示されない画像 データを表示するサンプルプログラム」→「深度カメラを用いたプレイヤーの認識を行うサンプ ルプログラム」を実行した後,「スケルトン認識を行うサンプルプログラム」を実行する段階で 以下のエラーが表示された.

(12)

”0xC0000005 ”というエラーコードは,メモリのアクセス違反を指す.プログラムが OS に よって確保されているメモリ部分にアクセスしようとすることで,他のプログラムも巻き込んで トラブルを起こしてしまうので,図-6 のようなエラーを表示してプログラムを強制終了する.  この初回エラーが発生してから,過去に成功した三つのサンプルプログラムのうち「RGB カ メラから得られた画像データを表示するサンプルプログラム」以外の二つのプログラムも図-6 と 同じエラーが表示されて実行出来なくなった.そこで,Windows タスクマネージャを表示しなが らプログラムのビルドを行い,メモリに負荷がかかることでエラーが表示されることを確認しよ うと試みたが,図-7 のようにメモリに負荷がかかってはいるものの(使用中物理メモリの割合: 73%),メモリのアクセス違反が起こるほどの負荷はかかっていないと考えられる.  コンピュータが実装しているメモリ(RAM)は 4GB だが,「ハードウェア予約済み」のメモリ 領域を差し引く必要があること,2.開発環境で既述したように Kinect の開発には最低でも 2GB 以 上のRAM が必要であること,さらには,今回問題となっている「スケルトン認識を行うサンプ ルプログラム」は処理量の多いプログラムであり,その処理量が追いつかなくなることで骨格情 報の取得に失敗するケースが他の開発者の中でも起きていることから,ハードウェアの要領は余 裕を持たせておくことが推奨されている[7]ことを考慮し,8GB のメモリを新たに取り付けた. しかし,結果は変わらず,図-6 と同じ結果が表示された.タスクマネージャで確認すると,使用 中の物理メモリの割合は減っていたことから,メモリの負荷によるエラーである可能性はないと 考えられる.  

 日本マイクロソフト株式会社が発表した日本語版”Microsoft Kinect for Windows SDK – v1.0 リ リースノート”の「既知の問題」として,以下のような文章を公開していた.

『SkeletalViewer サンプル (C++/Direct2D+GDI) は、CPU に負荷がかかると骨格の描画に失敗 することがあります。利用可能なフレームの通知を受けた場合のベストプラクティスは、ペン ディングになっているすべてのストリームで新しいフレームがないかどうかをチェックすること です。

C++ コードがアプリケーションのライフタイムを通じて NuiInitializa/NuiShutdown を複数回

(13)

実行する場合、これらの呼び出しの実行前に、SetDeviceStatusCallback を一回呼び出すように してください。』[11]  また,スケルトン認識を行う際,カメラの解像度は 640×840 としていたが,これ以上解像度 を下げて実行すると, ”スレッド 'Win32 スレッド' (0xecc) はコード 0 (0x0) で終了しました。” という今までとは異なる結果が得られた(プログラムは実行されない).新たに考慮に入れる必 要があるが,これはエラー表示ではないため,うまく原因を把握できずにいる状態である. 図-7   Windows タスクマネージャー(実装メモリ 4GB )

(14)

5.考察 予定していた作業は既述のエラーによって全くと言っていいほど進んでいない状態である.一刻 も早く原因の究明にあたり,当初予定していたシミュレーションアプリの開発に取り組まなけれ ばならない.優先して進めるべき学習は,5.1.2 トラブル 2(デバッグエラー)で触れた, SetDeviceStatusCallback であると思われるが,情報が少ないために理解を深めることが出来な い状況にある.また,解像度を変更するとデバッグの結果が変わることなど,把握が出来ていな い箇所が多く存在するので,一つ一つ解決にあたりたい.更に,サンプルプログラムの一部を完 全に把握できていないので,基礎から丁寧に学習を進める必要がある.(7 章でスケルトン認識 のプログラムにおいて現在把握できている部分を解説しているソースコードを記載した.)

(15)

6. 参考文献

[1]やってみよう!Kinect アプリ開発コンテンツ一覧

http://kinection.jp/post/100

[2]Kinect for Windows で機器を作るヒント──ジェスチャも音声も認識できる

http://www.kumikomi.net/archives/2012/05/ep05knc1.php?page=2 [3]手術室向け非接触型画像操作システム Opect(オペクト) http://www.nichiigakkan.co.jp/service/medical/category/hospital/opect.html [4]Kinect の特徴を生かしたインタラクティブ・リハビリシステム http://www.systemfriend.co.jp/node/434#.UgED3JLxreE [5]これまでとは違う!AR を本気でビジネスに生かす http://itpro.nikkeibp.co.jp/article/COLUMN/20130614/485301/?ST=systeml

[6]中村薫,斎藤俊太,宮城英人:Kinect for Windows SDK プログラミング C++編,P.2-3 [7]連載:Kinect for Windows SDK(ベータ版)開発入門(2/3)

http://www.atmarkit.co.jp/ait/articles/1107/28/news137_2.html

[8]連載:Kinect for Windows SDK(ベータ版)開発入門(1/3)

http://www.atmarkit.co.jp/ait/articles/1107/28/news137.html

[9]西林孝,小野憲史:キネクト ハッカーズマニュアル,P.92-95,P.100-101,P.116-117 [10]OpenCV 2.2 C++ リファレンス

http://opencv.jp/opencv-2svn/cpp/index.html

[11] Windows Multimedia Hacks

http://blogs.msdn.com/b/windows_multimedia_jp/archive/2012/02/28/microsoft-kinect-for-windows-sdk-v1-0.aspx

(16)

7.ソースコード(スケルトンの認識) #include <iostream> #include <sstream> //NuiApi.h の前に Windows.h をインクルードする #include <Windows.h> #include <NuiApi.h> #include <opencv2/opencv.hpp> //───────────現在,勉強中─────────

#define ERROR_CHECK( ret ) \ if ( ret != S_OK ){ \ std::stringstream ss; \

ss << "failed " #ret " " << std::hex << ret << std::endl; \ throw std::runtime_error( ss.str().c_str() ); \ }

const NUI_IMAGE_RESOLUTION CAMERA_RESOLUTION = NUI_IMAGE_RESOLUTION_640x480; class KinectSample { private: INuiSensor* kinect; //InuiSensor *kinect…Kinect センサのハードウェアアクセス機能を提供するインターフェース HANDLE imageStreamHandle; //RGB カメラのストリームデータを扱うためのハンドル HANDLE depthStreamHandle; //距離カメラのストリームデータを扱うためのハンドル HANDLE streamEvent; //RGB カメラおよび距離カメラのフレーム更新イベントを待つ ためのイベントハンドル DWORD width; //RGB カメラの表示解像度(横) DWORD height;//RGB カメラの表示解像度(縦)

(17)

public: KinectSample() { } ~KinectSample() { //終了処理 if( kinect != 0 ){ kinect->NuiShutdown(); kinect->Release(); } } void initialize() //初期化 { createInstance(); //Kinect の設定を初期化する ERROR_CHECK( kinect->NuiInitialize(    NUI_INITIALIZE_FLAG_USES_COLOR | //RGB カメラを使用する    NUI_INITIALIZE_FLAG_USES_DEPTH_AND_PLAYER_INDEX |       //距離カメラとプレイヤー認識を使用する    NUI_INITIALIZE_FLAG_USES_SKELETON)); //スケルトン認識を使用する //RGB カメラを初期化する ERROR_CHECK( kinect->NuiImageStreamOpen( //NuiImageStreamOpen…RGB カメラ、距離カメラのストリームを開く       NUI_IMAGE_TYPE_COLOR,  //RGB カメラストリーム            CAMERA_RESOLUTION, // NUI_IMAGE_RESOLUTION_640x480 …RGB カメラがサポートする解像度          0, 2, 0, &imageStreamHandle )); //動作フラグ、フレーム数、 次のフレームを待つためのイベントハンドル、開いたストリームのハンドル

(18)

//距離カメラを初期化する        //距離カメラとプレイヤー認識を初期化する ERROR_CHECK( kinect->NuiImageStreamOpen(      NUI_IMAGE_TYPE_DEPTH_AND_PLAYER_INDEX,          CAMERA_RESOLUTION,        0, 2, 0, &depthStreamHandle ));        //スケルトンを初期化する ERROR_CHECK( kinect->NuiSkeletonTrackingEnable( 0, 0) ); //スケルトントラッキングを有効にする // (0, 0) …(次のフレームを待つためのハンドル、動作フラグ) //フレーム更新イベントのハンドルを作成する

streamEvent = ::CreateEvent( 0, TRUE, FALSE, 0 );

//CreateEvent …イベントオブジェクトを生成する //(0, TRUE, FALSE, 0)…(① セキュリティ記述子,②リセットのタイプ,③初期状態,④イベン トオブジェクトの名前)        //①…取得したハンドルを継承できるかどうか決定する.1 個の構造体へのポインタを指定 //②…TRUE を指定しているので,手動リセットオブジェクト(待機関数に引っかかる)作成 //③…イベントオブジェクトの初期状態を指定する.FALSE を指定しているので非シグナル状態 //④…イベントオブジェクトの名前

ERROR_CHECK( kinect->NuiSetFrameEndEvent( streamEvent, 0 ) );

//NuiSetFrameEndEvent…RGB カメラ、距離カメラ、スケルトンのフレームを同期して更新するた めのイベントを設定する //(streamEvent, 0)…(次のフレームを待つためのイベントハンドル、動作フラグ)

       //指定した解像度の画面サイズを取得する

::NuiImageResolutionToSize(CAMERA_RESOLUTION, width, height ); }

//フレームデータの更新、画像の表示、キーボード入力処理

void run() {

(19)

cv::Mat image; //

//メインループ

while (1) {

//データの更新を待つ

DWORD ret = ::WaitForSingleObject( streamEvent, INFINITE );

    //WaitForSingleObject…指定したオブジェクトがシグナル状態になるか、タイムアウト 時間が経過するまで待機する関数 //(streamEvent, INFINITE)…(オブジェクト,タイムアウト時間)タイムアウト時間は INFINITE を指定しているのでオブジェクトがシグナル状態になるまで待機 ::ResetEvent( streamEvent ); //次のイベントに備えてリセット //───── 新しいフレームの準備完了───── drawRgbImage( image ); //RGB カメラの処理 drawDepthImage( image ); //距離カメラの処理 drawSkeleton( image ); //スケルトン認識の処理 //画像を表示する

cv::imshow( "RGBCamera", image );

//終了のためのキー入力チェック兼,表示のためのウェイト

int key = cv::waitKey( 10 ); if( key == 'q'){ break; } } } private: //インスタンス作成 void createInstance() { //接続されている kinect の数を取得する int count = 0;

(20)

       //接続数が 0 であれば Kinect の接続を促す

if ( count == 0){

throw std::runtime_error("Kinect を接続してください"); }

//最初の Kinect のインスタンスを作成する

ERROR_CHECK( ::NuiCreateSensorByIndex( 0, &kinect ) );

//NuiCreateSensorByIndex … 指定された(INuiSensor)インスタンスを生成する //(0, &kinect)…(インデックス,INuiSensor 型のポインタ)  //インデックスは接続数に対するもので、1 台であれば 0,2 台であれば 0,1 となる.

//kinect の状態を取得する

HRESULT status = kinect->NuiStatus(); //InuiSensor::NuiStatus()で接続状態を確認 //接続状態は HRESULT 型で表され、使用可能であれば S_OK を返す if ( status != S_OK){ throw std::runtime_error("kinect が利用可能ではありません"); } } //更新されたフレームデータの取得と処理

void drawRgbImage( cv::Mat& image ) {

//RGB カメラのフレームデータを取得する

NUI_IMAGE_FRAME imageFrame = { 0 };  

//RGB カメラの次フレームを取得する

ERROR_CHECK( kinect->NuiImageStreamGetNextFrame( imageStreamHandle, 0, &imageFrame) );

//NuiImageStreamGetNextFrame … RGB カメラの次フレームを取得する //(imageStreamHandle, 0, &imageFrame)…(ストリームのハンドル,フレーム取得までの待ち時間, フレームデータを格納する NUI_IMAGE_FRAME 構造体へのポインタ)

(21)

NUI_LOCKED_RECT colorData;         //フレームの画像データを取得する imageFrame.pFrameTexture->LockRect( 0, &colorData, 0, 0 ); // (0, &colorData, 0, 0 ) … (未使用(0 を指定), フレームのデータを保持するNUI_LOCKED_RECT 構造体へのポインタ,未使用,未使用) //画像データをコピーする

image = cv::Mat( height, width, CV_8UC4, colorData.pBits ); //OpenCV に渡す

//(高さ,幅,CV_8UC4,colorData.pBits )

//画像のサイズはあらかじめ取得した幅と高さ

//CV_8UC4 … unsigned char [4] (0 ~ 255) Kinect から得られる画像のフォーマットは 1 ピクセルあ

たり8 ビットの R,G,B データと無効値の 4 つ、32 ビットのデータとなるので CV_8UC4 を指定

する

//colorData.pBits … *pBits は画像データへのポインタ.RGB の並びは Kinect SDK,OpenCV とも

にBGR データであるため,そのままビットデータをコピーすることで表示が可能である.

//フレームデータを解放する

ERROR_CHECK( kinect->NuiImageStreamReleaseFrame( imageStreamHandle, &imageFrame ) );

//( imageStreamHandle, &imageFrame ) … (ストリームのハンドル,

      解放するフレームのNUI_IMAGE_FRAME 構造体へのポインタ)

}

//距離カメラから得られたデータの表示を行う.

void drawDepthImage ( cv::Mat& image ) {

//距離カメラのフレームデータを取得する

NUI_IMAGE_FRAME depthFrame = { 0 };        // 距離カメラの次フレームを取得する

ERROR_CHECK( kinect->NuiImageStreamGetNextFrame( depthStreamHandle, 0,           &depthFrame ) );

//NuiImageStreamGetNextFrame … 距離カメラの次フレームを取得する //(depthStreamHandle, 0, &depthFrame)…(ストリームのハンドル,フレーム取得までの待ち時間, フレームデータを格納する NUI_IMAGE_FRAME 構造体へのポインタ)

(22)

      //距離データを取得する NUI_LOCKED_RECT depthData = { 0 }; depthFrame.pFrameTexture->LockRect( 0, &depthData, 0, 0 ); // (0, &depthData, 0, 0 ) … (未使用(0 を指定), フレームのデータを保持するNUI_LOCKED_RECT 構造体へのポインタ,未使用,未使用) //───────────現在,勉強中─────────

USHORT* depth = (USHORT*)depthData.pBits; //USHORT…符号なし 16bit 整数

for ( unsigned int i = 0; i < (depthData.size / sizeof(USHORT)); ++i){ USHORT distance = ::NuiDepthPixelToDepth( depth[i] );

// NuiDepthPixelToDepth … 距離カメラのデータから、距離データを取得する // depth[i] … 距離カメラから渡されたデータ // 1 ピクセル 16bit のうち実際の距離データは 13bit のみで,下位 3bit はプレイヤーの認識に使用

      USHORT player = ::NuiDepthPixelToPlayerIndex( depth[i]);

//::NuiDepthPixelToPlayerIndex … 距離データからプレイヤー ID を取得する

LONG depthX = i % width; LONG depthY = i / width; LONG colorX = 0; LONG colorY = 0; //距離カメラの座標を、RGB カメラの座標に変換する kinect->NuiImageGetColorPixelCoordinatesFromDepthPixelAtResolution( CAMERA_RESOLUTION, //RGB カメラの解像度 CAMERA_RESOLUTION, //距離カメラの解像度 0,       //視点 depthX, // 距離カメラの X 座標 depthY, // 距離カメラの Y 座標 depth[i],         // 距離データ &colorX, // 指定した座標に対応した RGB カメラの X 座標 &colorY // 指定した座標に対応した RGB カメラの Y 座標

(23)

);

//変換された座標を利用して、表示画像のピクセルデータを取得する

int index = ((colorY * width) + colorX) * 4; UCHAR* data = &image.data[index];

//プレイヤー if( player != 0){ data[0] = 0; data[1] = 0; data[2] = 255; }//プレイヤーを検出したら,色付けすることで認識されたことを示す else{ //一定以上の距離を描画しない if( distance >= 1000 ){ // 取得された距離 distance と 1000 を比較してそれより小さい(近い)範囲のみ RGB 画像を描画 data[0] = 255; data[1] = 255; data[2] = 255; } } } //フレームデータを解放する ERROR_CHECK( kinect->NuiImageStreamReleaseFrame(depthStreamHandle,            &depthFrame ) ); // ( depthStreamHandle, &depthFrame ) … (ストリームのハンドル,       解放するフレームのNUI_IMAGE_FRAME 構造体へのポインタ) } //認識されたスケルトンのジョイント位置または,プレイヤーの位置を表示する.

void drawSkeleton( cv::Mat& image ) {

(24)

NUI_SKELETON_FRAME skeletonFrame = { 0 }; // スケルトン・トラッキングの次のフレームを取得する        kinect->NuiSkeletonGetNextFrame( 0, &skeletonFrame); //(0, &skeletonFrame ) … (フレーム取得までの待ち時間, フレームデータを格納するNUI_SKELETON_FRAME 構造体へのポインタ) //───── 認識されたスケルトンのジョイント位置またはプレイヤーの位置を表示 ────────

for ( int i = 0 ; i < NUI_SKELETON_COUNT; ++i){

//NUI_SKELETON_COUNT … プレイヤーの認識(追跡)上限

NUI_SKELETON_DATA& skeletonData = skeletonFrame.SkeletonData[i];

//NUI_SKELETON_FRAME::SkeletonData … プレーヤーごとのスケルトンデータ

//スケルトンが追跡されている(スケルトンのトラッキングをしている)状態にある場合は

if( skeletonData.eTrackingState == NUI_SKELETON_TRACKED){

// NUI_SKELETON_DATA::eTrackingState … スケルトンの認識(追跡)状態を取得 // NUI_SKELETON_TRACKED … スケルトンのトラッキングをしている //ジョイントが追跡されていない状態以外(追跡、推定)の場合 //(スケルトンのジョイントの数が追跡しきっていない) for(int j = 0; j < NUI_SKELETON_POSITION_COUNT; ++j){ // NUI_SKELETON_POSITION_COUNT … ジョイントの数 //スケルトンのジョイントが,認識(追跡)状態にある場合 if (skeletonData.eSkeletonPositionTrackingState[j] != NUI_SKELETON_POSITION_NOT_TRACKED){ // NUI_SKELETON_DATA_eSkeletonPositionTrackingState … ジョイントの認識(追跡)状態 // NUI_SKELETON_POSITION_NOT_TRACKED … ジョイントはトラッキングされていない //ジョイントの座標を描画する

drawJoint( image, skeletonData.SkeletonPositions[j]);

// NUI_SKELETON_DATA_SkeletonPositions … 座標を取得

} }

(25)

//プレイヤー及びスケルトンの位置のみ追跡している(ジョイントは認識していない)状態

else if (skeletonData.eTrackingState == NUI_SKELETON_POSITION_ONLY){

//NUI_SKELETON_POSITIONS_ONLY … スケルトンの位置のみをトラッキングしている

//プレイヤーの位置を描画する

drawJoint( image, skeletonData.Position );

// NUI_SKELETON_DATA::Position … スケルトンの位置

} }

}

// ジョイントを描画する

void drawJoint( cv::Mat& image, Vector4 position )

// Vector4 … 4 つの要素を持つベクトルを定義

{

//スケルトンの座標(3 次元)を,距離カメラの座標(2 次元)に変換する

FLOAT depthX = 0, depthY = 0; ::NuiTransformSkeletonToDepthImage( // NuiTransformSkeletonToDepthImage() … スケルトンの座標(3 次元)を,距離カメラの座標 (2 次元)に変換する           position, // 元になるスケルトンの座標(3 次元) &depthX, // 距離データの X 座標を格納する,LONG へのポインタ &depthY, // 距離データの Y 座標を格納する,LONG へのポインタ CAMERA_RESOLUTION //距離カメラの解像度 ); LONG colorX = 0; LONG colorY = 0; kinect->NuiImageGetColorPixelCoordinatesFromDepthPixelAtResolution( // InuiSensor :: NuiImageGetColorPixelCoordinatesFromDepthPixelAtResolution … 距離カメラの座標 を RGB カメラの座標に変換する CAMERA_RESOLUTION, //RGB カメラの解像度

(26)

0, //視点 (LONG)depthX, //距離カメラの X 座標 (LONG)depthY, //距離カメラの Y 座標 0, //距離データ &colorX, //指定した座標に対応した RGB カメラの X 座標 &colorY //指定した座標に対応した RGB カメラの Y 座標 ); // 変換された RGB 座標を中心にして円を描画することで,ジョイントの座標を表示する

cv::circle( image, cv::Point( colorX, colorY), 10, cv::Scalar( 0, 255, 0), 5);

//(画像,円の中心座標,半径,色,太さ) } }; void main() //現在,勉強中 { try{ KinectSample kinect; kinect.initialize(); kinect.run(); } catch ( std::exception& ex ){

std::cout << ex.what() << std::endl; }

図 -5  環境変数で指定するファイル

参照

関連したドキュメント

機械物理研究室では,光などの自然現象を 活用した高速・知的情報処理の創成を目指 した研究に取り組んでいます。応用物理学 会の「光

全国の 研究者情報 各大学の.

北陸 3 県の実験動物研究者,技術者,実験動物取り扱い企業の情報交換の場として年 2〜3 回開

プログラムに参加したどの生徒も週末になると大

これは基礎論的研究に端を発しつつ、計算機科学寄りの論理学の中で発展してきたもので ある。広義の構成主義者は、哲学思想や基礎論的な立場に縛られず、それどころかいわゆ

情報理工学研究科 情報・通信工学専攻. 2012/7/12

昨年度2科目で始まった自然科学研究科博士前期課程のMOT

健学科の基礎を築いた。医療短大部の4年制 大学への昇格は文部省の方針により,医学部