2012年7月25日水曜日

続・Macでのlibjpegとかlibpngとか

またしてもひと月おきの更新です。
さて。
今回はタイトルにも掲げていますが、先日書いた記事(Macでのlibjpegとかlibpngとか)の続き(というかまとめ)です。*1
あんまり追加情報はありません。

まとめ

先日の記事で書いた、「-Lオプション付ける位置次第で動いたり動かなかったりする」という問題は、どうやらNetBeansに依存する問題のようです。*2
ということで、Macでlibjpegおよびlibpngをうまいこと動かすには、

  1. libjpegはbrewなどでインストールしたモジュールを使う
    1. ライブラリパス /usr/local/lib は、デフォルトでdyldが探すので、手動で追加しない
    2. インクルードパス /usr/local/include は指定する(-I/usr/local/include)
  2. libpngは下手にbrewなどで追加しない
    1. 最初から(?) /usr/X11/lib にライブラリファイルがあるはずなので、それを使う
    2. ライブラリパスに /usr/X11/lib を追加する(-L/usr/X11/lib)
    3. インクルードパス /usr/X11/include も指定する(-I/usr/X11/include)

ということが重要なようです。
ちなみに、X11の下にlibpngがいない場合は、XCodeをインストールした後、Command Line Toolsという追加コンポーネントをダウンロードする必要があるかもしれません。

  • *1:閲覧数を見る限り割と需要がありそうだったので。
  • *2:ターミナルからgcc直接叩いたら問題なく動いた。

2012年6月28日木曜日

Cakefile書こうとして一歩目から躓いたお話

ご無沙汰しています。
最近自分のコードを書く気力がなくてどんよりしてます。

さて。

突然ですが、私、ここ最近CoffeeScriptに魅了されております。
会社の先輩にそそのかされたとかなんとか。

仕事で結構な行数のJavaScriptを書くことがあるのですけど、素のJavaScriptを書いているとどうもしんどいことが多々有りまして。
その点CoffeeScriptだと、手軽にコードが書けて非常に便利です。

んで、諸々の事情により、CoffeeScriptを自動コンパイルする必要が出てきて、Cakefileの書き方を調べていたのですが、初手から躓いたので、そこら辺をメモしておきます。

一番単純な(ハズの)Cakefile

まずはと思って、CakeFileの使い方 -CoffeeScript-を参考に一番単純なCakefileを書いてみました。
sys = require 'sys'

sys.puts 'Heloi, word.'

するとなぜかエラー。
sys.puts〜を削除してもエラー。

ここでようやく、エラーメッセージを確認するわけですが、
path.existsSync is deprecated. It is now called `fs.existsSync`.

