ARDeskTop上で動画再生(その2)
OpenCVのcvCaptureFromFile関数では動画の音声トラックは再生されないので、試しにDirectShowでも同時に再生してみた。まあ、あたりまえだが、そのままでは音と映像がズレてしまう。
で、DirectShowのGetPositions関数で現在の再生位置を取得して、それに合わせて動画を再生してみた。
同期成功!
ちなみに、FLV Splitterをインストールするとfpsが30くらいまでのならflvファイルがDirectShowでも再生できるようになる。
http://www.gigafree.net/media/codec/flvsplitter.html
あとは、このままではDirectShowの別ウインドウでも動画が再生されてしまうので、音声のみを再生できるようにすれば終了。
int CCVVideoManager::Animate(void) { if(!capture) return(1); if(!CAnimeManager::Animate()) return(1); int n; if(fps > 40.0f) { if(elapsedTimeMS * fps < counter) return(1); n = elapsedTimeMS * fps - counter + 1; } else { //DirectShowから現在の再生位置を取得して何フレーム進めるか決める LONGLONG pCurrent, pStop; pMediaSeeking->GetPositions(&pCurrent, &pStop); float current = pCurrent * 0.0000001; if(current * fps < counter) return(1); n = current * fps - counter + 1; } IplImage* image; for(int i = 0; i < n; i++) { image = cvQueryFrame(capture); if(!image) { Stop(); return(0); } } counter += n; if(!frame) frame = cvCreateImage(cvSize(image->width / 3, image->height / 3), IPL_DEPTH_8U, 3); cvResize(image, frame, CV_INTER_CUBIC); ((CCVPicture*) component)->SetTexture(image); return(0); } bool CCVVideoManager::OpenVideoFile(wchar_t* pFileName, double size) { char cFileName[256]; setlocale(LC_ALL, "ja"); wcstombs(cFileName, pFileName, 256); //OpenCV capture = cvCaptureFromFile(cFileName); if(!capture) { return(false); } fps = (float) cvGetCaptureProperty(capture, CV_CAP_PROP_FPS); //DirectShow if(fps <= 40.0f) { IMediaPosition* pMediaPosition; //DirectShowの初期化は本当はここでやったらダメだろうな。 CoInitialize(NULL); CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC, IID_IGraphBuilder, (LPVOID*) &pGraphBuilder); pGraphBuilder->QueryInterface(IID_IMediaControl, (LPVOID*) &pMediaControl); pGraphBuilder->QueryInterface(IID_IMediaPosition, (LPVOID*) &pMediaPosition); pGraphBuilder->QueryInterface(IID_IMediaSeeking, (LPVOID*) &pMediaSeeking); pGraphBuilder->RenderFile((BSTR) pFileName, NULL); //再生時間取得 REFTIME length; pMediaPosition->get_Duration(&length); animetionTimeMS = (float) length; pMediaPosition->Release(); pMediaControl->Run(); } else { //DirectShowでは再生不可能 animetionTimeMS = 1000.0f; //適当 } Play(); Animate(); return(true); }
参考サイト:
Geekなぺーじ : DirectShowプログラミング [VC++]
http://www.geekpage.jp/programming/directshow/
ARDeskTop上で動画再生
OpenCVの動画再生関数cvCaptureFromFileを使用してARDeskTop上で動画を再生してみた。とは言え、dandelion氏の協力なくしてはすんなりコーディングはできなかったであろう(本当にありがとうございます)。
CAnimeManagerクラスから動画再生用にCCVVideoManagerクラスを派生させて処理する。同期を取るために何フレームかは飛ばしたり、何もしなかったりする。
OpenCVのみなのでまだ音は出ない。
int CCVVideoManager::Animate(void) { if(!capture) return(1); if(!CAnimeManager::Animate()) return(1); if(elapsedTimeMS * fps < counter) return(1); IplImage* image; int n = elapsedTimeMS * fps - counter + 1; for(int i = 0; i < n; i++) { image = cvQueryFrame(capture); if(!image) { Stop(); return(0); } } counter += n; if(!frame) frame = cvCreateImage(cvSize(image->width / 3, image->height / 3), IPL_DEPTH_8U, 3); cvResize(image, frame, CV_INTER_CUBIC); ((CCVPicture*) component)->SetTexture(image); return(0); } bool CCVVideoManager::OpenVideoFile(wchar_t* pFileName, double size) { char cFileName[256]; setlocale(LC_ALL, "ja"); wcstombs(cFileName, pFileName, 256); capture = cvCaptureFromFile(cFileName); if(!capture) { return(false); } fps = (float) cvGetCaptureProperty(capture, CV_CAP_PROP_FPS); animetionTimeMS = 1000.0f; Play(); Animate(); return(true); }
ただOpenVideoFile関数内でPlayとAnimate関数入れておかないとうまく実行できない。
OpenCVで色認識
OpenCVのサンプルをいじって簡単な色認識を作ってみた。
大まかな処理の流れ。
1.Webカメラの映像を画像として取り込む。
2.取り込んだ画像をRGBからHSVに変換する。
3.HSV色空間内の特定の範囲だけマスキングして表示する。
HSVの方が特定の色を抜き取りやすいらしい。
http://render.s73.xrea.com/pipe_render/2008/06/artoolkit-hsv.html
実行結果はこんな感じ。
#include#include void GetMaskHSV(IplImage* src, IplImage* mask,int erosions, int dilations) { int x = 0, y = 0; uchar H, S, V; uchar minH, minS, minV, maxH, maxS, maxV; CvPixelPosition8u pos_src, pos_dst; uchar* p_src; uchar* p_dst; IplImage* tmp; tmp = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 3); //HSVに変換 cvCvtColor(src, tmp, CV_RGB2HSV); CV_INIT_PIXEL_POS(pos_src, (unsigned char*) tmp->imageData, tmp->widthStep,cvGetSize(tmp), x, y, tmp->origin); CV_INIT_PIXEL_POS(pos_dst, (unsigned char*) mask->imageData, mask->widthStep, cvGetSize(mask), x, y, mask->origin); minH = 100; maxH = 115; minS = 80; maxS = 255; minV = 120; maxV = 255; for(y = 0; y < tmp->height; y++) { for(x = 0; x < tmp->width; x++) { p_src = CV_MOVE_TO(pos_src, x, y, 3); p_dst = CV_MOVE_TO(pos_dst, x, y, 3); H = p_src[0]; //0から180 S = p_src[1]; V = p_src[2]; if( minH <= H && H <= maxH && minS <= S && S <= maxS && minV <= V && V <= maxV ) { p_dst[0] = 255; p_dst[1] = 255; p_dst[2] = 255; } else { p_dst[0] = 0; p_dst[1] = 0; p_dst[2] = 0; } } } if(erosions > 0) cvErode(mask, mask, 0, erosions); if(dilations > 0) cvDilate(mask, mask, 0, dilations); cvReleaseImage(&tmp); } int main(int argc, char **argv) { int c; CvCapture* capture = 0; IplImage* frame = 0; IplImage* mask = 0; IplImage* dst = 0; if(argc == 1 || (argc == 2 && strlen (argv[1]) == 1 && isdigit(argv[1][0]))) capture = cvCreateCameraCapture(argc == 2 ? argv[1][0] - '0' : 0); frame = cvQueryFrame(capture); mask = cvCreateImage(cvSize(frame->width, frame->height), IPL_DEPTH_8U, 3); dst = cvCreateImage(cvSize(frame->width, frame->height), IPL_DEPTH_8U, 3); cvNamedWindow("src", CV_WINDOW_AUTOSIZE); cvNamedWindow("dst", CV_WINDOW_AUTOSIZE); while(1) { frame = cvQueryFrame(capture); GetMaskHSV(frame, mask, 1, 1); cvAnd(frame, mask, dst); cvShowImage("src", frame); cvShowImage("dst", dst); c = cvWaitKey(10); if(c == 'q') break; } cvDestroyWindow("src"); cvDestroyWindow("dst"); cvReleaseImage(&frame); cvReleaseImage(&dst); cvReleaseImage(&mask); cvReleaseCapture(&capture); return(0); }
参考にしたサンプルはこちら。
http://opencv.jp/sample/accumulation_of_background.html
http://chihara.naist.jp/opencv/?%BF%A7%BE%F0%CA%F3%A4%CB%A4%E8%A4%EB%CE%CE%B0%E8%C3%EA%BD%D0
テクスチャをOpenCVで読み込み
半透明オブジェクト
どうも、ARDeskTop開発者のわうわうふーわです。
ゆる〜く現状をブログにしていきます。
半透明のオブジェクトに描写は、そのときだけデプス処理をオフにしてやってるんですが、それだと後に描いたオブジェクトが奥にあろうが、手前に見えてしまう欠点があります。
で、どうにかならないかと思い、フレームの裏に透明なポリゴンを描くと言う手を思いつきました。
ただし、裏っかわにひっくり返すと変な感じになるし、透明ななのか透明じゃないのかよくわからない状態になります。
でも、前後の関係はよくわかるようになりました。
法線ベクトルと視線ベクトルの内積を計算して、どっち向いてるか計算もしてみようと思っています。