自習室

こもります

Kinect, OpenCV, openFrameworks のカラー画像を相互に変換する

はじめに

以前の記事で KinectColorFrameReader から得た画像を ofImage 形式に変換して描画したりしましたが、いろいろ調べてみると、Kinect の画像形式から直接 ofImage に変換している例は意外と少ないようでした。そりゃまぁカラー画像をそのまま取得するだけだったらわざわざKinect使わんわい、という話だと思います。

それで、OpenCV も一緒に利用するケースを考えてみました。

f:id:AMANE:20150209231053p:plain

この三者間を画像データが行き来出来れば、柔軟にプログラムが出来そうです。

oF 内で OpenCV を利用する方法について

先日の記事ではoFでKinect for Windows SDK 2.0 を使う手法について調査検討しましたが、OpenCVについても同様に調査します。

大まかには、以下の方法があると思います。

  • 公式の ofxOpenCV を使う
  • kylemcdonald/ofxCv を使う
  • OpenCV を直接叩く
公式の ofxOpenCV を使う

OpenCVのバージョンは2.3.1です。ofxCvColorimage など oF での編集や描画がしやすいようアレンジされた画像クラスが利用できるのは便利です。公式のアドオンですが、IplImageを使っている箇所があったりするあたりはイケてません。そしてちょっと古い。

kylemcdonald/ofxCv を使う

内部で ofxOpenCV のアドレスを見ているので、利用しているのは ofxOpenCV と同様に 2.3.1 です。toCv() toOf() という多目的の関数があり、以下の様な変換が可能です。これは非常に便利です。変換可能な組を一部抜粋します。

- ofVec2(3)f --- Point2(3)f
- ofImage --- cv::Mat
- ofRectangle --- cv::Rect

詳細はコードをご参考 ofxCv/Utilities.h at master · kylemcdonald/ofxCv · GitHub

OpenCVはちょっと古いのですが、一方でコード中で ofDraw** という openFrameworks 0.9 系で採用される予定の記述があったりもし、いくつかのサンプルがビルドできませんでした。これの修正も結構大変そうです。

OpenCV を直接叩く

ofxAddons では無いので導入は若干面倒ですが、最新の機能を全部使える様になります。ただし、画像のデータなど、自分で変換する必要があります。

どうするか

ofxCv が素直に使えれば良かったのですが、先述の通りの問題があったりするのが玉に瑕で、Kinect for Windows SDK 2.0 を直接叩くのと同様の理屈で OpenCV も直接使えば良いじゃん、という結論になりました。OpenCV の生コードを書くのが何だかんだ楽です。

ところで、ofxCv はその目標に以下の様な物を掲げています。

Provide clean implementations of all functions in order to provide a stepping stone to direct OpenCV use.

と言う風に素のOpenCVも書けるような仕様になっているらしいので、ちゃんと ofxCv がまとまり oF も 0.9 に上がった暁には、 ofxCv を利用するのも良いかもしれません。

環境

openFrameworksv0.8.4 を Visual Studio Community 2013 で使う方法については、先日の記事をご参照ください

また、Visual StudioOpenCV を用いて開発する方法については、下記ブログなどをご参照ください

完成品はあげてあります

解説

ウィンドウが複数開いて大量に絵が出てきますが、下図の様な変換を行っています。

f:id:AMANE:20150209231104p:plain

以下ポイントだけ説明いたします ofImage と cv::Mat の相互変換については、先述の Kyle先生の ofxCv から toCv toOf 関数の実装を参考にさせていただいております。

ofImage -> cv::Mat

cv::Matコンストラクタに、配列の中身になる実データを指定出来るものがあるので、ofImageから実データを引っこ抜いて利用します。

// ofImage ofColor; ... ofVideoGrabber からデータを引っこ抜いたモノ
ofColor.allocate(CAM_WIDTH, CAM_HEIGHT, OF_IMAGE_COLOR);
cv::Mat cvColor = cv::Mat(CAM_HEIGHT, CAM_WIDTH, CV_8UC3, ofColor.getPixels());

cv::Mat のドキュメントによると

data – Pointer to the user data. Matrix constructors that take data and step parameters do not allocate matrix data. Instead, they just initialize the matrix header that points to the specified data, which means that no data is copied. This operation is very efficient and can be used to process external data using OpenCV functions. The external data is not automatically deallocated, so you should take care of it.

ということで、cv::Mat は実際は ofImage の確保しているデータを直接参照します。メモリの無駄がない、と言うことです。

また、ofImage は標準で RGB 配列ですが、 OpenCV では BGR 配列が標準ですので、変換が必要です

// #include <opencv2/imgproc/imgproc.hpp>
cvtColor(cvColor, cvColor, CV_RGB2BGR);

cv::Mat -> ofImage

// ofImage ofCropped;
ofCropped.allocate(CROPPED_WIDTH, CROPPED_HEIGHT, OF_IMAGE_COLOR); 
ofCropped.setFromPixels(cvCropped.ptr(), cvCropped.cols, cvCropped.rows, OF_IMAGE_COLOR, false);

cv 側でROIを決めてクロップした画像の生データ、のポインタを教えて sestFromPixels 関数で ofImage を作ることが出来ます。 四つ目の引数を false とすることで、BGR配列のデータでも直接 ofImage にRGB配列で突っ込むことが出来ます。

(Kinect) ColorFrame -> cv::Mat

// unsigned char* bufForColorFromKinect;
int nBufferSize = KINECT_CAM_WIDTH * KINECT_CAM_HEIGHT * 4;
bufForColorFromKinect = new unsigned char[nBufferSize];
hr = colorFrame->CopyConvertedFrameDataToArray(nBufferSize, bufForColorFromKinect, ColorImageFormat_Bgra);
cv::Mat cvColorFromK = cv::Mat(KINECT_CAM_HEIGHT, KINECT_CAM_WIDTH, CV_8UC4, bufForColorFromKinect);

Kinect画像の生データをバッファにいったんコピーして、それを使って先ほどと同様に cv::Mat() を作成します。 CopyCOnvertedFrameDataToArray() 関数で、ターゲットとなるフォーマットを指定するのがポイントです。cv::Mat のアルファ付きカラー画像は BGRAが標準です。

