Hi-farm blog

ActionScript 3.0 , AIR , FLEXからCocoa, OpenGL

Archive for December, 2011

OpenNIのUnityWrapper

このエントリはOpenNI Advent Calendar 2011 : ATNDの12月24日分です!!


さてクリスマスイブですが、
少し前からOpenNIにはUnityWrapper版が存在していますのでそれについて紹介します。

unity_screenshot

最近話題になっている、ゲームの開発環境のUnity3Dというものがあり、OpenNIのサイトからUnity3Dで使うためのUnityWrapperをダウンロードできます。

opennidownload


Unity3Dについて:

Unity3D ( http://unity3d.com/unity/ ) とはゲーム開発ツールであり、WindowsとMacのどちらでも開発する事が可能です。
IDEがあるのでステージの画面を見ながら次々とオブジェクトを配置するだけでゲームの世界を簡単に作る事ができます。
プログラムはJavascriptとC#(mono)で書く事ができるのでweb開発者や.NETの開発者にも取っ付きやすいのではないでしょうか。
MacでもC#で記述する事ができます。

また、一人でグラフィックやサウンドやモデリング、プログラムを行うのは大変ですが、Unity3DではAsset Storeというものが用意されており、これを利用する事で必要な素材を入手する事ができるので気軽にゲーム開発を進める事ができます。

Unity3Dの無料版、有料版、ライセンスについて

無料版と有料版があり、無料版では制限はいくつかありますが、WindowsとMacで実行できますし、有料版にアップグレードする事でAndroidやiOSに対応させる事も可能です。
詳しいライセンスなどはUnity3Dのサイト( http://unity3d.com/unity/licenses )か、「強火で進め」さまのサイトが詳しいです。( http://d.hatena.ne.jp/nakamura001/20110710/1310292561


Unityのダウンロードからインストール

それでは、Unityをダウンロードしましょう。
http://unity3d.com/unity/download/より、Unityをダウンロードし、流れに沿ってインストールしてください。
インストール後、先ほどOpenNIのサイトからダウンロードしたファイル(Unity OpenNI toolkit 0.9.7.1.unitypackage )をダブルクリックしImport Packageより一式をunityにインポートします。
importが完了すると、Projectタブにこのようなファイル群が表示されます。
unity_project

OpenNI/Sample Scenes以下にすぐに試せるようなサンプルシーンが入っていますのでダブルクリックしてシーンを開き、三角の再生ボタンを押して次々と試してみるとUnity3D+OpenNIの可能性を試せると思います。
Unity_IDE

私はライブなどで使ったりしていますが、骨格をちゃんと映していれば問題なく現場でも使えます。今のUnityWrapperだと全身映す前提のコードになっているので、上半身だけ認識などに変更する事でより柔軟なアプリケーションが開発できます。

ではそれぞれのサンプルのキャプチャやサンプル動画をのせておきます。


サンプルのシーンについて

MultipleSkeletons:
僕は一人なので試せませんでしたが、複数人のスケルトンを認識できるサンプルだと思います。
MutipleSkeletons
NIGUIControl:
NIGUIControl
NIInputControl:
すごく地味なのですが、手を動かすと黒い四角が追従します。XBoxでもあるような、手で操作するゲームはこれを使うと作れそうですね。

SimpleGame:
上からふってくるボールにタッチするゲームです。実際に動いたりジャンプするとそれにあわせて画面も動きます。一番運動している感じになりそうですね。

SingleSkeleton:
スケルトンの情報をもとに画面のキャラクターが動きます。

せっかくなのでスケルトンをサンタにかえてみましたよ。サンタ気分で小さく踊ってみました。
あ、サンタのデータはAsset Storeで購入可能ですよ!

※この記事は、下記の環境で確認しました。

OpenNI 1.5.2.7
NITE 1.5.2.7
Unity3D 3.4.2f3

OpenNIをOpenframeworksで使う

このエントリはOpenNI Advent Calendar 2011 : ATNDの12月23日分です!!

OpenframeworksでOpenNIの連携について書きます。

Openframeworks ( http://www.openframeworks.cc/ )(以下、oF)とは、メディアアート界隈で使われている描画や動画の扱いやプログラムの書き方がprocessingっぽく作られている、クロスプラットフォームで動作するC++のフレームワークです。
oFはたくさんの有志により様々なアドオンが配布されており、それを使うとソケットやOSC、OpenCVなどの機能を簡単に使う事ができます。

oFで使えるアドオン

oFで使えるKinect関連のアドオンがいくつか、下記のものがあります。
・ofxKinect: ( https://github.com/ofTheo/ofxKinect )
→深度情報とRGBが取得できます。スケルトンの取得機能はありません。
・ofxOpenNI:( https://github.com/gameoverhack/ofxOpenNI )
→OpenNIをoFで使えるように作ったもの。

ただ、OpenNI自体バージョンアップが早い事もあるので今回は普通のOpenNIをoFで使う方法を紹介します。

oFを使えるようにする

oFのWebサイトから必要なファイルをダウンロードします。私の場合はMacなのでosxバージョンをダウンロードします。
http://www.openframeworks.cc/download/

ダウンロードしたファイルを解凍すると下記のフォルダ構成になっています。

  • add ons / oFのアドオンが格納されています。
  • apps / サンプルプログラムがたくさん入っています。実際にoFでアプリを開発する場合はこの中のexamples/EmptyExampleをベースにします。
  • libs / oF自体のライブラリやoFが使っているライブラリが格納されています。

of_directory

では、oFの基本を理解するために EmptyExampleをみてみます。

testApp.cppをみてみましょう。
はじめに定義されているメソッドの実装を進めて開発を進めます。

setup() :
アプリケーションの起動時あるいはnewした直後に呼ばれる関数です。初期化などはここで行います。
update():
毎フレーム毎draw()の前に呼ばれます。ここでデータや座標計算の更新をすると良いでしょう。
draw():
毎フレーム毎、update()の後に呼ばれます。ここには描画処理をかきます。

基本的にはこれらを使うのですが、マウスやキーボードのユーザー入力にも対応しています。

keyPressed, keyReleased:
キーボードを押したとき、離したときに呼ばれます。
mouseMoved, mouseDragged, mousePressed, mouseReleased:
マウスの移動、ドラッグ、マウスダウン、マウスを離した時に呼ばれます。

OpenNIの設定:

準備

今回はとにかく簡単に使えるようになる事を考えて説明します。
まず、OpenNIのIncludeとLibフォルダをプロジェクト直下に”OpenNI”というフォルダを作成し、そこに移動します。

次にプロジェクトにヘッダー参照パスとライブラリパスの設定をします。
プロジェクト設定の “Build Settings” → “Search Paths”の

Header Search Pathsに以下を設定します。
“$(SRCROOT)/../OpenNI/Include
Library Search Pathsに以下を設定します。
“$(SRCROOT)/../OpenNI/Lib

※設定後、自動的に別の項目に変更される場合がありますが、ビルドが通れば問題はありません。
私の環境では、
HEADER_SEARCH_PATHS_QUOTED_FOR_TARGET_1
LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1
の項目が追加されていました。

さて、それではOpenNIのコードを書いてみましょう。NiSimpleViewerをパク、、いやもとにして、深度情報を表示させてみましょう。
表示にはoFTextureクラスを使い、テクスチャとして表示させます。

今回は簡単に移植するため、NiSimpleViewerからコピペする事にします。
まず、

testApp.h

testApp.hに下記を追加します。

#include <XnCppWrapper.h>
using namespace xn;
//---------------------------------------------------------------------------
// Defines
//---------------------------------------------------------------------------
#define SAMPLE_XML_PATH "../../../data/SamplesConfig.xml"

#define DISPLAY_MODE_DEPTH		2
#define DEFAULT_DISPLAY_MODE	DISPLAY_MODE_DEPTH

#define MAX_DEPTH 10000

SamplesConfig.xmlはbin/data/以下に設置したため、
SAMPLE_XML_PATHを変更しています。

——-

testApp.cpp

testApp.cppに”Globals”の内容をもとに移植します。

//---------------------------------------------------------------------------
// Globals
//---------------------------------------------------------------------------
float g_pDepthHist[MAX_DEPTH];
XnRGB24Pixel* g_pTexMap = NULL;
unsigned int g_nTexMapX = 0;
unsigned int g_nTexMapY = 0;

unsigned int g_nViewState = DEFAULT_DISPLAY_MODE;

Context g_context;
ScriptNode g_scriptNode;
DepthGenerator g_depth;
DepthMetaData g_depthMD;

——–
NiSimpleViewerのmain関数が初期化に関する内容なので、setupに移植します。

	XnStatus rc;

	EnumerationErrors errors;
	rc = g_context.InitFromXmlFile(SAMPLE_XML_PATH, g_scriptNode, &errors);
	if (rc == XN_STATUS_NO_NODE_PRESENT)
	{
		XnChar strError[1024];
		errors.ToString(strError, 1024);
		printf("%s\n", strError);
		return ;
	}
	else if (rc != XN_STATUS_OK)
	{
		printf("Open failed: %s\n", xnGetStatusString(rc));
		return;
	}

	rc = g_context.FindExistingNode(XN_NODE_TYPE_DEPTH, g_depth);
	if (rc != XN_STATUS_OK)
	{
		printf("No depth node exists! Check your XML.");
		return;
	}

	g_depth.GetMetaData(g_depthMD);

	// Texture map init
	g_nTexMapX = (((unsigned short)(g_depthMD.FullXRes()-1) / 512) + 1) * 512;
	g_nTexMapY = (((unsigned short)(g_depthMD.FullYRes()-1) / 512) + 1) * 512;
	g_pTexMap = (XnRGB24Pixel*)malloc(g_nTexMapX * g_nTexMapY * sizeof(XnRGB24Pixel));

——-
setup関数の最後にofTextureクラスとofTextureで表示させるためのunsigned char*のデータをを初期化します。

	pixels = (unsigned char*)malloc(640*480*3*sizeof(unsigned char));
	tex.allocate(640, 480, GL_RGB);

——-
OpenNIでのデータを更新する処理をupdateに移植します。

	XnStatus rc = XN_STATUS_OK;

	// Read a new frame
	rc = g_context.WaitAnyUpdateAll();
	if (rc != XN_STATUS_OK)
	{
		printf("Read failed: %s\n", xnGetStatusString(rc));
		return;
	}

	g_depth.GetMetaData(g_depthMD);
	//g_image.GetMetaData(g_imageMD);

	const XnDepthPixel* pDepth = g_depthMD.Data();

	// Calculate the accumulative histogram (the yellow display...)
	xnOSMemSet(g_pDepthHist, 0, MAX_DEPTH*sizeof(float));

	unsigned int nNumberOfPoints = 0;
	for (XnUInt y = 0; y < g_depthMD.YRes(); ++y)
	{
		for (XnUInt x = 0; x < g_depthMD.XRes(); ++x, ++pDepth)
		{
			if (*pDepth != 0)
			{
				g_pDepthHist[*pDepth]++;
				nNumberOfPoints++;
			}
		}
	}
	for (int nIndex=1; nIndex<MAX_DEPTH; nIndex++)
	{
		g_pDepthHist[nIndex] += g_pDepthHist[nIndex-1];
	}
	if (nNumberOfPoints)
	{
		for (int nIndex=1; nIndex<MAX_DEPTH; nIndex++)
		{
			g_pDepthHist[nIndex] = (unsigned int)(256 * (1.0f - (g_pDepthHist[nIndex] / nNumberOfPoints)));
		}
	}

	xnOSMemSet(g_pTexMap, 0, g_nTexMapX*g_nTexMapY*sizeof(XnRGB24Pixel));

	// check if we need to draw depth frame to texture
	const XnDepthPixel* pDepthRow = g_depthMD.Data();
	XnRGB24Pixel* pTexRow = g_pTexMap + g_depthMD.YOffset() * g_nTexMapX;

	for (XnUInt y = 0; y < g_depthMD.YRes(); ++y)
	{
		const XnDepthPixel* pDepth = pDepthRow;
		XnRGB24Pixel* pTex = pTexRow + g_depthMD.XOffset();

		for (XnUInt x = 0; x < g_depthMD.XRes(); ++x, ++pDepth, ++pTex)
		{
			int idx = (x + y * g_depthMD.XRes()) * 3;
			if (*pDepth != 0)
			{
				int nHistValue = g_pDepthHist[*pDepth];

				pixels[idx] = nHistValue;
				pixels[idx+1] = nHistValue;
				pixels[idx+2] = nHistValue;
			}
			else
			{
				pixels[idx] = 0;
				pixels[idx+1] = 0;
				pixels[idx+2] = 0;
			}
		}

		pDepthRow += g_depthMD.XRes();
		pTexRow += g_nTexMapX;
	}

	tex.loadData(pixels, 640, 480, GL_RGB);

ofTextureのloadDataメソッドを使い、深度データをテクスチャとして読み込ませます。
——
最後にdrawメソッドにofTexetureのdrawを使って実際に描画します。

引数は、x座標、y座標、幅、高さを示しています。
—–

これでビルドすると表示できるようになります。
たくさんの警告はありますが、ライブラリ内部的なものもあるので無視する事にします。

advant_of

ファイル一式をこちらにアップしましたのでダウンロードして試してみてください。
https://github.com/mmlemon/OpenNI_Advent_oFSample

※OpenNIは1.4.0.2、oFは007で記述しています。

  • 0 Comments
  • Filed under: 未分類
  • このブログで初めて?技術以外の記事を書きます。

    IMG_0283
    会場の様子。結構広いところで30人?くらいで集まってただわいわい騒いでいました。

    昨日、「よるヒルズ半年記念パーティー第3部「独り身」」に参加してきました。
    最近はこういった会にちょこちょこ顔を出すようになっていて、これからもさらにいろんな人と交流しようと思っているのですが、なぜ僕がこのような心境になったのかを書きます。

    きっかけ – 再びフリーランスに戻ってから

    この夏にフリーランスに舞い戻ってからというもの、やはり一人暮らしで自宅作業だけだとなかなか集中することや人と話さない生活だと精神衛生上よくない、、という事で電源が使えるカフェや喫茶店などいろいろと探してはmixiの日記にメモ代わりに写真と記事を書いていました。

    まあそこでも”人の声が聞こえる”という意味では自宅作業よりは相当ましではあるのですが、他の人と話す事はまずありません。
    一人が好きだけど寂しがりやという最高に面倒くさい性格な僕は、次に人と話す事ができないかと思いました。

    一応人と会う環境はあるのだけど。。

    VJやらなんやらでクラブにいる事があって、いてしまえばそこにはいろんな人がいるのですが、どうも人種が違うように思えて話しかける勇気が出ません。
    また、ナンパなんて事をできるような人間でもないので、話しかけられません。
    さらには学生のときに僕の事に完全に気があると思ってた人に話しかけてみたら完全に避けられたという苦い思い出も加わり、とてもじゃないけど話しかける事なんてできません。。

    おっと。痛さ自慢をしてしまうところでした。

    まあそんな面倒くさい僕なのですが、今までも勉強会やフリーランスの自分として人と出会う時はクラブでの僕しか知らない人からすれば意外なくらい普通にいろんな人に話しかけたりできます。
    知り合いが一人もいないイベントだったとしても、何のためらいもなく参加できたりします。

    何が違うのか?

    何が違うかを考えてみると、
    ・頑張って軽く話さなくてよい(自分の説明&相手の方についての基本的な内容。まじめでも良いし、ふざけてても良い)
    ・ナンパみたいな感じで話さなくてよい
    ・技術の話や仕事、好きな事など話す事がある。
    ・意識や考え方などに言語化しにくいけど共通する感覚を持っている(と思い込んでいる)

    という違いですね。

    勉強会なら技術の事だし、技術が好きな人特有の愛に満ちたすてきな性格。
    よるヒルズ的なのであれば、多分好きに生きようとしている人が多いだろうから、普段わかってもらいにくい感覚
    があると思っています。

    まあ、昨日のは思い込みで突き進みましたが、楽しかったので多分感覚的にわかるところがあったと思います。

    初めて大阪から関東地方に来るとき(その時は横浜でした)は大学生。
    人口が多いが故に色んな人や性格、考え方や生き方を許容する雰囲気があって、田舎のように一つの価値観からはみ出るものは変な人として阻害する事も無く、それがすごく好きでした。
    会社に入ったけどやっぱり僕の性格は組織じゃなくて一人で生きていく方が合っていると思ってフリーになりました。
    組織の中にいると当然少数派なのですが、そとの世界にふれあってみると、どうやら自分が思っている以上にたくさんの人が同じように個人としての動き方について考えている人がいて、実際に動いている人も結構な数がいる事に気づきました。
    なんとなくいるだろうとは思っていたのですが、実際に顔を合わせてみると行動力がすごくてたくましい人にたくさん会えて、すごくたくさんの刺激とやる気をもらっています。

    なんかすごい安っぽい言葉ですが、実際そうなんですよね。

    そしてこのような流れはいわゆるノマド、シャアオフィス、シェアハウス、コワーキングスペースなどという言葉とつながり、一つの新しい生き方の形として根付いていくのではないかと感じています。
    というか、そうなってほしいという願望もあるし、その中の一人になってみたいなあ、とも思っています。
    これからどんな人と会えるのかとおもうとワクワクドキドキしますよ。

    なんかまとまりの無い文章になってごめんなさい。
    こんな僕ですが皆様よろしくお願いします。

    何か聞いてみたいこととかあればお気軽に質問ください!

    あと、、、、
    これは関係ない事ですが、僕が卒業した大学の課程(学部の下にある学科ってやつですね)がなくなっていた事を昨日しりました。。。。

  • 0 Comments
  • Filed under: 日記
  • 少しはまっていたのでメモ。

    SyphonとはMac OSX用の、アプリケーション間の画面を共有するためのフレームワークです。

    これを使うとアプリAで映像を加工し、アプリBで別の映像を加工したものをアプリCでミックスする、といったようにアプリケーション間で映像を再利用することが簡単にできる非常に便利なものです。

    Modul8やMadMapper、確かGrandVJなどの主要VJソフトも対応しています。

    通常のSDKもあるのですが、ofxSyphonというOpenFrameworksのアドオンも開発されています。

    今回はそれを追加しようとしたときに発生したエラーとその解決方法を残しておきます。

    単純にofxSyphonのアドオンを addonsフォルダに追加し、ビルドすると、アプリが起動するときに突然このエラーで落ちてしまうという問題が起きました。

    dyld: Library not loaded: @loader_path/../Frameworks/Syphon.framework/Versions/A/Syphon
    Referenced from: /Users/artcoreface/utopia/vj/kinect/openframeworks_0062/apps/examples/ofxKinect_fft_syphon/bin/ofxKinectDebug.app/Contents/MacOS/ofxKinectDebug
    Reason: image not found
    sharedlibrary apply-load-rules all

    下記のURLに書いているのですが、これはSyphon.frameworkがビルド時にコピーされないために実行時にあるはずのファイルが存在しなくなり、起きているエラーです。

    こういうエラーが発生した場合は、Syphon.frameworkが正しくコピーされるようにしないといけません。

    プロジェクトファイルを選択肢、「Build Phases」の「Copy Files」にSyphon.frameworkをドラッグ&ドロップするとビルド時に正しくコピーされるようになり、エラーが解消されます。

    ofxsyphon

    http://forums.v002.info/topic.php?id=52

    ※マシン間での通信はできないそうです。また、対応させる予定もしていないようです。

  • 0 Comments
  • Filed under: OpenFrameworks