December 2010 Archives

flashいじりがひと段落

| No Comments | No TrackBacks

どうやら今月の頭に着手していたらしいflashからC#への手動移植作業だけど、ここ3,4日集中して作業することで、4000件近くあったコンパイルエラーを全て解決して、ライブラリを生成することができた。アセンブリが出来たといっても、中はNotImplementedExceptionなどがたくさん投げられるもので、実際に動作するコードができあがったわけではない。少しずつ動作するモジュールを見つけながら動かせるようにしていくのだろうと思う。

今回の移植作業で割と勉強になったのはC# dynamicの適用範囲だ。dynamicはvarともobjectとも異なり、その柔軟性のゆえにむしろコンパイルエラーを積極的に引き起こす場合がある。

  • switch-case文における条件式で、dynamic型のオブジェクトでToString()を呼び出しても、ToString()はstringを返さないかもしれないため、switch条件式で許された型として認識してもらえない(!) objectなどの場合は、string以外を返すToString()のオーバーロードが無い限りはswitch文で使える。
  • ActionやFuncなどのdelegate互換型オブジェクトは、var変数に代入されれば、型付けされているので問題なくdelegateとして渡せるが、dynamic変数に代入されると、delegateとして渡すことができない。
  • dynamicオブジェクトのメンバーを別のオブジェクトメンバーや変数に代入するのは、通常は問題なく書ける(チェックを後回しに出来る)が、indexerによるアクセスの戻り値については、やはりvarで強く型付けされている方がコンパイル時にもエラーになりにくい。

delegateはまだ(?)covarianceやcontravarianceに限界があって、AS3のような動的なメソッドオブジェクトの代入が行えない。そんなわけでAS3のaddEventListenerのようなメソッドは、genericにしてListenerが受け取る引数の型を渡すといった手作業で移植する必要がありそうだ。まあ、いずれにしろ機械的な変換は行っていないのだけど。

とりあえず昨日今日はかなり長時間をこれに費やしたので、今日はこのくらいにしておこうと思う。

Kinectを買ってきた

| No Comments | No TrackBacks

うちにはXBoxなど無いのだけど、Kinectは入力デバイスとして大きな可能性をもっていると思う。ちなみにこれが今年の3月に書いた随想なのだから、思ったより早く時代が来たのだと思う。まあこれはTEDの関連講演やProject Qatalなんかを見て思ったことだから、別に自分の考えが時代の先を行っていたわけでは全然ないのだけど。

Kinectはオープンソースのライブラリも開発されており、PCのみで遊ぶことが出来るし、3Dカメラで手軽に遊べるというのは面白い。そんなわけで、Kinectはずっと興味深く眺めていた。先日まで忙しくてそれどころではなかったのだけど、時間的に余裕ができたのでようやく買ってきたというわけだ。

さて、そんなKinectをPCから操作する方法は、主に2つあるようだ。ひとつはXBoxのコントローラを提供しているPrimeSenseが公開しているOpenNIで、もうひとつは賞金をかけて開発されたプロジェクトOpenKinectだ。ちなみにOpenKinectで公開されているドライバはlibfreenectという名前だ。

どちらもgithubで公開されているオープンソースのプロジェクトだ、と言いたいところだけど、実際にはどちらもUSBドライバと基本的な入力の受信のみがオープンソースで公開されている。OpenNIにはPrimeSenseのミドルウェアが含まれており、これは人体の認識など、OpenNIデバイス(Kinectもその一つだ)からの入力情報から人体の動きなどを算出できるもので、より高水準のアプリケーションの作成が可能になるが、これがオープンソースではない。そしてOpenKinectには、まだこのミドルウェアに相当するものが存在しない。

また、サポート対象のプラットフォームがだいぶ異なっていて、libfreenectは主にLinuxを対象にしていて、win32はまだ正式にサポートされていない。OpenNIはWindowsとUbuntu Linuxのみで、PrimeSenseのミドルウェアがUbuntuのみということもあってか、うちのOpenSUSEではどうも動作しない(エラーメッセージをwebで探したら、異なるパッケージのライブラリにlddできないのでなないか等の指摘があって、要するにUbuntuでないとダメそうな感じだった)。仕方ないので、Windows上ではOpenNI、Linux上ではlibfreenectを使用して出来る範囲で遊んでいる。

実のところ、今はOpenKinectのサイトでは世界中で行われているハックを見られることもあって、libfreenectの方が興味深い。日本ではOpenNIの方が出来ることが多そうだというだけでそちらが話題になることが多いようだ。libfreenectのビルドは10分とかからず動かすことが出来たが、WindowsへのOpenNIの正しいインストールには1時間以上かかった上に、user trackingがまだ正常に動作しない。

今日はほぼ初めて真面目にKinectハックを見て回ったので、それで分かったことを他にも列挙してみよう。

  • 日本で話題になっているMikuMikuDanceのmotion captureはOpenNIベース(これはwindowsアプリなので当然か)。日本ではOpenCVやARToolkit連携などでもこっちがよく見つかる。
  • 逆にlibfreenectに基づいているものとしてDepthJSなどがあるが、これにもOpenCV連携が含まれている。DepthJSはgainerのFlashドライバと似たような構造で、ローカルで動作するtornadoをサーバに、chrome/safari extensionをクライアントにして(WebSocketsで)通信するようだ。
  • OpenNIにもlibfreenectにもいくつかのforkがあって、それぞれ目的に合ったものを探す必要がありそうだ。たとえばOpenNIで必要となるPrimseSenseのWindows版ドライバはgithubのmaster上には存在しない(これは他の人が日本語でもまとめている通り)。libfreenectでもC#ラッパーなどは他の人のforkが一番進んでいるようだ(今日見た感じではメインリポジトリのunstableブランチと変わらないようにも見えたが)。異なるものをインストールしても上手く動作しなかったり、インストールするドライバが見つからなかったりする。
  • Kinectは小型なので、電源のある喫茶店などに持って行っていじることもできる(!)