(Kinect) ColorFrame -> ofImage

// ofImage ofColorFromK;
ofColorFromK.allocate(KINECT_CAM_WIDTH, KINECT_CAM_HEIGHT, OF_IMAGE_COLOR_ALPHA);
int nBufferSize = KINECT_CAM_WIDTH * KINECT_CAM_HEIGHT * 4;
unsigned char* data = ofColorFromK.getPixels();
hr = colorFrame->CopyConvertedFrameDataToArray(nBufferSize, data, ColorImageFormat_Rgba);
ofColorFromK.update();

先ほどと同様に ColorFrame からデータを変換しつつバッファにコピーしますが、今回は ofImage ofColorFromK を事前に確保しているので、書き込む先の実データのポインタを直接指定できます。また、ofImage では色のフォーマットは RGBA になります。

最後の update() を忘れずに。

cv::Mat、ofImageから(Kinect)ColorFrameに戻す

Kinectの画像形式に戻すことは無い気がするので、ここでは割愛いたします。

さいごに

グレーの画像だったり、Depthなどビット深度の異なる画像も、CVの方で CV_8UC3 等と指定している画像のデータ形式を合わせることで対応出来ると思います。

少々面倒なところもありますが、ofxCv を使う場合より現時点では汎用性が高いと思います。活用していきます。

長期展示や実験の運用のため Windows8.1を定期的に自動再起動させる

はじめに

f:id:AMANE:20150202202006j:plain

展示や実験の運用で、定期的にPCを休ませたい、自動的に再起動してリフレッシュした後・展示・実験を再開したい、というニーズがあると思います。ありました。そのための手法を考えてみました。

修正

投稿当初、以下の様に書いていたのですが

Microsoft アカウント を利用しているとパスワード解除ができず、PCの再起動をしたとしてもログイン前で止まってしまいます。MSアカウント を利用されている方は、以下の手順でローカルアカウントログインに変更します。

その後調べていたら、MSアカウントでもパスワード無しで起動時ログイン出来ることがわかりました。その点について修正しています。

前提

- Windows8.1
- Microsoft アカウントを利用したまま、パスワードを不要にする **または**
- Microsoft アカウントでのログインは利用せず、マシンのローカルアカウントログインとする
- その上で、パスワードを解除してマシンを運用する
- BIOSに、Auto Power On 的な機能がないものとする

Windows 8.1 としましたが、おそらくwindows7,8 でも同様に可能だと思います。

Auto Power On があれば

完全にシャットダウンした状態からでもマザーボードの持っているタイマーで起動ができるので、本記事で説明するような 必要時間休止→復帰→リブート というプロセスを通る必要がなくなります。

本記事では、Auto Power On的な機能がない場合にどうするか、について説明していきます。

Auto Power On については下記記事を参考にされてください

MSアカウント でのログインのまま、起動時のパスワード入力を不要にする

下記サイトの方法で可能です

(または)ローカルアカウントにし、パスワードを解除する

Microsoft アカウント を利用しているとパスワード解除ができず、PCの再起動をしたとしてもログイン前で止まってしまいます。MS ID を利用されている方は、以下の手順でローカルアカウントログインに変更します。

ローカルアカウントを使用すると、パスワードをそもそも設定しないことが出来ます。

この工程の一番最後で、パスワードを入れて確認するところがありますが、ここを空白のまま「次へ」進むと、パスワードが解除された状態でローカルアカウントに切り替わります。

ちなみに、MSアカウント時代のデータが消えたりはしないのでご安心ください

工程

全容はこんな感じ

1. 展示・実験の終了時刻になったら、動いていたプロセスを殺して、PCをシャットダウンできる状況にする
2. ハイバネーション(休止)状態にする
3. 展示・実験の開始時刻の少し前に、タスクスケジューラの機能でハイバネーション(休止)から復帰する
4. 再起動する
5. 展示・実験に必要なプログラムをスクリプトで起動する

先述の通り、Auto Power On が出来ないためシャットダウンはせず、しかしハイバネーションさせることで極力PCを休ませたのちリフレッシュのために再起動する、という作戦となっています。

一個ずつ見ていきます

1. 動いていたプロセスを殺す + 2. ハイバネーション

バッチファイル作成

以下のようなバッチファイルを作成して適当な場所に置いておきます

rem
rem goToSleep.bat
rem

echo "kill all apps and go to Hibernation"

taskkill /im "iexplore.exe" /f

timeout /T 10

taskkill /im "notepad++.exe"

timeout /T 20

rundll32.exe PowrProf.dll,SetSuspendState

ここでは、 IEと "notepad++.exe" というアプリが仮に展示で使われていると仮定して、それを殺し、20秒待った後、ハイバネーションに入る、というバッチとなっています。

ハイバネーションは、setsuspendstate というWindowsAPIを使うことで実現しています。

rundll32.exe の罠

このStackoverflow のスレッドでは、 rundll32.exe PowrProf.dll,SetSuspendState 0,1,0 でスリープする、と言っていますが、これは間違いなようです。私も数パタン試してみましたが、最後のbool三つの「引数のような指定」はおそらく機能しておらず、すべてハイバネーションしています。APIのデフォルトの動作なのでしょうか。

この状態でも今回の目的は達成できているとも言えるのですが、もし何かしらの理由でハイバネーションできない/したくない場合は、正しくスリープのAPIを呼ぶ必要があります。プログラムからスリープを呼ぶ方法は、以下のページ様の手法で確認が出来ました。

これをちょっとカスタムして、以下のコードでプロジェクトを作って、exe をはき出しておきます。

// これを、 GoToSleep.exe としてビルド

#include <Windows.h>
#include <powrprof.h>
#pragma comment(lib, "powrprof.lib")

int main()
{
    SetSuspendState(FALSE, FALSE, FALSE);
    // 第1引数がFALSEだとスリープ、TRUEだと休止(hibernation)
    return 0;
}

その上で、バッチファイルを書き換えます

