Visual C++ 2008 Express Edition で動画再生と OpenCV との連携
MPEG-2 ファイルを処理したいが,OpenCV で読み込めない.DirectShow で 出来るらしいから試し,実際に出来た.事前にセットアップすべきは
表題の情報は DirectShowプログラミング [VC++]:Geekなぺーじ にまとまっている.手元の環境で
- MPEGファイルを再生する(RenderFile)
- 映像再生が終るまで待つ
の2件が成功した.リンカ入力に「strmiids.lib」を設定すること.
読み込んだ画像は OpenCV で処理したい.
http://www.eml.ele.cst.nihon-u.ac.jp/~momma/wiki/wiki.cgi/Windows/DirectShow/OpenCV%E3%81%A8%E3%81%AE%E7%B5%84%E5%90%88%E3%81%9B.html にサンプルがある.入力がカメラだったから Aspire One で試し,動くのを確認した.リンカ入力には「strmiids.lib cv.lib cxcore.lib highgui.lib」を設定した.dxtrans.h が無いというトラブル*1があるが,
- DirectX SDK November 2007にdxtrans.hが入っていない件について - DenpaFreak
- dxtrans.h missing in Microsoft DirectX SDK (November 2007)...
で解決できた.qedit.h をインクルードする直前に
#pragma include_alias( "dxtrans.h", "qedit.h" ) #define __IDxtCompositor_INTERFACE_DEFINED__ #define __IDxtAlphaSetter_INTERFACE_DEFINED__ #define __IDxtJpeg_INTERFACE_DEFINED__ #define __IDxtKey_INTERFACE_DEFINED__
を追記する.
コード全文
たった5行を追加しただけだが,コード全文を掲載する.
// 書籍「はじめての動画処理プログラミング」土井 滋貴 著 CQ出版 // http://www.cqpub.co.jp/hanbai/books/43/43001.htm // で公開されている // list604.cpp DirectShowを使ったキャプチャ ver1.1 // を利用 // // DirectShow対応デバイスからキャプチャしたビットマップをOpenCVで横取り // 当然Windows専用 // 変更者 Eiichiro Momma 2007/7/4 #include <windows.h> #include <dshow.h> #include <stdio.h> #include <conio.h> #pragma include_alias( "dxtrans.h", "qedit.h" ) #define __IDxtCompositor_INTERFACE_DEFINED__ #define __IDxtAlphaSetter_INTERFACE_DEFINED__ #define __IDxtJpeg_INTERFACE_DEFINED__ #define __IDxtKey_INTERFACE_DEFINED__ #include <qedit.h> // SampleGrabber用 #include <cv.h> #include <highgui.h> void main() { /*ここからDirectShow用の処理 設定をいじらないならブラックボックス扱いで良い*/ HRESULT hr; CoInitialize(NULL); // COMの初期化 // ---- キャプチャフィルタの準備 ---- // キャプチャデバイスを探す ICreateDevEnum * pDevEnum = NULL; IEnumMoniker * pClassEnum = NULL; IBaseFilter *pbf = NULL; IMoniker * pMoniker = NULL; ULONG cFetched; // デバイス列挙子を作成 CoCreateInstance( CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC, IID_ICreateDevEnum, (void ** ) &pDevEnum); // ビデオキャプチャデバイス列挙子を作成 pDevEnum -> CreateClassEnumerator( CLSID_VideoInputDeviceCategory, &pClassEnum, 0); if ( pClassEnum == NULL ){ printf("ビデオキャプチャデバイスは存在しません\n"); pDevEnum -> Release(); CoUninitialize(); return ; } // 最初に見つかったビデオキャプチャデバイスのオブジェクトの // インタフェースを得る pClassEnum -> Next(1, &pMoniker, &cFetched); pMoniker -> BindToObject( 0, 0, IID_IBaseFilter, (void**)&pbf ); pMoniker -> Release(); pDevEnum -> Release(); pClassEnum -> Release(); // ---- フィルタグラフの準備 ---- IGraphBuilder * pGraph = NULL; IMediaControl * pMC = NULL; // フィルタグラフを作り、インターフェースを得る CoCreateInstance( CLSID_FilterGraph, NULL, CLSCTX_INPROC, IID_IGraphBuilder, (void **) &pGraph); pGraph -> QueryInterface( IID_IMediaControl, (LPVOID *) &pMC ); // キャプチャフィルタをフィルタグラフに追加 pGraph -> AddFilter( pbf, L"Video Capture"); // ---- グラバフィルタの準備 ---- ISampleGrabber *pGrab = NULL; // これらは後で解放すること。 IBaseFilter *pF = NULL; AM_MEDIA_TYPE amt; // グラバフィルタを作る CoCreateInstance( CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (LPVOID *)&pF); pF -> QueryInterface( IID_ISampleGrabber, (void **)&pGrab ); // グラバフィルタの挿入場所の特定のための設定 ZeroMemory(&amt, sizeof(AM_MEDIA_TYPE)); amt.majortype = MEDIATYPE_Video; amt.subtype = MEDIASUBTYPE_RGB24; amt.formattype = FORMAT_VideoInfo; pGrab -> SetMediaType( &amt ); // グラバフィルタをフィルタグラフに追加 pGraph -> AddFilter(pF, L"SamGra"); // ---- キャプチャグラフの準備 ---- ICaptureGraphBuilder2 * pCapture = NULL; // キャプチャグラフを作る CoCreateInstance( CLSID_CaptureGraphBuilder2 , NULL, CLSCTX_INPROC, IID_ICaptureGraphBuilder2, (void **) &pCapture ); // フィルタグラフをキャプチャグラフに組み込む pCapture -> SetFiltergraph( pGraph ); // キャプチャグラフの設定、グラバをレンダリング出力に設定 pCapture -> RenderStream ( &PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, pbf, NULL, pF); // ビットマップ情報の取得 pGrab -> GetConnectedMediaType( &amt ); // ビデオ ヘッダーへのポインタを獲得する。 printf( "amt.lSampleSize = %d (byte)\n", amt.lSampleSize ); VIDEOINFOHEADER *pVideoHeader = (VIDEOINFOHEADER*)amt.pbFormat; // ビデオ ヘッダーには、ビットマップ情報が含まれる。 // ビットマップ情報を BITMAPINFO 構造体にコピーする。 BITMAPINFO BitmapInfo; ZeroMemory( &BitmapInfo, sizeof(BitmapInfo) ); CopyMemory( &BitmapInfo.bmiHeader, &(pVideoHeader->bmiHeader), sizeof(BITMAPINFOHEADER)); printf( "width = %d , height %d , color %d \n", BitmapInfo.bmiHeader.biWidth, BitmapInfo.bmiHeader.biHeight, BitmapInfo.bmiHeader.biBitCount ); printf( "キャプチャを開始します、どれかキーを押して下さい\n" ); getch(); /*ここまでDirectShow用の処理 設定をいじらないならブラックボックス扱いで良い*/ /*ここからOpenCVの処理*/ IplImage *frame = 0; IplImage *dstImage = 0; IplImage *baseImage = 0; //カラー24bitという前提 frame = cvCreateImage(cvSize(BitmapInfo.bmiHeader.biWidth, BitmapInfo.bmiHeader.biHeight),IPL_DEPTH_8U,3); dstImage = cvCreateImage(cvSize(BitmapInfo.bmiHeader.biWidth, BitmapInfo.bmiHeader.biHeight),IPL_DEPTH_8U,3); baseImage = cvCreateImage(cvSize(BitmapInfo.bmiHeader.biWidth, BitmapInfo.bmiHeader.biHeight),IPL_DEPTH_8U,3); cvNamedWindow("OpenCV",CV_WINDOW_AUTOSIZE); cvNamedWindow("Dst Image",CV_WINDOW_AUTOSIZE); /*ここまでOpenCVの処理*/ // ---- キャプチャ開始 ---- pMC -> Run(); // レンダリング開始 pGrab -> SetBufferSamples(TRUE); // グラブ開始 int nn = 0; // グラブ回数のカウント、意味はない int input=0; int fCount=1; char fname[2048]; while(1){ hr = pGrab -> GetCurrentBuffer((long *)&(BitmapInfo.bmiHeader.biSizeImage), // グラブ (long *)(frame->imageData) ); //<-ここで横取り cvFlip(frame,frame,0); //上下反転しているのでcvFlipで戻す if(nn == 1){ //初期背景画像 cvCopyImage(frame,baseImage); } cvSub(frame,baseImage,dstImage); //差分画像の作成 cvShowImage("Dst Image",dstImage); //差分の表示 cvShowImage("OpenCV",frame); //現在画像の表示 nn++; printf("グラブ hr = %x, n = %d\n", hr, nn ); input = cvWaitKey(100); //早過ぎると処理が間に合わない? switch(input){ case 'q': goto EXIT_WHILE; break; case 'b': //背景の更新 cvCopyImage(frame,baseImage); break; case 'c': //キャプチャ sprintf(fname,"frame%00d.jpg",fCount); cvSaveImage(fname,frame); sprintf(fname,"sub%00d.jpg",fCount); cvSaveImage(fname,dstImage); sprintf(fname,"base%00d.jpg",fCount); cvSaveImage(fname,baseImage); fCount++; break; } } EXIT_WHILE: /* ここからDirectShowの終了処理 */ // インターフェースのリリース pbf -> Release(); // キャプチャフィルタ用 pMC -> Release(); // フィルタグラフ用 pGraph -> Release(); pCapture -> Release(); // キャプチャグラフ用 pF -> Release(); // サンプルグラバ用 pGrab -> Release(); // COMのリリース CoUninitialize(); /*ここまでDirectShowの終了処理*/ //OpenCVの後片付け cvDestroyWindow("OpenCV"); cvDestroyWindow("Dst Image"); cvReleaseImage(&frame); cvReleaseImage(&baseImage); cvReleaseImage(&dstImage); }