前回 Intel Perceptual Computing SDK のユーザーズマニュアルまとめになりつつありました。
もういっそ今回の話は Intel CREATIVEカメラの使い方ということで進めます。
このセンサとライブラリなら自分の夢が実現できるかもしれません。
最優先で取り組みたい!
セッションがアクティブな間だけ処理が可能
セッションを介してモジュールとI/Oを列挙(グループ、サブグループにフラグを立ててフィルタリング可能)
モジュール単位でデバイスを列挙可能(フィルタリング例は確認していない)
デバイスから出ているストリームを列挙可能(フィルタリング例は確認していない)
列挙したディスクリプタからはどういったモジュールなのか、デバイスなのか、ストリームなのか判別することが可能。
それぞれ情報列挙だけでなく、インスタンスを作成して、インスタンスを介してプロパティの設定・取得が可能。
ここまで使用例を示している。
環境で利用できるカメラやマイクなどのセンサがわかる、それを触れるということ。
これができれば後はそのセンサからどうやって情報を取得するのか…になるわけです。
ここまでは前回の段階で確認出来ている。
doc/CHM フォルダの sdkhelp.chm, sdkmanuals.chm ファイル
これら英語のドキュメントに目を通した人なら、そこに書いてあることをそのまま載せているだけじゃないかと
そう思われると思いますが、そのとおりです。
私自身もわざわざ訳文を作る必要はないですが、後々忘れた時に
日本語でドキュメントあると確認がはやいのでここにメモとして書いていきます。
画像データとオーディオデータの取得について確認します。
まずは画像データについてですが、アクセスしやすいようにオブジェクトを用意しています。
PXC[M]Image インスタンスを介して、カメラ画像の byte 配列にアクセスできます。
(前回この byte 配列に Windows の API から直接アクセスできずにイライラしていましたが
このマニュアルは第一声が byte 配列にはこうやってアクセスすると示してくれます。
うれしいと思いますが、これが普通です。)
PXC[M]Image の扱いは次のとおり、作成には PXCMAccelerator のインスタンスが必要とのこと。
作った PXC[M]Image のデータにアクセスするには AcquireAccess でロックして
ReleaseAccess でロック解除しろとのこと。
data のメンバ planes, pitches から生データが取れるそうです。
planes, pitches のことは良くわかりませんが data である ImageData は次の関数を公開しています。
ToBitmap (C#), ToByteArray (C#), ToFloatArray (C#), ToShortArray (C#), ToWriteableBitmap (C#)
引数に planes のインデックスを渡すそうです。0 がカラーイメージデータで
情報がぎっしり詰まったバッファであるという記述があります。
この表現は意味不明です。0~3 までインデックスが取れるそうですが、どれが何であるかという記述はなし。
普通は 0 が意図した内容と思うのですが…どうなんでしょう?もう少し読み進めてみましょう。
Bitmap から PXCMImage を作るコードを次に示します。
だいぶ情報が揃ってきました。
planes[0] にはビットマップ内の最初のピクセルデータのアドレスが入ります。
pitches[0] には、ピクセル情報のストライド[byte]が入ります。
作り方はわかりました、次にデバイスの画像ストリームから取得する場合を調べます。
まずここまでに確認した PXCMImage が for 文や while 文や、イベントハンドラなどでフレーム取得ごとに
入手できれば良いのです。
それには Util[M]Pipeline, Util[M]Capture, PXC[M]Capture を使う3つの方法が示されています。
Util[M]Pipeline はセンサデバイスを選ぶことが出来ない点で汎用性が低いのですが、記述が簡単です。
Util[M]Capture はプロパティをいじれますが、やはりデバイスやストリームの選択に不自由するでしょう。
PXC[M]Capture を使えば、デバイスを扱う上で困ることは無いと思いますが、記述が煩雑です。
覚えてしまえば PXC[M]Capture 一択ですよねと、そんな雰囲気です。
Util[M]Pipeline を使った例1を次に示します。for 文で回すやり方です。
一応条件を渡して stream を選択していることになります。
Util[M]Pipeline を使った例2を次に示します。
LoopFrames でループして、継承クラスのオーバーライドイベントハンドラで処理する例です。
こちらも条件を渡して stream を選択していることになります。
PXCMCapture を使ってストリームを取得して、for 文を回して処理する例を次に示します。
これも条件を渡して stream を選択していることになります。
PXCMCapture を使った場合の例を次に示します。
モジュール、デバイス、ストリーム、プロファイルと階層ごとに for 文を回しています。
環境に接続されている全てのセンサデバイスを検出することが出来ます。
その中から一つ選んで、ReadStreamAsync を呼び出します。
この Async と付いている関数は、非同期処理を行なうものであり、同期させたい場合は受け取った
SyncPoint を Synchronize() することで、フレーム取得が完了するまでブロックできます。
デバイスの検出、プロパティの編集、while 文などで、Frame ごとの生データ PXCMImage が取得できることを確認しました。
この情報をどうするかはユーザーに任されます。
センサはカラーカメラと深度カメラが付いていますので、お互いズレなく一緒に画像を取得したい。
いや、別々にそれぞれのフレームレートで取得したい。
みたいな要望に応えられる機構が用意されています。
先に示した
Util[M]Pipeline はセンサデバイスを選ぶことが出来ない点で汎用性が低いのですが、記述が簡単です。
Util[M]Capture はプロパティをいじれますが、やはりデバイスやストリームの選択に不自由するでしょう。
PXC[M]Capture を使えば、デバイスを扱う上で困ることは無いと思いますが、記述が煩雑です。
という3つの方法で今回も例を示します。
Util[M]Pipeline を使う方法。
Enable を追加するだけです。同期して取得可能です。
Util[M]Capture を使う方法は2つ例を示します。
最初に示すのが同期して取得する方法、次に示すのが非同期で取得する方法です。
解説がほしいと思ったのは sts=sps[i].Synchronize(0); の行ですね。
準備中ならば for 文を continue しているところがポイントです。
ほかはスラスラ読めると思います。
最後に PXC[M]Capture を使った方法を示そうと思いますが、実はデバイスを列挙する部分が違うだけで
上で示した Util[M]Capture とやる内容は変わりません。
特に参考コードを示す必要はないので示しません。
同期ポイントをそれぞれストリームから取って、うまいこと SynchronizeEx と for 文で処理して下さい。
ここまで理解して読めていれば迷うことはないはずです。
ここまで画像データの取得についてでしたが、ここではオーディオデータの取得方法について示します。
また、既視感があるのですが
Util[M]Pipeline はセンサデバイスを選ぶことが出来ない点で汎用性が低いのですが、記述が簡単です。
Util[M]Capture はプロパティをいじれますが、やはりデバイスやストリームの選択に不自由するでしょう。
PXC[M]Capture を使えば、デバイスを扱う上で困ることは無いと思いますが、記述が煩雑です。
ということです。
Util[M]Pipeline で for 文を使った例です。
画像取得を読んだ今、EnableAudio, QueryAudio の呼び出しの違いがあるという認識のみで良いと思います。
PXCMAudio オブジェクトの使い方は今のところ不明ですが、おいおい学んでいこうと思います。
私は音声解析の経験はありませんが、こんなFrameごとにぶつ切りして処理するものなのでしょうか?
Util[M]Pipeline でイベントハンドラを使った例です。
センサが Audio フレームを取得するたび PXCMAudio がほしい、そんなときはこれが一番シンプルで良いですね。
Util[M]Capture を使った例を示します。
リクエストとなるスペックを指定し、LocateStream をすると目的の stream を探しだしてくれます。
あとは for 文を回して、同期ポイントの同期後に PXCMAudio を処理するループを作ります。
最後に PXC[M]Capture を使った Audio 取得例を示します。
画像の時と同じでモジュール、デバイス、ストリームを列挙し、ディスクリプタから何なのか確認します。
stream.ReadStreamAsync で PXCMAudio を取得、同期ポイントを同期してから処理します。
ファイルへ録画、ファイルから再生をサポートしています。
Util[M]Pipeline or Util[M]Capture を使って録画、再生が可能です。
Util[M]Pipeline はコンストラクタにファイルパスとレコードフラグを渡せます。
ファイルパスに保存先ファイルパス、レコードフラグを立てることでここまで示したフレーム取得と同時に
ファイルへの録画/録音を行います。
逆にレコードフラグを下ろすと、指定したファイルパスの情報を再生します。
不正なパスや、パスに null を渡した場合はここまで示したとおり、デバイスからの生データを取得します。
Util[M]Capture 自体には録画、録音、再生機能はありませんが、これを継承した Util[M]CaptureFile クラスにはあります。
コンストラクタでファイルパスとレコードフラグを指定することができます。
仕様は上記で示した Util[M]Pipeline と変わりません。
画像座標系は左上を基点に横方向にX軸、縦方向にY軸が伸びる。
ワールド座標系はカメラ位置を原点に左手座標系でカメラ奥行き方向にY軸、カメラ上方へZ軸、カメラ左方向へX軸が伸びる。
ワールド座標系の単位はメートル[m]
(DirectX で表示する私としては左手座標系はうれしい!)
深度画像の画像座標と深度値を利用してこのワールド座標系にするには PXC[M]Projection クラスを使います。
インスタンスを取得する方法は次のとおり
作成にはデバイスインスタンスが必要です。
ということは Util[M]Pipeline or Util[M]Capture ではデバイス検索を行わないので
ワールド座標系の点群を手に入れるためには PXC[M]Capture を使うほかありません。
PXC[M]Projection のインタフェースには次のものがあります。
距離点群にカラーカメラの画像をUVマッピングするためのインタフェースもあります。
ここの記述で見かけましたが planes のインデックス 0~3 のうち 2 はカラーカメラの画像座標を表しているそうです。
UVマッピングの例は次のとおり。
格納されている 32bit float 値は 0~1 の正規化された値となっています。
センサから生データを取得する方法を示しました。
フレームごとに Image, Audio が手に入るコードを確認しています。
次回はこの Image, Audio をどのように扱うと顔認識や音声認識ができるか示します。
お楽しみに!
2014/04/20 初記。
2014/04/27 更新。