W3CではHTML Media Captureという仕様がwebcam入力をAPIとして標準化しようとしているけど、2Dの動画が標準化される頃には、Kinectのような3D入力デバイスが普及しているかもしれない。まあ、さすがにそれは無いだろうか。

しかし遊んでいてふと気づいたのだけど、OpenCV連携で遊んでいるだけでは3Dカメラらしいことを何もしていない。もっとドキュメントの類を読んで、何が出来るのかを勉強したほうが面白そうだ。

ひさしぶりにflashいじり(?)

| No Comments | No TrackBacks

11月のひと仕事が終わった後、先週末まではまた別の方面で、FM音源を使った慣れない作曲作業などに追われてしまっていた。FM音色いじりは、それはそれで面白い話かもしれないけど、あまり技術的にまとめられるユニークなネタが無いので、それはおいておこうと思う。

そんなわけで、ひさびさにゆとりができたので、のんびり以前作りかけていたAS3コンバータまわりを眺めていた。とはいえ、実のところ、もうコンバータ自体を改良してどうこうするより、そろそろ既存のソースを手作業で移植したほうが楽な段階なのではないかと思って、そちらに移行したところだ。

手作業で自動生成ソースのエラー修正を始めると、またいろいろAS3とC#の違いが見えてくる。

たとえばArray。C#の配列は固定だが、AS3のそれは違う、という認識で、Arrayは全てListのように扱っていたのだけど(その後紆余曲折を経て自動生成ソースの変数は全てdynamicにしてしまった)、実際にはArrayのコンストラクタ引数で、可変にするか固定にするかを指示することができるようだ。固定配列なら配列にしたほうがやりやすい。

C#に同等の式がある場合でも、意味が異なりうる場合も多そうだ。C#でコンパイルエラーになった事例としては、intVariable *= intVariable * NumberVariable のような乗算代入式がある。乗算結果はAS3ではNumberになるが、そのままintにキャストされて代入されるようだ。C#ではdoubleをintに代入しようとすることになり、エラーになる。

AS3では ||演算子がC#の ??演算子 に相当する場合がある。式の両辺の型を認識しないと、自動変換は出来ない。

AS3では条件式にCのような整数型やポインタ型を評価式にできるが、C#はもちろんboolのみだ。これも式の型を認識しないうちは不可能だ。

AS3では関数内で関数を定義することができる。コンバータでは、これはややこしいということで、関数は別途クラス内で定義していたのだけど、今度は変数のスコープの問題があって、AS3では定義された内側の関数から、外側の関数のローカル変数にアクセスできてしまうということがわかった。これはC#ではanonymous methodを定義してActionないしFuncに置き換えれば良いので、自動生成でも対応できないことはないだろう。(もう今更自動生成には戻れないけど)

...書いているとキリがないのでこのくらいにしておくけど、いずれにしろ数千件のエラーを手作業で修正していくのも大変そうだ。目に付く簡単なものから消していった現在でも、残り2000件近くある。まあのんびりやろうと思う。

前回のエントリを書いてから急な裏仕事が入ってしまって、11月はいっぱいいっぱいで過ごしてしまった。ようやく続きに取りかかることが出来た。

まず、前回書いたandroid.R.styleableをJavaベースでandroidのAPIとして呼びだそうとしたら、いきなりつまづいた。調べてみると、どうやらこのクラスはプラットフォーム依存になっていたので、望ましくないとして削除されていたようだ。Android APIのドキュメントには相変わらず存在しているので、困ったものだ。

それで今はどうしているかというと、どうやら非公開クラスであるcom.android.internal.R.styleableというクラスを使っているらしい。しかもこのソース、gitwebのbase.gitの中から直ちに見つけることが出来ない。ビルド中に自動生成されているのかもしれない。

他に方法がないか探してみたところ、Resources.Themeの中にobtainStyledAttributes()というメソッドがあることに気がついた。どうやらこれがスタイルの配列を返しているようだ。これが使えるかどうかを調べてみるというのが、ひとつのやり方だろう。

とはいえ、これだと実際にandroid環境で実行するコードを書かないといけなくなるので、なるべくそれはなしですませたい。というわけで、もうAPI上は存在しなくなったandroid.R.styleableのドキュメントをscrapingして属性スキーマを生成する、というやり方でやっつけることにした。これは文書構造さえ調べれば実現できる、安易なアプローチだ。

というわけで、このアプローチで実装して、スキーマを生成するところまで進んだのだけど、実際に生成されたスキーマでlayout/*.xmlをいくつかvalidateしてみたら、エラーになっていた。どうやら、旧android.R.styleable.LinearLayout_Layoutなどのために定義された属性が、実際にはその子孫ノード上でも指定できてしまうようだ。例えばLinearLayoutの中にあるTextViewがandroid:layout_widthを指定できる。仕方がないので、この種の属性については、全てViewで利用できるようにした(つまりどのViewの派生クラスでも利用できてしまう)。これはあまり好ましくないのだけど、そうするより他にない。

そんな感じで、デザイン上の制約をいろいろ加えつつ、一応スキーマらしきものを作ることはできた。作ってみて思ったのは、やはりAndroidのlayout.xmlはXML Schemaとは相性が悪いということだ。まだRELAX NGで定義した方がうまくいくのではないか。