OpenCVとの戦い、カメラ画像を表示する最低限のコード
id:nyaxtさんからOpenCVを教えてもらってとりあえずニャンニャンしてみた。
ありがとう!!
とりあえずOpenCVのカメラ入力方法
OpenCVライブラリセットアップは↓
http://d.hatena.ne.jp/sakusan_net/20080625/1214371034
とりあえずカメラ画像をウインドウに表示する。
#include <stdio.h> #include <cv.h> #include <highgui.h> #include <ctype.h> int main () { CvCapture *capture = 0; IplImage *frame = 0; double w = 320, h = 240; int c; capture = cvCreateCameraCapture (CV_CAP_ANY); cvSetCaptureProperty (capture, CV_CAP_PROP_FRAME_WIDTH, w); cvSetCaptureProperty (capture, CV_CAP_PROP_FRAME_HEIGHT, h); cvNamedWindow ("Capture", CV_WINDOW_AUTOSIZE); // (3)カメラから画像をキャプチャする while (1) { frame = cvQueryFrame (capture); cvShowImage ("Capture", frame); c = cvWaitKey (10); if (c == '\x1b') break; } cvDestroyWindow ("Capture"); cvReleaseImage (&frame); return 0; }
cvCreateCameraCaptureの引数はカメラIDですが、上のコードではANYにしてとにかくカメラをみつけたら表示、となっています。
恒例の罠
あれですね。自分とりあえず片っ端から罠にはまってる気がします。
ここでの注意はこのコードからいらないと思って勝手に削らないこと
自分の場合、cvWaitKey(10) はエスケープでbreakをするためだけにあるものだと思い、最初に削ってしまいまして。そうするとウインドウがうまく表示されなかったり、フレームレートが異常に落ちたりします。
まず何も考えずにこのコードをコピペして走らせるのがいいと思います。
OpenCVとの戦い、とりあえずピクセルの情報を入手する。
↓の記事の最低限のコードのWhile部分のみを抜粋
http://d.hatena.ne.jp/sakusan_net/20080626/1214449256
while (1) { frame = cvQueryFrame (capture); cvShowImage ("Capture", frame); unsigned char **pimage = new unsigned char *[frame->height]; for(int i = 0; i < frame->height; i++){ pimage[i] = (unsigned char *)frame->imageData + i*frame->widthStep; } for (y = 0; y < frame->height; y++) { for (x = 0; x < frame->width; x++) { int r = pimage[y][x*3+2]; int g = pimage[y][x*3+1]; int b = pimage[y][x*3]; //ここらへんで適当に処理したりバッファしたりする } } delete pimage; c = cvWaitKey (10); if (c == '\x1b') break; }
とりあえずこれで指定ピクセルのRGBがintで取れる。
RGBさえ取れてしまえばあとは結構どうにでも使えるので便利
ちなみにその他のピクセルアクセス方法は以下を参照
http://opencv.jp/sample/basic_structures.html#access_pixels
行数は少なくまとめられてるけど読みにくいのが難
OpenCVとの戦い、動画にオプティカルフロー
カメラに写ったものの動作ベクトルをとるものです。
以下のアドレスに画像でのサンプルがあります。
http://opencv.jp/sample/optical_flow.html#optflowBM
恒例の罠
カメラの画像で使う場合には少々罠があるのでそれだけ記録しておきます。
とりあえずさんぷるのイメージの部分にそのままカメラの画像イメージを突っ込むと普通に怒られます。
原因は普通にcvQueryFrameでキャプチャをするとイメージのビット深度がIPL_DEPTH_8Uになっていないためです。
なので、新しいフレームをIPL_DEPTH8で作成し、キャプチャフレームからコンバートをかけます。
ここでのlframeは1フレーム前の比較用データです。
IplImage *frame8 = cvCreateImage(cvSize( w,h ),IPL_DEPTH_8U, 1); IplImage *lframe8 = cvCreateImage(cvSize( w,h ),IPL_DEPTH_8U, 1); cvConvertImage(frame,frame8); cvConvertImage(lframe,lframe8); cvCalcOpticalFlowBM (frame8, lframe8, block, shift, max_range, 0, velx, vely);
Whileの最後に
lframe = cvCloneImage (frame);
とかで、lframeに比較用フレームを保存しておきます。
あとは上で紹介した公式ページのサンプルとほとんど同じです。
・・・
ただ・・・
重い!!
くそおもい。
Core2DuoのマシンでFPsが0.5くらいしかでない。
正直使い物に以下略、って感じですよ。
OpenCVとの戦い、取り込みの高速化&&複数カメラからの入力。
id:nyaxtさんid:inajobさんありがとう!。
彼らからの情報提供で複数カメラ入力&高速化ができました。
そもそもの罠
まず経緯からお話しすると。
OpenCVはそのままだと複数台カメラのキャプチャがうまくいかないらしい。様々なサイトを見て回ったんだけどどうもうまくいかないとの記事ばかりでうまく取れている形跡がない。
そして、OpenCVはキャプチャが重いとの定評もあるらしい。(これは噂)
そこでid:inajobさんに以下の情報をいただきました。
内容としてはキャプチャだけDirectShowで行い、OpenCVで処理するというもの。
http://wikiwiki.jp/masayashi/?OpenCV%2FDirectShow%A4%C7%A5%AD%A5%E3%A5%D7%A5%C1%A5%E3%A4%B7%A4%BF%B2%E8%C1%FC%A4%F2%C9%BD%BC%A8%A4%B9%A4%EB
第一の罠
まず、DirectShow。
自分はインストールしてあったので怒られなかったが、もしstrmbasd.libやstrmbase.libで怒られた場合、これらはDirectShowでカメラを使うためのライブラリであるにも係らず自分でコンパイルする必要がある。
そしてたいていのサイトにはDirectXのSamplesフォルダに入っているとかいてあるが、これが大いなる罠。
DirectShowはDX9のどっかのタイミングでDirectX SDKからはずされMicrosoft Windows SDKに引越しをしている。
なのでMicrosoftWindowsSDKとかで検索をし、最新のものをインストールする必要がある。ちなみにCDイメージでの配布なので、焼くかヴァーチャルドライブで読む。
で、やっとこさDLLのコンパイルなわけですが。フォルダの階層が深い・・・
うちでは以下のフォルダにありました。が、ヴァージョンによってはちがうかも
..\Microsoft SDKs\Windows\v6.0\Samples\Multimedia\DirectShow\BaseClasses
コンパイル前に以下のフォルダをツールのオプションからインクルードパスに追加しておきましょう。
..\Microsoft SDKs\Windows\v6.0\Include
..\Microsoft SDKs\Windows\v6.0\Lib
これでコンパイルできればLIBファイルができるので、それを使います。
っていうか最初からいれとけよ!!!!!mjd
第二の罠
先程のDirectShowからキャプチャをし〜。のサンプルはewclibというヘッダを使っています。
以下作者のページ
http://www.geocities.jp/in_subaru/ewclib/index.html
ですが、先程のサンプルのままで最新のヘッダを使うと所々に問題が起こります。
あれです。仕様変更の罠ってやつです。
エラーが出つつ重要なのは DirectShow.cppの中にあるここ
EWC_Open(MEDIASUBTYPE_RGB24, capture_size_x, capture_size_y, FPS);
最新版ではこれの第一引数が省略され、defineでMEDIASUBTYPE_RGB32に決め打ちがしてあります。なので普通に第一引数を削るだけだと画像が全部二重になり、グレードットが並びます。
これはビット深度の違いなので、一番楽な直し方は
1、第一引数を削る。
2、ewclibの決め打ちされているMEDIASUBTYPE_RGB32をMEDIASUBTYPE_RGB24に打ち直す。
と、いったところです。
まあ、もうちょっとスマートな解決方法もあると思いますが、とりあえずこれで直ります。