sys.js:1
throw new Error(
      ^
Error: The "sys" module is now called "util".
    at sys.js:1:69
    at NativeModule.compile (node.js:585:5)
    at Function.require (node.js:553:18)
    at Function._load (module.js:297:25)
    at Module.require (module.js:362:17)
    at require (module.js:378:17)
    at Object. (/Users/kyama/xxx/xxx/.../xxx/Cakefile:4:9)
    at Object. (/Users/kyama/xxx/xxx/.../xxx/Cakefile:8:4)
    at Module._compile (module.js:449:26)
    at Object.run (/Users/kyama/.node/v0.7.9/lib/node_modules/coffee-script/lib/coffee-script/coffee-script.js:79:25)
とのこと。

おや?
どうやら6行目のメッセージによると "sys" は "util" に変わっているようです。

ということで、書き直して↓
util = require 'util'

util.puts 'Heloi, word.'

結果は↓
path.existsSync is deprecated. It is now called `fs.existsSync`.
Heloi, word.
Cakefile defines the following tasks:
    

結局 sys を util に変更することで事なきを得たという実にくだらないお話でした。
これで自分の環境が原因だったら更にくだらない…

2012年5月3日木曜日

アラインメントの罠

大型連休っていいですね!!

ということで日がな一日好きなコードを書き続けています。こんばんは。
ちょっと勉強がてら、OpenCVでカメラからキャプチャした画像をOpenGLで描画しようとして、またしてもハマったのでメモ。

やろうとしたこと

冒頭にも書いた通り、今回はOpenCVで読み込んだ画像をOpenGLで出力-CPPのようなことをやろうとしてました。
他にも類似の記事はたくさん引っかかったので、すぐできるだろー、と思いコードを書くことに。

方針としては、cvQueryFrame()を使ってIplImageを取ってきて、それを毎回glDrawPixels()に渡して描画する、という流れを考えてました。

結果

うまくいきませんでした……orz

cvQueryFrame()で取れた画像をglDrawPixels()に直接渡して描画*1しようとした結果が以下です。

どうしてこうなった……(´・ω:;.:...

原因

設定がおかしいのかとも思いましたが、結局、正しいデータを渡せていないことが原因でした。
cvCreateImage()で作ったIplImageにcvQueryFrame()で取れたIplImageのデータを「ちゃんと」コピーすることで、期待通りの動作をするようになります。

具体的には以下のようにコピーすることでうまく動作しました。
    // _pFrameはcvQueryFrame()で取得したIplImage
    // frameはcvCreateImage()で作成したIplImage↓
    // IplImage *frame = cvCreateImage( cvSize( _pFrame->width, _pFrame->height ), IPL_DEPTH_8U, 3);
    for (int y = 0; y < frame->height; y++) {
        for (int x = 0; x < frame->width; x++) {
            frame->imageData[frame->widthStep * y + x * 3] =
                    _pFrame->imageData[_pFrame->widthStep * y + x * 3];
            frame->imageData[frame->widthStep * y + x * 3 + 1] =
                    _pFrame->imageData[_pFrame->widthStep * y + x * 3 + 1];
            frame->imageData[frame->widthStep * y + x * 3 + 2] =
                    _pFrame->imageData[_pFrame->widthStep * y + x * 3 + 2];
                    
        }
    }

実行結果↓

どうやらcvQueryFrame()で取得できるIplImageには、各行ごとにパディング用の領域が確保されていて、その領域をOpenGLが読み飛ばせずにおかしな描画をしていたようです。
実際、cvQueryFrame()で取れたIplImageとcvCreateImage()で作ったIplImageのwidthStepを見ると、それぞれ、

  • cvQueryFrame()のIplImage->widthStep = 2560 (= 640 * 4)
  • cvCreateImage()のIplImage->widthStep = 1920 (= 640 * 3)

(※ともにwidth=640, nChannels=3)
となっており、確かに余計な領域が入っていることが確認できました。

そんなわけで、cvQueryFrame()でキャプチャした画像を直接OpenGLに渡す場合には気をつけましょうね!




……と、ここまで書いて気づきました。



cvCopy()一発でいけるんじゃ……?



ということで、forループを2周してコピーしている部分を以下のように書き変えました。
    cvCopy(_pFrame, frame);

で、結果↓


……まぁすっきりしたからよしとしましょう!!

結論

  • cvQueueFrame()で取得したIplImageをglDrawPixels()に渡す際は、一度cvCopy()でコピーしておくと良い
  • 変なコードを書く前に調べる


  • *1:cvCloneImage()してコピーした画像を渡したりもしてみた

2012年5月1日火曜日

SBJsonでの自作クラスJSON化

最近色々動けていなかった鬱憤を晴らすかのように2本目です。

何の因果か、ここのところiOSの開発もできるようにならないといけなくてお勉強したりしているわけですが、ちょっとライブラリを使うときにハマったので、軽くがっつりメモしておきます。

iOSでJSON文字列を生成する

google先生によると、どうやらiOSでJSONを使う場合、SBJsonというライブラリを使うのが一般的な様子。
昔はJson.frameworkと呼ばれていたようですが、いまはSBJsonとなっているそうです。

で、2012/05/01現在、SBJsonの最新バージョンは3.1になっていました。
トップページのAPI DocumentationにはVersion 3.1(Alpha)と書かれていますが、githubを見てみるとひと月前くらいにアップデートされているみたいですね。
ちなみに3.0と3.1の差異はARC対応しているかどうかだそうです→http://d.hatena.ne.jp/paraches/20120115/1326650073

ひとまずgithubからバージョン3.1のzipを落としてきて展開します。


インストールの方法はいくつかあるらしいのですが、他でも紹介されているようにソース一式をプロジェクトに追加しました。


これで準備は完了したので、後はコードを書いていきます。

必要なところで#import "SBJson.h"すれば、すぐにパーサが使えるようになるようです。
文字列をオブジェクトに変換するクラスはSBJsonParserで、このクラスのobjectWithStringなどを使うといい感じに変換してくれます。

んで、例えば↓
 [
  {
     "name":"google",
     "url":"www.google.com"
   },
   {
     "name":"yahoo",
     "url":"www.yahoo.com"
   }
 ]
のようなJSON文字列をパースしてオブジェクト化する場合のコードが↓↓
    SBJsonParser *parser = [[SBJsonParser alloc] init];
    NSError *error = nil;
    // jsonStrにJSON文字列が入ってます
    NSArray *resultList = [parser objectWithString:jsonStr error:&error];
    if ( error ) {
        NSLog(@"parse error: %@", jsonStr);
    } else {
        NSLog(@"%@", resultList);
    }
です。

これを実行してみると、
 (
    {
        name = google;
        url = "www.google.com";
    },
    {
        name = yahoo;
        url = "www.yahoo.com";
    }
 )
という感じの出力が得られるはずです。

逆に、配列などをJSONにしたい場合はSBJsonWriterを使います。
例えば、
    SBJsonWriter *writer = [[SBJsonWriter alloc] init];
    NSMutableDictionary *dstDict = [NSMutableDictionary dictionaryWithCapacity:100];
    [dstDict setObject:[NSNumber numberWithDouble:123.27] forKey:@"latitude"];
    [dstDict setObject:[NSNumber numberWithDouble:74.027] forKey:@"longitude"];
    [dstDict setObject:[NSNumber numberWithDouble:0.0001] forKey:@"accuracy"];
    error = nil;
    jsonStr = [writer stringWithObject:dstDict error:&error];
    if ( error ) {
        NSLog(@"parse error: %@", dstDict);
    } else {
        NSLog(@"%@", jsonStr);
    }
のようなコードを実行すると、
{"longitude":74.027000000000001,"latitude":123.27,"accuracy":0.0001}
という文字列を返してくれます。

自作クラスをSBJsonWriterに引数として直接渡す

前フリが長かったですが、ここからが本題です。
SBJsonWriterを使ってJSON文字列を作成する場合、stringWithObjectを使うことになります。
このとき、引数として渡すオブジェクトはなんでもいいのですが、基本的にはNSArrayかNSDictionaryしか渡すことができません。
自作クラスのオブジェクトも渡せますが、普通に渡すとエラーが返ってきます。
しかしどうにかして自作クラスを直接渡したい。

ということで軽くソースを眺めてみると、SBJsonStreamWriter.hの41行目以降に書いてありました。
 If you have a custom class that you want to create a JSON representation for you can implement this method in your class. It should return a representation of your object defined in terms of objects that can be translated into JSON. For example, a Person object might implement it like this: 
 @code
 - (id)proxyForJson {
        return [NSDictionary dictionaryWithObjectsAndKeys:
        name, @"name",
        phone, @"phone",
        email, @"email",
        nil];
 }
 @endcode
ということで、proxyForJsonメソッドを実装すれば良いそうです。

で、実際に実装してみた結果が以下。

MyClassSample.h
@interface MyClassSample : NSObject

@property (nonatomic, strong) NSString *name;
@property (nonatomic) uint age;

- (id)proxyForJson;  // SBJsonを使用して任意のオブジェクトをjsonにする場合,このメソッドを実装する必要がある
@end
MyClassSample.m
#import "MyClassSample.h"

@implementation MyClassSample

@synthesize name;
@synthesize age;

- (id) proxyForJson {
    return [NSDictionary dictionaryWithObjectsAndKeys:
            name, @"name",
            [NSNumber numberWithUnsignedInt:age], @"age", 
            nil];
}

@end
呼び出し側
    MyClassSample *obj1 = [[MyClassSample alloc] init];
    obj1.name = @"name1";
    obj1.age = 21;
    
    error = nil;
    jsonStr = [writer stringWithObject:obj1 error:&error];
    if ( error ) {
        NSLog(@"parse error: %@", obj1);
    } else {
        NSLog(@"%@", jsonStr);
    }
実行結果
{"age":21,"name":"name1"}

ということで、無事に自作クラスをJSON化できました。
ちなみに、自作クラスをNSDictionaryに追加してもちゃんと動作して、
呼び出し側
    MyClassSample *obj1 = [[MyClassSample alloc] init];
    MyClassSample *obj2 = [[MyClassSample alloc] init];
    obj1.name = @"name1";
    obj1.age = 21;
    obj2.name = @"name2";
    obj2.age = 42;
    NSDictionary *userMap = [NSDictionary dictionaryWithObjectsAndKeys:
                             obj1, @"user1", 
                             obj2, @"user2", 
                             nil];
    
    error = nil;
    jsonStr = [writer stringWithObject:userMap error:&error];
    if ( error ) {
        NSLog(@"parse error: %@", userMap);
    } else {
        NSLog(@"%@", jsonStr);
    }
実行結果
{"user2":{"age":42,"name":"name2"},"user1":{"age":21,"name":"name1"}}

という感じになり、こちらも無事にJSON文字列を取ってくることができました。

GLMetaseqとHandyARを使ってみる その0

3日坊主にだけはするまいと思っていたにも関わらず、約一月ぶりの更新です。
こんばんは。
まだまだ仕事のコントロールが出来ない若造でございます。

さて、前回までにHandyARで手のひらを検出するところまで行ってましたが、ちまちま作業をしていた結果、ひとまずミクさんが手のひらに乗ってくれるところまで到達↓

※3Dモデルは――innoce――さんのLat式ミクさんをお借りしました。

タイトルにもありますが、3Dモデルの読み込みにGLMetaseq(元記事)というライブラリを使用し、読み込んだデータをHandyARで検出した座標系を使って表示、という流れになっています。
どう見ても二番煎じです。本当に(ry

で、このあとどうするかが問題で、

  1. アニメーションを適用する
  2. 手の検出精度を上げる
  3. ぜんぜん違うことやる

と3つくらい考えてます。
個人的にはアニメーションが結構ややこしそうなので、手の検出精度を上げるか、ぜんぜん違うことやり始めようかなーと思ってたりします。
が、あんまり決めてなかったりするのでどうなるかは不明です。

ちなみに実装でハマったところとかそのへんは近日中に書くと思います。
GLMetaseq付属のサンプルは画面描画のときにメモリリークしてる気がしたりとか…ね…

2012年4月7日土曜日

Macでのlibjpegとかlibpngとか

凄まじくハマったので、忘れないように(AND 追加の問題発生時の対応用に)メモ。
試行錯誤しながらやったので、細かい部分は曖昧です。

(2012/07/25追記)
下記の内容をまとめました→(続・Macでのlibjpegとかlibpngとか
お急ぎの方ははまとめをご覧下さい。


何をしようとしたか

そもそもの発端は、前回までの続きとしてミクさんをプログラム的に呼び出す方法を調べていたことでした。
んで、工学ナビさんが急募してたのでMacでGLMetaseqを使ってみたとか、「ARToolKitで初音ミク」をやってみようといったエントリを参考に、環境構築をしていたわけです。
最初は順調だったんですが、工学ナビさんが急募してたのでMacでGLMetaseqを使ってみた(続き)に書かれているpng対応などを追加したあたりから雲行きが怪しく…。

最初作っていた環境はMacports経由で色々インストールしていたので、状況は全く同じはずだったんですが、なぜか実行時に"symbol not found"などと怒られ、一切実行できなくなってしまいました。

libjpeg.dylibとかlibpng.dylibのあるディレクトリにはパス通してました*1し、原因が一切思いつかないので、とりあえず最近流行りらしいし、パッケージ管理をMacportsからhomebrewに変えようと思い、一式アンインストールして入れなおすという暴挙に。

続く迷走

暴挙に出た結果としては、そもそもコンパイルすら通らなくなる有様*2…。
この辺からよく分からなくなって、brewがインストールするときに張るシンボリックリンクをImageIO.frameworkの下にいるlibjpeg.dylibとかに張り替えるとか、挙句OSのクリーンインストールまでやる始末。
また、OpenCVの中でlibjpegとか呼んでるのが悪いんじゃないかと考えて、ImageIO.frameworkの配下にいるライブラリを叩くように修正しようかと、訳のわからないことをやろうとしたりで、大迷走。

ライブラリの読み込み順

たださすがにOpenCV自体をいじるのはコスト的に美味しくないので、どうにかならないかと調べていたら、以下のエントリがまさに答えを示していました。

MacPorts のために DYLD_LIBRARY_PATH を使ってはいけない理由

曰く、
Macではランタイムライブラリの検索順序について、「man 1 dyld」 で確認することができます。
曰く、以下の順序で検索されます。
1. DYLD_LIBRARY_PATH
If it still can’t find the library, it then searches DYLD_FALLBACK_FRAMEWORK_PATH and DYLD_FALLBACK_LIBRARY_PATH in turn.
2. DYLD_FALLBACK_FRAMEWORK_PATH
By default, it is set to /Library/Frameworks:/Network/Library/Frameworks:/System/Library/Frameworks
3. DYLD_FALLBACK_LIBRARY_PATH
By default, it is set to $(HOME)/lib:/usr/local/lib:/lib:/usr/lib.
とのこと。

デフォルト状態ではDYLD_LIBRARY_PATHは設定されていないので、IDEなどで明示的に設定しない場合のライブラリ検索順序は、

  1. /Library/Frameworks:/Network/Library/Frameworks:/System/Library/Frameworks
  2. $(HOME)/lib:/usr/local/lib:/lib:/usr/lib

となるはず。
Macportsを使っていたときは、/opt/local/libの下にライブラリ一式がいたので意味がなかったのですけど、homebrewは/usr/local/libにライブラリ一式を追加してくれてます。

…ということで、これまで自力でライブラリパスを通していたのが実は裏目に出ていたようです。
これで、libjpegまわりのエラーはなくなりました。

で、libpngについてですが、homebrewの管理から外れているということは承知の上で、brew search libpngを実行したところ、こんなメッセージが。
Apple distributes libpng with OS X, you can find it in /usr/X11/lib. However not all build scripts look here, so you may need to call ENV.x11 in your formula's install function.
…おや?
そう、なにもサードパーティのlibpngを入れるまでもなく、最初から入ってたんですね。
もちろんヘッダファイルも/usr/X11/includeにしっかりいました。

で、/usr/X11/libはどこにもパス指定されていないので、コンパイル時には指定しないとダメなはずですが、今回はNetBeansがよしなに計らってくれているようで*3、うまいことできてました。
自分のために、ライブラリパスを明示的に設定しない場合と設定した場合に実行されたコマンドを貼っておきます。


  • 設定しない場合(うまく実行できる)
gcc     -framework GLUT -framework OpenGL -L/usr/X11/lib -o dist/Debug/GNU-MacOSX/glmetaseq_test build/Debug/GNU-MacOSX/_ext/2091976640/GLMetaseq.o build/Debug/GNU-MacOSX/_ext/2091976640/main.o -ljpeg -lpng
  • 設定した場合(実行できない)
gcc     -framework GLUT -framework OpenGL -L/usr/X11/lib -o dist/Debug/GNU-MacOSX/glmetaseq_test build/Debug/GNU-MacOSX/_ext/2091976640/GLMetaseq.o build/Debug/GNU-MacOSX/_ext/2091976640/main.o -L/usr/X11/lib -ljpeg -lpng
オブジェクトファイルの後ろで-Lオプションつけると何が変わるんでしたっけ…?


(2012/4/8追記)
上記/usr/X11/libへのパスですが、自分で強引に設定していたのを忘れていました…。
プロジェクトのプロパティー→構築→リンカーとたどって、普通は「追加のライブラリディレクトリ」としてパスを設定すると思いますが、今回は「追加のオプション」に -L/usr/X11/lib を追加することでうまくいっていました。(=明示的に設定している)
ただ、やっぱりオブジェクトファイルのあとで-Lオプションつけるのと何が違うのか、さっぱりです。

…動いたからよしとしましょう。

結論

今回の結論としては、

  1. デフォルトで検索されるライブラリパスはいじらないほうが吉
  2. いじる必要がある場合、他のものに出る影響を最小化するために、DYLD_FALLBACK_LIBRARY_PATHへ追加する

といったところでしょうか。
本来ならもっとスマートに解決できそうに思いますが、どうもこのへんが限界です

先のエントリの結論にも書かれてますが、こういうのは「既存ソフトウェアに影響があるので、新規ライブラリ (ports で入れたライブラリ等) はデフォルトライブラリの後で読み込むようにしましょう。」この一言につきますね。



…しかしOpenCVと組み合わせたらまた問題が出そうな気がしますね、コレ。

  • *1:これがそもそもの間違い
  • *2:こっちもシンボル見つからない系のエラーを吐いてた
  • *3:こういう姿勢がもう色々とダメ

2012年4月6日金曜日

MacBookAir(10.7 Lion)でHandyAR その3

今のところLionだからという感じの問題に遭遇していないので、タイトルが釣りっぽいなーと思ったりしながらの3日目です。

ということで今日は前回の続きということで、固まっている原因はどこか、ソースコードを確認していきたいと思います。


先に結論

とりあえず先に結論だけ書いてしまうと、固まっているように見えたのは、前処理にものすごい時間がかかってただけでしたw
ということで、無事動くまでの経緯を…。

困ったときのprintfデバッグ

まずはどこまで無事に動作するかを確認するため、ひたすらprintf()デバッグを敢行しました。
なぜかNetBeansのデバッガが使えなかったので

すると、HandRegion.cppのloadSkinColorProbTable()ってところがどうも怪しいのでよーく確認すると、

51行目〜
        printf("making a lookup table for skin color distribution ");
        _SkinColor.MakeLookUpTable();
        printf("done\n");

この部分で止まっているようです。
ということでMakeLookUpTable()を探してみると、MixGaussian.cppにあったので、中を覗くと…、

118行目〜
void MixGaussian::MakeLookUpTable()
{
    CvMat * SampleMat = cvCreateMat( 3, 1, CV_64FC1 );

    for ( int R = 0 ; R < 256 ; R ++ )
    {
        printf(".");
        for ( int G = 0 ; G < 256 ; G ++ )
        {
            for ( int B = 0 ; B < 256 ; B ++ )
            {
                cvSetReal1D( SampleMat, 0, (double)R );
                cvSetReal1D( SampleMat, 1, (double)G );
                cvSetReal1D( SampleMat, 2, (double)B );

                _Probability[R][G][B] = GetProbability( SampleMat );
            }
        }
    }
    
    cvReleaseMat( &SampleMat );
}

3重ループかー…
どうもここの計算に時間を取られていたようです。
しかもprintf(".")って、改行コード出してないからインジケータとしての意味が無いですし…。

そんな訳で、インジケータをわかりやすく(R=20ごとに改行)変更したところ、無事に動いていることが確認でき…、


てない…orz
コードを確認すると、上の処理の直後にnonskin.mgmというファイルを読んでいるのですが、追加されてませんでした。
なので、nonskin.mgmファイルを追加した後、改めて実行。

そして待つことしばし…



動いた!!!(・∀・)
でも上下反転してますね…(;´∀`)

付属のドキュメントを見ると、flipオプションというのがあり、
-  [-filp]: flip video images vertically. (Default=don’t flip)    
とのこと。

なので、実行時に -flip を渡して再度実行…、


ktkr!!!


ということで、ひとまずMacでも動くことが確認できたので、次回はミクさんに登場して頂けるように頑張りましょうw

2012年4月4日水曜日

MacBookAir(10.7 Lion)でHandyAR その2

ということで2日目です。
昨日はコンパイル通ったところまで確認できたので、今日は実際に動かしてみましょう!

実行ファイル作成

とりあえずmain書かないとお話にならないので、まずはそこからいきます。
とはいえ何も参考にしないで書ける訳がないので、デモに入っているmain.cppを覗いてみます。

…なんかそのまま使えそうなので、使ってしまいましょう。
てい。



案の定、エラー出ませんでした。
引き続き、インクルードしているヘッダ(main.h、bunny/inc/bunny.h)をすべて追加すれば準備が完了です。
実行ファイルを作りましょう。
といってもNetBeansにお任せなので、必要なパスを通して依存関係書いておけばあとは勝手に…


はいエラーw
昨日の段階でコンパイルできてたってのは幻想だったんですねーwww

…やっぱりソースの修正は必要なようです。

エラー吐いたファイルはFingertipTracker.cppだそうなので、中を見てみましょう。
エラーの箇所はこんな感じでした。

684行目〜
    if ( nPoints < NUM_FINGERTIP )
    {
        _fDetected = false;
        _nFingertips = 0;
        _nPoints = 0;
        goto Finished;
    }

772行目〜
Finished:

    //
    // Update Mode
    //
    if ( _fDetected )
    {
        _nMode = MODE_FINGERTIP_TRACKING;
    }
    else
    {
        _nMode = MODE_FINGERTIP_LOST_TRACKING;
    }

    return _fDetected;

goto文って使ってる人いたんだ、とか思いつつ、文法的には合ってるっぽいので何故にエラーが出たのかもよくわからず。

軽くぐぐってみると、どうもMac特有のエラーらしいので、goto文を使わないように修正します。
幸い、単純にエラー時の終了処理のためだけに使われているようなので、772行目以降のif文をメソッドに閉じ込めて、684行目のif文に入ったらそのメソッドを呼び出して即returnするようにしましょう。

ということで、修正後のコードは以下になります。
684行目〜
    if ( nPoints < NUM_FINGERTIP )
    {
        _fDetected = false;
        _nFingertips = 0;
        _nPoints = 0;
        updateMode();

        return _fDetected;
    }
772行目〜
    //
    // Update Mode
    //
    updateMode();

    return _fDetected;
どちらもupdateMode()というメソッドがいきなり出てきてますが、これは以下のように定義しています。

void FingertipTracker::updateMode() {
    if ( _fDetected )
    {
        _nMode = MODE_FINGERTIP_TRACKING;
    }
    else
    {
        _nMode = MODE_FINGERTIP_LOST_TRACKING;
    }
}
単にif文をメソッド化しただけ。

ということで再度ビルドしてみますが、今度はFingertipPoseEstimation.cppからエラー…
ただしこちらもgoto文関係のエラーなので、まずは関連しているラベルを確認。

209行目〜
Finished:

    return fResult;

…goto文をすべて消して、直後に全く同じreturn文を書くことで対処しました。

改めてビルドすると今度こそ…
成功!
無駄に長かったですねー…

実行してみる

はやる心を抑えつつ、早速実行してみます。


あ。


(ノ∀`)アチャー

ダメでした。
しかしエラーログ見る限り、必要なファイルが無いだけのようなので、これをプロジェクトルートに追加します。
一応、念のために必要そうなファイルはすべて追加しておきましょう。


気を取り直して再度実行します。


とりあえずエラーは出てませんし、カメラにもアクセスできている風なんですが、全然ウィンドウが表示される気配が無いです…


ということで、困ったときのアクティビティモニタ。


応答なしwww
こらダメだwwwww

中身に踏み込…もうとする

このままではどうしようもないので、頑張ってソースを読むことにします。



…が、今日は疲れたので明日の自分に期待!!

2012年4月3日火曜日

MacBookAir(10.7 Lion)でHandyAR その1

色々やろうやろうと思いつつ、気づけば数ヶ月…。
最近になってようやく仕事が一段落してきたので、いざ!ということで、やりたかったことをガシガシ進めていきます。

そんなわけでしばらくの間、タイトルの通り、LionでHandyARを動かしていきます。
当面の目標としては、このへん↓
HandyARで初音ミクが手のひらの上でウッーウッーウマウマ(゚∀゚)
を目指しておきます。
今更感が漂いすぎててアレなところはスルーで
イケそうならiPhoneでも動かしてみようと思います。

ホントはPTAMあたりを使おうかなと思ってたんですが、64bit環境だとインストールが非常に手間みたいなので、今回はHandyARを採用する方向でいきます。

HandyARの入手

HandyAR自体はいろんな方が解説されてますので、詳細は割愛しますが、カリフォルニア大のTaehee Leeという方たちが作った手法だそうです。

ソースコードの入手自体は、彼らのページから可能です。
ページ下部の"Source Code"に"HandyAR Verx.x"というリンクがあるので、そこからzipを落とすだけでOK。
おそらく"HandyAR-verx.x.zip"みたいなファイルがDLできるはずです。

とりあえず解凍してみると、なんかいろいろ入ってました。

入ってますが、今回用があるのは DemoHandyAR/DemoHandyAR/HandyAR/ 以下のファイル群になると思いますので、ここのファイルをごちゃごちゃいじっていきます。

とりあえずコンパイルしてみる

何もせずに動くならそれに越したことはないので、とりあえずコンパイルできる状態へ持っていきます。
なお、今回は個人的な趣味によりNetBeansで色々いじっていきます。

まずは HandyAR/ 以下のファイルを、ディレクトリごとプロジェクト直下にコピーしてきます。
また、上では HandyAR/ 以下だけで大丈夫そうと書きましたが、一応 ARTag/ と Capture/ もコピーしておきます。

コピーが済んだので、インクルードパスを通して、適当なファイルを開いてみると…


おや?

エラーがたくさんある上にインクルード文からも警告が…

インクルードファイル開くと…

 global.hも必要ですか…orz
ということでこれもコピー。
そして再度確認!


今度はglobal.h内部がおかしいようです。
global.hの中を覗くと…


OpenCVとglut関係でエラー吐いてます。
ただ、現時点で自分の環境にインストール済みのOpenCVはバージョン2.3なのですが、このヘッダ指定はどう見ても1.xのそれなので、激しく中身を書き換えたい衝動に…
ついでにデモ用に書かれたであろうヘッダ(cvFindExtrinsicCameraParams3.h)まであるので、うーんって感じです。

なんですが、今日はコンパイルさえ通ればよいので、バージョン古くても問題なし。
早速インクルードパスをOpenCVとglutに通し、cvFindExtrinsicCameraParams3.cpp/.hをプロジェクト直下に追加。
さらに再度確認。



ということで、無事通りました。
残りのファイルもエラー出てないな…



…と思ってたら、


エラーだらけ…orz
Capture/ 以下のFlyCap.cpp/.hがどうも他のライブラリに依存しているような感じですね。

ここで、同梱されていたドキュメント(DemoHandyAR Documentation.pdf)を読んでみると、

 Capture/
- In this directory, Capture.h and cpp files are used to capture video from a camera using OpenCV functions (and PointGrey’s SDK). In order to use PointGrey’s SDK, you need to include FlyCap.h and cpp files in the same directory into your VC++ project.
Capture/
- このディレクトリには、OpenCV(とPointGrey's SDK)を利用し、カメラからビデオキャプチャを行うために必要なCapture.h と cppファイルがあります。PointGrey's SDKを使うには、同じディレクトリのFlyCap.h と cppファイルをVC++プロジェクトに追加する必要があります。

とのこと。

ひとまずキャプチャはOpenCVだけで十分だと思いますので、上で出たエラーは無視できるようですね。
というか、調べてみるとPointGrey's SDKと言っているのは、FlyCapture SDKというものらしいんですが、どうもMacOSには対応してないみたいです。
なのでいずれにせよ上記のエラーは無視するしかないようです。南無。



なにはともあれ、これでようやく全体のコンパイルが終了(2012/4/4追記:全然コンパイルできてませんでしたw 詳細はその2へ)ということで、次回は実際に何か動かすところまで持っていこうとおもいます。
そういえばHandyARのライセンス関係ってどうなってるんだろう