rem rundll32.exe PowrProf.dll,SetSuspendState
cd <PATH_TO_EXE>
start GoToSleep.exe

これで正しくスリープ / 休止が出来ます。

タスクスケジューラに登録
  • コントロールパネル > システムとセキュリティ > 管理ツール > タスクスケジューラ でタスクスケジューラを開きます
  • 基本タスクの作成 をクリックすると、タスク作成のウィザードが始まり、埋めていくことでタスクを登録できます。
  • 名前を適当につけます。 goToSleep とか
  • PCをハイバネート/スリープ させたい周期を考えてトリガーに登録します (たとえば、「毎日、20:30」 など
  • 操作として、先ほど作成したバッチを登録します

このスクリプトについては、タスクのオプションをいじる必要はありません

3. ハイバネーションから復帰 + 4. 再起動

バッチファイル作成

Windows 標準のタスクスケジューラの機能で、ハイバネーション or スリープ から復帰することができます。

以下のようなバッチファイルを作成して、適当な場所に置いておきます

rem
rem wakeFromSleepAndReboot.bat
rem

echo "wake from sleep and reboot"

timeout /T 20

shutdown -r -t 10

ここでは、20秒待ったのちリブートする、というスクリプトになっています。

タスクスケジューラに登録

今回、ハイバネーション/スリープからの復帰は、タスクスケジューラの機能を用いて行います。まず一個前と同様に作成したバッチをタスクスケジューラに登録します。

その後、登録したタスクのプロパティを開き 条件 タブ中の 「タスクを実行するためにスリープを解除する」 にチェックを入れます。

f:id:AMANE:20150202201830p:plain

これで、ハイバネーション/スリープ中であっても、登録したバッチが実行されるようになります。

このあたりについては、こちらのサイトで紹介されていました。

5. 必要なプログラムの起動

バッチファイル作成

複数のプログラムを順に起動したい場合も多いと思うので、これもバッチを作ります。

例として、notepad++ と IE を起動します。(意味はとくにありません(>_<))

rem
rem launchApps.bat
rem

echo "launch apps"

cd "C:\Program Files (x86)\Notepad++"
start notepad++.exe

timeout /T 10

start iexplore.exe

exit

notepad++ を起動した後、10秒待って、Internet Explorer を立ち上げます

タスクスケジューラに登録

ここでは上二つのバッチとは異なり、時刻指定ではなく、スタートアップを引き金としてアプリを立ち上げる指定にしてみます。起動からPCが色々立ち上げたり、ネットワークがつながって落ち着くまでの時間を多少取った方が良いかとも思うからです。

「基本タスクの作成」のウィザードで、トリガー を「コンピュータの起動時」にします。これでも十分かもしれませんが、更に少し余裕を持たせるために、開始を遅延させます。

  • タスクスケジューラの一覧から今登録したタスクのプロパティを開く
  • トリガースタートアップ時 を編集します。
  • 遅延時間を指定する にチェックを入れて、適当に時間を設定します。たとえば起動後1分。

f:id:AMANE:20150202195533p:plain

これで、上記のバッチは起動後1分で実行されることになります。

完成!

以上で、定期的に再起動する仕組みができました。ハイバネーションの設定周りで、PCごとに差があるかもしれません。その辺りは各自柔軟に対処、と言うことで。

Sleep / Standby / Suspend / Hibernation / Hybrid Sleep について

今回、setsuspendstate の挙動で結構はまっていろいろ調べたところ、日本語と英語の間、また、プログラマWindowsの一般ユーザ の間で、スリープや休止に関する言葉の使い方がそれぞれ異なることがわかりました。ここに整理してまとめておきます。

参照

Sleep == Standby == (hibernationでは無い)Suspend == スリープ、スタンバイ

メモリ上にOSの状態を残し、メモリにのみ通電を続けるもの。直ぐ起動できるがやや電気を食う。

Hibernation な suspend == 休止

HDD/SSD にOSの状態を保存し、いったんシステム全体の電源を落とす物。やや起動に時間がかかるが、シャットダウン時と同様に電気を使わなくなる

Hybrid Sleep == ハイブリッドスリープ

上の二つの合わせ技。通常はスリープ的に寝ていて直ぐ起動できる状態であるが、電池が切れそうになるとHibernation状態に移行する

初め、Suspend == 休止 だと思い込んでいて混乱しました。

さいごに

もしかすると似たような事をする為のユーティリティソフトもあるかもしれませんが、あまり調べていません。もし良いものをご存じの方がいらっしゃいましたら、教えていただけると嬉しいです。

openFrameworks に Kinect for Windows SDK 2.0 の AudioBasics サンプルを移植する

はじめに

前回、Color画像のサンプルや FaceTracking のサンプルを移植しましたが、今回は Audioのサンプルを移植してみます。

AudioBasics-D2D

このサンプルは、Kinectのマイクをつかって、1つの音源の方向を特定し、方向とその信頼度を可視化しつつ、リアルタイムに音波の強さを描画します。

f:id:AMANE:20150206203741p:plain

音源の方向特定はかなりの精度で出来ていますが、今のところ一方向のみの特定に制約されています。しかし、API複数の AudioBeamFrame を取り出せる作りになっているので、将来的にはもしかしたら、同時に複数方向から鳴っているときも、それぞれ識別できるようになるかもしれません。楽しみです。

本記事の完成品

事前に

ポイントになりそうなところを調べておきます。

マルチスレッド

本家サンプルコードをざーっと読んでみたところ

  • 受け取った音声データの解析・可視化を行うメインスレッド
  • 音声データの受け取りを行うスレッド

の2つがあることがわかりました。SDK本家サンプルではこれを CreateThread 関数や EnterCriticalSection 関数を使ったWindowsらしいマルチスレッドプログラミングで実現していますが、せっかくoFなのでoFのマルチスレッドで実現したいです。

リングバッファの取り扱いと逐次描画

Kinecet SDK を oF に移植するぜ!という主旨からは若干離れるので本記事では特段言及しませんが、

  • 「40byte分のボリュームの平均値」 を、可視化する量より少し多い 1000 個分ためて先頭を記録するリングバッファ
  • その中で可視化する領域の先頭を指すポインタ
  • 前回の描画フレーム後入ってきたデータの量の算出
  • 上記の情報を使って、数秒分を少しずつ進めながらリアルタイムにボリューム可視化する

あたりのプログラムのサンプルとして非常に勉強になりました。

取りかかる

oFでKinect for Windows SDK 2.0 を使う方法の概要については、前回の記事を参考になさってください。

ブロッキング

ofThread のサンプルを参考に、音声データの受け取りを行うスレッドを作ります。受け取る瞬間と、データを絵を描くのに使う配列に移動する瞬間がぶつかるとまずいので、スレッドを立てて、ロックアンロックを行います。

本家では EnterCriticalSection() LeaveCriticalSection()クリティカルセクションを作っているところは、 if(lock()) + unlock() で同様の処理になります。

WINAPIのクリティカルセクションについてはこちらの記事が分かりやすかったです

ofThread は startThread() 引数無しだとブロッキングなスレッドになって、 lock() 時に他でロックしてたら、それがアンロックされるのを待機します。一方 startThread(false) でスレッドをスタートさせるとノンブロッキングになり、if(lock()){} は即時に false を返すので、 if文ブロック内の処理はいったん飛ばされることになります。今回はWINAPIのクリティカルセクションの手法に習って、ブロッキングなスレッドとします。

ofThreadのブロッキングについてはこちらのフォーラムが勉強になりました。 Theo先生直々返答。

ofApp::exit() での処理 WaitForThread()

ofThreadのサンプルは stopThread() 関数で終了させていますが、今回のような音のプログラミングの終了時にこれをやると、データのコピー中等に処理を殺そうとしてしまい、多くの場合エラーを起こします。(エラーが起きない場合もあるようです) ちゃんとスレッド内の処理が終わるまで待ってあげるために、アプリ終了時は WaitForThread() を使いましょう。

それ以外

は、ほぼ本家サンプルのコピーです。すみません。ありがとうございます。

できあがり

描画は、適宜良い感じにしてください!

f:id:AMANE:20150208221425p:plain

openFrameworks で Kinect for Windows SDK 2.0 をまるっと利用する

はじめに

f:id:AMANE:20150201220035j:plain

この記事では、 ラッパなどを挟まず、 Kinect for Windows SDK 2.0 のフル機能を oF 内で直接利用する方法について調べた内容をまとめます。ラッパを利用しないのは、MSDN の公式リファレンスが非常にしっかりしているからです。ネットに転がっているKinect v2 がらみの情報も公式 SDK を直接たたくものが多いので、いまのとこは素で使った方がなにかと幸せな予感がしています。

oF 内で利用することで様々な機能をひっつけやすくなるので、アプリ全体としての構築も楽になると考えています。

環境

Visual Studio は Proの方が幸せですが、ここではExpressの前提ですすめます。

Visual Studio Community 2013 じゃだめか?

個人のデベロッパだと、Visual Studio Community 2013 を使ってアドオンうはうはしたいところです。しかし、公式には openFrameworks は、vs2013 をサポートしていません。そこで片手落ちではありますが以下の手順で ビルド環境としては2012ですが、エディタとしては VS Community 2013 を使って openFrameworks の開発 を行えるようになります。

  • VS Community 2013 とは別に VS2012 Express を入れておくと、VS2012 (v110) のビルドツールが使えるようになります。
  • oF の Project Generator でプロジェクトを作る
  • VS Community 2013 で開くと、通常だとソリューションのコンバートを勧められますが、これをキャンセルします

VS の Solution Explorer で下図のように表示されていたらできていると思います。

f:id:AMANE:20150127133522p:plain

このあたりは、@selflash 氏が説明してくださっているのでご参照ください。

使い方

プロジェクト設定

@kaorun55 先生の記事ではウィンドウズアプリの前提で説明されていますが、プロジェクト設定はoFでも同じです

Kinect for Windows SDK v2.0 で開発する環境を整える(C++編)

  • of の Project Generator でプロジェクトをじぇねれーーとする
  • 追加のインクルードディレクトリを設定する
    C:\Program Files\Microsoft SDKs\Kinect\v2.0_1409\inc
  • 追加のライブラリディレクトリを設定する
    C:\Program Files\Microsoft SDKs\Kinect\v2.0_1409\Lib\x86
  • 追加の依存ファイルに Kinect20.lib を設定する

シンプルにカラー画像の表示だけ

簡単な作例として、SDK をインストールしたらついてくる公式サンプル Color Basics-D2D をベースに、oFで動かしてみました。Kinect v2 からカラーのイメージをとってきて描画するだけ。

f:id:AMANE:20150201223037j:plain

ofImage か ofTexture か

oF 使い的にはきっと基本的すぎてあれですが、動画をoFで描画する際にどっちを使うといいのかわかりませんでした。

調べてみたところ、下記フォーラムで同様の質問がなされていました。

ofImage は ofTexture を内部で使っていて、メモリの確保なども含めてラップしているクラスなので、描画部分に関しては差はない、とのこと。今回のような Kinect との連携だと、ofTexture を使う場合でも、ColorFrame からpixel配列をいったん引っこ抜いてからそれを ofTextureにloadData する必要があるので、確保するメモリ量的にも差がなさそうです。

コードは #ifdef して両方試しています

あげてあります

Face Tracking も試してみた

つづけて、FaceBasics-D2D というサンプルから、顔認識に関する最低限野部分をoF向けに移植してみました。

f:id:AMANE:20150201223113j:plain

顔出しツラいっすね。写真は悪用厳禁っす。

一生懸命口角を上げたおかげで笑顔判定がYESなのと、(普段かけない)めがね判定がYESなのが確認できると思います。(^^;)

Kinect v2 はボーンやデプスも使って顔認識とトラッキングを行うので、かなりロバストです。本当は顔出し恥ずかしいですが、写真の印刷だとほとんど判定しないのですすすs… Kinect v2 すごいっす。

コード

追加のインポート

FaceTracking の機能は Kinect20.Face.lib という別のライブラリにまとめられているので、プロジェクトの設定でそれも追加する必要があります

  • Kinect.face.h を必要なコードでインクルードする
  • Project Properties 追加の依存ファイルに Kinect20.Face.lib を設定する
(追記しました) ポストビルドコマンドで、dll等必要なファイルを持ってくる

また、oFやKinectwindowsアプリは、VSのビルドコマンド内で、必要なdllなどのファイルをoFやKinectSDKのインストールディレクトリから自分の実行ディレクトリ(exeを出力するところ)にコピーしてきて、それを使ってexeを実行しています。

たとえば Kinect for Windows SDK 2.0 のサンプル FaceBasics-D2D では、下図のような指定で必要なdllなどを取ってきています。

f:id:AMANE:20150212081206p:plain

Visual Studio で oFアプリをビルドする場合は更に、oFアプリの実行に必要なdll等一式も持ってくる必要がありますが、これは、Visual Studio向けのProject Generator でアプリを作成すれば、自動的にコマンドがセットされています。正確には、oFのインストールディレクトリ中に定義されている、デフォルトのプロパティーシートを見ています。

(下図のプロパティシートは、 VIEW > OTHER WINDOW > PROPERTY MANAGER で開きます)

f:id:AMANE:20150212083706p:plain

したがって、今回のケースで言うと、 oF のデフォルトのポストビルドコマンドと、Kinect20.Face.dll 関連のポストビルドコマンドを同居させてあげる必要があります。

プロパティシートがプロジェクトに登録してあったら、その内容は継承されるのかと思ったのですが、どうもプロジェクト固有のプロパティに書いた内容で上書きされる仕様なようですので、すべて記入されてある必要があります。できあがりはこんな感じ。

xcopy /e /i /y "$(ProjectDir)..\..\..\export\vs\*.dll" "$(ProjectDir)bin"
xcopy "$(KINECTSDK20_DIR)Redist\Face\x86\NuiDatabase" "$(TargetDir)NuiDatabase" /e /y /i /r
xcopy "$(KINECTSDK20_DIR)Redist\Face\x86\Kinect20.Face.dll" "$(TargetDir)" /c /y

この状態でビルドすると、ビルド結果の出力で、exeがはき出された後にいろいろコピーしているのがわかると思います。

1>  KinectV2Sample.vcxproj -> F:\develop\of_v0.8.4_vs_release\apps\myApps\KinectV2Sample\bin\KinectV2Sample_debug.exe
1>  F:\develop\of_v0.8.4_vs_release\apps\myApps\KinectV2Sample\..\..\..\export\vs\Assimp32.dll
1>  F:\develop\of_v0.8.4_vs_release\apps\myApps\KinectV2Sample\..\..\..\export\vs\fmodex.dll
1>  F:\develop\of_v0.8.4_vs_release\apps\myApps\KinectV2Sample\..\..\..\export\vs\fmodexL.dll
1>  F:\develop\of_v0.8.4_vs_release\apps\myApps\KinectV2Sample\..\..\..\export\vs\FreeImage.dll
1>  F:\develop\of_v0.8.4_vs_release\apps\myApps\KinectV2Sample\..\..\..\export\vs\FreeType-6.dll
1>  F:\develop\of_v0.8.4_vs_release\apps\myApps\KinectV2Sample\..\..\..\export\vs\glut32.dll
1>  F:\develop\of_v0.8.4_vs_release\apps\myApps\KinectV2Sample\..\..\..\export\vs\libeay32.dll
1>  F:\develop\of_v0.8.4_vs_release\apps\myApps\KinectV2Sample\..\..\..\export\vs\ssleay32.dll
1>  F:\develop\of_v0.8.4_vs_release\apps\myApps\KinectV2Sample\..\..\..\export\vs\Zlib.dll
1>  9 個のファイルをコピーしました
1>  C:\Program Files\Microsoft SDKs\Kinect\v2.0_1409\Redist\Face\x86\NuiDatabase\FaceAlignment.bin
1>  C:\Program Files\Microsoft SDKs\Kinect\v2.0_1409\Redist\Face\x86\NuiDatabase\FaceAlignmentColor.bin
1>  C:\Program Files\Microsoft SDKs\Kinect\v2.0_1409\Redist\Face\x86\NuiDatabase\FaceAlignmentColor27.bin

中略。この辺りは、顔発見のための辞書データなどをコピーしている

1>  C:\Program Files\Microsoft SDKs\Kinect\v2.0_1409\Redist\Face\x86\NuiDatabase\HDFaceTracker\ViewModel\left.p.txt
1>  C:\Program Files\Microsoft SDKs\Kinect\v2.0_1409\Redist\Face\x86\NuiDatabase\HDFaceTracker\ViewModel\right.mod.bin
1>  C:\Program Files\Microsoft SDKs\Kinect\v2.0_1409\Redist\Face\x86\NuiDatabase\HDFaceTracker\ViewModel\right.p.txt
1>  C:\Program Files\Microsoft SDKs\Kinect\v2.0_1409\Redist\Face\x86\NuiDatabase\HDFaceTracker\WholeHeadModel\FullHeadMaskVertexCorrespondence.txt
1>  C:\Program Files\Microsoft SDKs\Kinect\v2.0_1409\Redist\Face\x86\NuiDatabase\HDFaceTracker\WholeHeadModel\fullMeanHead60_tri.ply
1>  57 個のファイルをコピーしました
1>  C:\Program Files\Microsoft SDKs\Kinect\v2.0_1409\Redist\Face\x86\Kinect20.Face.dll
1>  1 個のファイルをコピーしました

これで実行可能です。

一応あげてあります

コードはかなりやっつけな感じで書いたので、一応上げますが、あまり参考にはされない方が良いかと思います(>_<)

先ほどのリポジトリにブランチとしてぶら下げています。

そのほかのアプローチ

以上のように使えることの確認をしましたが、ここに至る前に、いろいろ Kinect for Windows SDK 2.0 と oF のつなぎ方を調査したので、それもまとめておきます。

Kinect Common Bridge / ofxKinectv2

Kinect Common Bridge は、MSOpenTech コミュニティで開発されている Kinect for Windows SDK のラッパで、そのブランチとして 2.0 向けが開発されています。CinderやoFなどのクリエイティブコーダー向けに使いやすくするのが主目的のようです。

これを使ってoF向けにさらにラップしたのが ofxKinectv2 という addon です。これはまだ Face Tracking のフィーチャをサポートしていません。Color, Depth, Infrared, Body あたりの機能を簡単に使う分にはこれでも良さそうです。

Windows Store 向け

Channel9 (MSのデベロッパー向け広報ブログ) で、 Windows Store App 版での oF + Kinect v2 の記事が紹介されていました。この記事中で、MSOpenTech が Windows Store 向けアプリを生成する変更を加えた Project Generator 込みの oF Fork を紹介しています。もし必要があれば。

Mac

Mac + oF + Kinect v2 をやる場合は、 Theo 先生のこれが使えそうですが、試してはいません。名前かぶってますね。

Unity 使おうぜ Unity

このブログで過去に取り上げましたが、Unity Pro をお持ちならKinect v2 用の公式 UnityPackage がありますので、こちらを使うと楽ちんです。が、SDK 2.0 のフル機能を使えるわけではなさそうです(要調査) *1

さいごに

使えるようになったので、使っていきます。

*1:kaorun55 先生資料によると、FaceやSpeech、Gestureなど結構な部分が使えないようです http://www.slideshare.net/kaorun55/kinect-for-windows-v2-39610207

読書感想:融けるデザイン

はじめに

講演会や研究発表の場などで(一方的に)非常に注目しお世話になっている、インタラクション研究者、渡邊恵太先生の著作が出たので、発売日に買って読みました。

あまりに「はまった」ので、2周読んだところで読書感想ブログします。

融けるデザイン ―ハード×ソフト×ネット時代の新たな設計論

融けるデザイン ―ハード×ソフト×ネット時代の新たな設計論

渡邊恵太先生

の研究については、彼のホームページにきれいにまとめてあるので、そちらに目を通してから本を読まれると、より理解が進むかと思います。

サイト上で試すことのできる Visual Haptics や 味ペン は是非体験してみてください。

また、本書の中でも繰り返されている自己帰属感について、iPhoneを事例に紹介されている記事があり、わかりやすいので、本を読む前に読んでみると良いかと思います。

感動した一節集 兼 ざっくり要約

自分のためのメモと本書のイメージ紹介として、私が「なるほどー」とか「そうだ、その表現だ!」とか「この考え方は使える」と膝を打った文章を一部引用させていただきます。

この記事を書く前、2周目を読んでいるときに作ったメモは、この記事の10倍くらいあるのですが、何とか選抜して減らしてみました。(そのくらい、読み応えがあります!)

正しい切り出し方ができていなかったら渡邊先生に非常に申し訳ないので、少しでもご興味もたれた方は是非本を読んでください(^^;)

インターフェイス/インタラクションデザインとは

インターフェイスのデザインとは、コンピュータと人との関係性を設計し、人の行動や活動を作ること

コンピュータとインターネットで、なにやる?って考えたときに、ついうっかりスマートテレビとか作ってしまうと、思考の広がって無さが露呈して非常に残念な感じになるので、いま人は、何をするか何が起こるのか何を得て何を感じるのか、もっと自由にデザインしなければいけない。  

インターフェイスデザインとは、可能のデザイン。環境から人が何を知覚し、どんな行為を生むかをデザインすること。

現象レイヤの体験と自己帰属感

現象レイヤの体験(人の認知や心理な観点で見た人の知覚と行為)をデザインすることがいかに大切であるか、についての説明。

会社では当然「高いクオリティ」や「美しいビジュアル・アニメーション」を求めるけど、その具体的な評価指標を考える上で非常に参考になると思いました。

インターフェイス石器時代のような道具のあり方、原因と結果が直接的な関係になることを一つの目標とする。ハンマーという道具自体を意識せず、釘を打つこと(対象)に集中できるようなあり方が、道具が透明である、ということ。

パソコン操作中にカーソルを意識しないことや、iPhoneの体験の良さを例に、自己帰属感が説明されます。iPhoneを操作しているのではなく、その先の情報に直接触れているような感覚を得られるようになる。

(iPhoneが非常になめらかにさくさく動く意味は→) 指とグラフィックとの高い動きの連動性が道具的存在となり、自己帰属感をもたらす。そしてその結果、道具としての透明性を得る。

ユビキタスコンピューティングから、環境と知覚、ギブソンの話

人間と環境の間に、行為だけでなく、行為を拡張する道具が介入すれば、別の次元の「可能」を知覚し、また行為へつながる。良い道具は、特にこの可能の知覚が優れている。そして、環境と接続する知覚と行為は途切れることなく循環している。それが「体験」の正体であると思う

私がいすや丈夫な台を見れば「座れる」と思うのと同じ透明感で、コンピュータが人とインタラクションし機能する世界、ということか。

情報技術を中心としたインタラクションデザインの目標は、ユビキタスコンピューティングの流れをくめば、もはやパソコンやスマートフォンを使っていると言う意識がないまま直接コンピュータやインターネットの恩恵を受ける透明性をどうやって実現するか、ということなのだ

環境と知覚、という考え方からインタラクションを考えると

インタラクションは既にある人間の知覚行為を支えている環境の仕組みを活かしながら、コンピュータという異物をうまく馴染ませる。自然回帰ではなく、世界を拡張するために。

人と世界の拡張、については説明が繰り返されます

なぜ自己帰属感が大事か

目的行為への集中だけではなく、、、

自己帰属した道具は透明化し、意識されなくなる。すると何も感じない世界があるのだろうか。(中略) 自己帰属がもたらすのは、そこにある新しい知覚世界だ。(中略)道具はあなたを変えながら世界との接点を変える。自己が拡張される。

最近はやりの「拡張人間」も、ロボティクスとかセンシングとかV/M/A/R的な派手な側面ばかりではなく、渡邊先生の研究のように日々の体験を静かに変えるような側面からも考えて取り組んでいきたいです。

自己帰属感が高いと、自己感や「私が感」が生まれて「自分の体験」が立ち上がってくる。この体験こそが生きている実感、あるいは愉しさや喜びとも言える。生きている実感のようなものを、その道具/サービスを使う中で感じられる

ここまで来ると会社では説明しづらいですが(笑) 個人的には納得いったし、こういった観念を常に持って取り組んでいきたいです。

デザインへの取り組み方。体験の設計方法の具体的取り組み。意識すべきこと

これからのデザイン。画面のデザイン、モノの形のデザインにとどまらない。

インターネット + コンピュータのメタメディアの持つ、(既存のメタファに縛られない)表現の自由度と柔軟性の高さを最大限に生かし、新しい価値を生み出す

20世紀の技術は、人がこれまでやってきたことを効率よく代行するものであった。これからは知的創造行為も含まれる。本書が目指すのは、個人の能力拡張とそのデザインである

メタメディアのインターフェイスデザインの実例

実世界へ直接働きかけるインターフェイス。情報の道具化、情報自体を道具として利用する。人々が利用する道具自体にウェブ上のデータを結びつけ、物理的に制約を与えて、人の行動を直接的に支援する

それらの実例が、smoon, integlass, length printer などのプロジェクト。

パラレルインタラクションのすすめ

ユーザーインターフェイスの常識とは、「システムを使いたくて使っている人」や「目の前に居る人」を暗黙の内に前提としている。そのため操作を提供するデザインを「ユーザーインターフェイス」と呼んでいる。暗黙的にインタラクションの高速を前提に設計してしまっている 「私のシステムを使っている限り、私のシステムは使いやすい」

パラレルインタラクション。マルチデバイスの時代。「あなたのサービスはユーザーの生活のごく一部でしかない」

  • 文脈はデバイスから生活へ
  • 拘束性は配慮へ
  • 利用タイミングは集中から分散へ

(やや禁則事項ですが) これは、会社の上の人ほど逃れられない呪縛みたいになっているのをひしひしと感じています。「パラレルになるとしたら、プロダクト/コンテンツの価値が低い証拠だ」とか言われかねない勢いです。そういった文化を背景にビジネスをやってきた会社ですからそう考えてしまうのも仕方ないかもしれませんが、自分が関わるプロジェクトはそういうところを少しずつ変えていきたいと思っています。

さいごに

研究者の方の著作なのに、実際の生活に具体的な提案をしていかなければいけないメーカーの人間(私)に、かなりダイレクトに響く内容でした。

自己帰属感の話、iPhoneの例は非常にわかりやすく「そこのクオリティ上げたら、商品売れるの?」「それより機能を増やすべきじゃないの?」という「あるある」問答集に対する明確な答えになっており、これから積極的に同僚内で布教していきたいと考えています。

まずは、理解のありそうなデザイナさんやエンジニアさんに本書を布教して、こういったとこ大事にして企画とかインターフェイスデザインとかしていこうぜ!という雰囲気を作り出していきたいです。

Web Audio API の勉強 - グラフィックイコライザーを作る

はじめに

前回の記事で「Web Audio API はシンプルで使いやすいしパフォーマンスも問題なさそう」という予感を得たので、少し勉強してみることにしました。まずは基本的な使い方を勉強して、それから練習問題として、グラフィックイコライザーを作ってみます。

グラフィックイコライザー

iTunes でいうこいつ。ベースを聞きたいから低い周波数を強める(相対的に中高音を抑える)とか、シンバルの響きを感じたいから中高音を上げる(相対的に定温を抑える)とかするのに使うやつ。(俺氏曰く)

f:id:AMANE:20150124182347p:plain

完成品

今回は効果を分かりやすくするために「すべての周波数で同じ強度」となるホワイトノイズを生成し、それに対して周波数ごとの強弱をつけられるようなサンプルになっています。

使い方

  • Play でホワイトノイズが鳴ります(ボリューム注意!)
  • バーを動かすことで、指定周波数周辺を増減させます
  • グラフの下の"Log" "Linear" ボタンを押すと、グラフのx軸(音の周波数)を対数表示に切り替えられます

別ページで開く場合はこちらから > Web Audio Graphical Equalizer

このプログラムは g200kg.com さまの下記記事をベースに改変して作成いたしました。

基礎のお勉強

まずはWeb Audio APIの基本を勉強しました。参考にさせていただいた主なサイトは以下。

Getting Started with Web Audio API - HTML5 Rocks

"Web Audio API" でググるとトップに出るので、まずはここから。Googleのエンジニアによる記事。短い文量でWeb Audio APIの概要をつかむことが出来ました。

(電子書籍) O'Reilly Japan - Web Audio API

上の記事著者の著作、の邦訳。実質上の公式入門書。上の記事を拡張したような内容。この本のサポートページとして作られているサンプル集が非常に良い感じです。

また、上記サンプル集自体が、webaudioapi.com と言うサイトに含まれていて、ここから仕様書だったり、一般の方が作られている作例集に飛べたりします。

Web Audio API 解説 - 01.前説 | g200kg Music & Software

結論としては、このサイトだけで良かったです。Web Audio APIの基本から、細かい各ノードの使い方、それらの背景にあるデジタル音楽の理論まで、一通り学ぶことが出来ます。今回作成したグライコも、ここの記事中のコードをフォークして作らせていただきました。

Web Audio API (日本語訳)

上記サイトの方が、W3C の公式文書を邦訳してくださっています。ありがたすぎました。完璧でした。 Published Versionとしてはいまのところ W3C Working Draft 10 October 2013 が最新のようなので、邦訳も最新、と言うことになります。

Editors Draft としては、2015/1/6 に最新のものが提示されていました。

イコライザの実装

BiquadFilter "peaking" のチェーン

Web Audio API では sourceNode (音の発生源または音声データ)から destinationNode(最終的な出力先。端末のサウンドデバイスなど) までの間に、ゲイン調整や周波数領域でのフィルタリング、パンニングなどの効果をつけるノードを複数挟むことが出来ます。

ターゲット周波数の異なる複数ピーキングフィルタを通すことで、グライコ的な物が作れるだろうと予測をつけて調べて見たところ、似たようなやりとりがされているのを見つけました。これで行けそうな気がします。

操作する周波数は、冒頭にキャプチャを貼った iTunes のイコライザを参考に、 32kHz から 2倍ずつ上がっていく物にしました。

ホワイトノイズの発生と、可視化

この辺りは、参考にさせていただいた元記事様を参考になさってください

グラフのx軸を対数にする

イコライザーのバーは対数で並べているのに対し結果のグラフがリニアで表示されていると、低い周波数の左側の辺りが過密になって見にくかったので、x軸を対数表示と切り替えられるようにしました。

できあがりのルーティング

f:id:AMANE:20150124214154p:plain

(細かいところ)

縦向きのスライダーバーの作り方

さいごに

実装の詳細はコードをご覧下さい。

Web Audio API を使ってリッチな楽器を作っている作例なども勉強中に見かけました。自分もトライしてみたいですが、大変そうな予感。

前回今回試したように、入ってくる音に対してフィルタリングするような用途には、Web Audio APIはかなり答えてくれている印象を持ちました。今回も BiquadFilter を多段で挟んでも、特にパフォーマンスが悪くなったりはしていません。コードもかなりスッキリ書けるので良いですね。

積極的に使っていこうと思います。

マイク入力を WebAudio で加工して、ビデオと合流させた後 WebRTC で使う

はじめに

前の2記事ほど、ウェブカメラの映像を openFrameworks で加工してビデオデバイスに再度流し込むことで、WebRTC などで扱えるようにする方法について調査してきました。

音声も同様に加工して WebRTCで扱えるようにしたいなーと思いました。

完成品

f:id:AMANE:20150118110301p:plain

こちらで動かしています -> http://www.izmiz.me/mediaStreamMerging/

簡単に使い方
  • ウェブカムとマイクを持っている二台のPCで上記サイトにアクセスします
  • カメラとマイクの利用の許諾を問われるので、許可してください。
  • どちらかのPCで、相手の画面に表示されているIDを打ち込んで call すると、ウェブチャットが開始されます
  • Filter on にチェックして、 Frequency や Q値 を動かすと、相手側に伝える音声に ローパスがかかります
  • ハウリング注意。

検討した2手法

仮想サウンドドライバを使ってOSに流し込む方法 (不採用)

ycapture と同じ考え方で、作り上げた音声をOSの音声デバイスに再度流し込む手法を初めは検討しました。ドライバ相当のものを自力で書くのは面倒なので、有り物の組み合わせで何とか行きたいです。

と思って調べていたところ、ニコニコとかで実況をする方々が、自分の音声と音楽やら動画やらの音声を混ぜるのにOSのソフトウェアミキサー(Windowsのステレオミキサー)を使っていることを知りました。さらにその流れで、NETDUETTO というソフトに同梱されている仮想サウンドドライバを使うことで、コンピュータで再生している音声を音声デバイスとして再入力出来ることが分かりました。

となれば、oF なり Pure data なりで音声を加工してこの仕組みで音声デバイスに戻せば、WebRTCでも使えそうです。

f:id:AMANE:20150118104431p:plain

WebAudio と WebRTC を組み合わせる方法 (採用☆)

一方で、WebAudio API を使えば、jsの簡単なコードで音声にエフェクトを掛けられることも分かりました。ブラウザ内で完結するのもgoodです。

  • WebAudio APIの入力をマイクにする
  • WebAudio APIの出力を、mediaStream のビデオに合流させる

この2つが出来れば、目的は果たせます。そのためにちょいと調査をしました

こちらの記事様の時点では、AudioDestinationNode から mediaStream を引っこ抜くのは実装が不完全そう、という結果になっていました。しかし希望を持ったのでもう少し調べて見たところ、w3c の公式で「まさに」な内容が紹介されていました

The following examples illustrate WebRTC integration with the Web Audio API.

とのことです。このページの Example5 が、まさに今回の内容と同じになっています。図示すると下のような感じになります。これでいけそうです。

f:id:AMANE:20150118104440p:plain

今回は

ウェブカム映像へのエフェクトについては、パフォーマンスの観点から別アプリとの連携という形にしましたが、ちょっとWebAudio API を使ってみたところ、シンプルなフィルタリング等ならパフォーマンスに問題はなさそうでした。

システム構成もシンプルに出来るので、音声に関しては後者、ブラウザ内ですべてやる方式でトライしてみます。

音質

NETDUETTO の仮想デバイスをまたいで入ってきた音の音質が悪い印象もありました。これはもしかしたら私の設定の問題かもしれないのでここでは断言はしませんが、今のところ音質良くできている Web Audio API を利用する方向で行きます。

実装

映像のストリームも加える

最終的に「映像・音声共にエフェクトの掛けられるウェブチャットシステム」としたいので、上のExample 5に加えて、カメラ映像もmediaStreamに合流させる必要があります。

試行錯誤した結果、映像・音声で別々の mediaStream を作ったあと、片方をもう片方にマージ出来ることが分かりました。

// videoStream 映像のMediaStream
// audioDestNode WebAudio API の AudioDestinationNode

videoStream.addTrack(audioDestNode.stream.getAudioTracks()[0]);

// できあがったstream を、peerjs で使う

先の構成図にこの処理を加えて、最終的にはこんな感じになります

f:id:AMANE:20150118175140p:plain

完成品

今回は、下記二つのコードを合体させています

これに、上で述べた映像のストリームを追加する方法を加えて、音声加工可能なビデオチャットシステムとしています。

初めにも書きましたが、完成品はこちらで動いています。http://www.izmiz.me/mediaStreamMerging/

SkyWay サービス利用の注意点

上がっているコードには、SkyWayのAPI key が直打ちされています。この API key は私のドメイン(www.izmiz.me)からしか使えない物になっているので、ご自身で試される場合は、ご自身でSkyWayのアカウントを作成し、ご自身のドメインを適用して API key を取得してください。

さいごに

今回はWebRTC との組み合わせにフォーカスしてまとめました。

次はWebAudio API にフォーカスして、エフェクトの作り込みにトライしてみたいです。