注意
- 使用するカメラによってはエラーが発生するバグが確認されています。
参考のためソースは残しますが、動作を保障するものではありません。
新バージョンはこちらです→OpenCV/DirectShowでキャプチャした画像を表示する
説明
- OpenCVのカメラキャプチャの性能が若干不安定だったので、DirectShowからカメラを取得して、キャプチャしたバッファだけを貰ってきてOpenCVで動かす。
- (2006.12.21変更) IplImage* を返すようにした。
- 処理速度の検証のため、ループを一周するのにかかった時間を画面内に表示している。
- 結果として、キャプチャ速度に大幅な改善が見られた。原因は不明。
- 処理速度比較に関する第一段階 : 作業ログ/2006-12-17
スクリーンショット
コードに関するコメント
- DirectShowに関する処理は、DShowクラスで一括して管理する。
- 最小限の機能しか持たせていない。エラー処理もしていない。
- コンストラクタでキャプチャの幅と高さを指定し、その後 GetCaptureIplImage() 関数を用いてキャプチャ画像yを取得する。
- ときどきによって、キャプチャ画像が上下逆に取れたり、そのまま取れたりする。何の違いで起きている現象なのかわからないので、とりあえずどちらにも対応できるようにしておいた。(#ifdef REVERSE_IMAGEあたり)
- 実装にあたり、以下ページのソースを一部拝借しましたので、この場を借りてお礼申し上げます。
VisualStudioプロジェクトファイル
dshow.h
#ifndef _DSHOW_H
#define _DSHOW_H
//for DirectShow
#include <dshow.h>
#include <qedit.h>
#pragma comment(lib,"strmiids.lib")
//for OpenCV
#include <cv.h>
#include <highgui.h>
#pragma comment(lib,"cv.lib")
#pragma comment(lib,"cxcore.lib")
#pragma comment(lib,"cvaux.lib")
#pragma comment(lib,"highgui.lib")
// REVERSE_IMAGE ???`?????????A
// ?L???v?`???????o?b?t?@????????t????
#define REVERSE_IMAGE
//=============================================================
// DShow?N???X
//-------------------------------------------------------------
// DirectShow??J?????f?o?C?X??J??A
// ?L???v?`???o?b?t?@?????????N???X
//=============================================================
class DShow{
public:
//?R???X?g???N?^
DShow(int width, int height) {
//?p?????[?^??Z?b?g
capture_size_x = width;
capture_size_y = height;
//???
Init();
};
//?f?X?g???N?^
~DShow() {
//?J?????
Release();
};
//?O???????????
void GetCaptureBuffer(unsigned char *buffer);
IplImage *GetCaptureIplImage();
private:
//?v???C?x?[?g????
int Init();
void Release();
//?v???C?x?[?g????
//?L???v?`??????????
int capture_size_x;
int capture_size_y;
long buffer_size; //?L???v?`???o?b?t?@??T?C?Y
unsigned char *buffer; //?L???v?`????o?b?t?@??
//DirectShow??A
IGraphBuilder *pGraph;
IMediaControl *pMC;
ICaptureGraphBuilder2 *pCapture;
IBaseFilter *pF;
ISampleGrabber *pGrab;
ICreateDevEnum *pDevEnum;
};
#endif //_DSHOW_H
dshow.cpp
// ============================================================
// DirectShow??J?????f?o?C?X??J??A
// ?L???v?`???o?b?t?@?????????N???X
// Init - ???[?v???apture - Release ??????
// ?z??????g?p?@
// ============================================================
#include "dshow.h"
//-------------------------------------------------------------
// Name : DShow::Init
// Function :
// Argument : int width : ?L???v?`?????
// : int height : ?L???v?`???????
// Return : ??????
// Comment :
//-------------------------------------------------------------
int DShow::Init()
{
AM_MEDIA_TYPE amt;
// COM??????
CoInitialize(NULL);
// ---- ?L???v?`???t?B???^?????----
// ?L???v?`???f?o?C?X??T??
IBaseFilter *pbf = NULL;
IMoniker * pMoniker = NULL;
ULONG cFetched;
// ?f?o?C?X????????
CoCreateInstance( CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
IID_ICreateDevEnum, (void ** ) &pDevEnum);
// ?r?f?I?L???v?`???f?o?C?X????????
IEnumMoniker * pClassEnum = NULL;
pDevEnum->CreateClassEnumerator(
CLSID_VideoInputDeviceCategory, &pClassEnum, 0);
if (pClassEnum == NULL){
printf("?r?f?I?L???v?`???f?o?C?X????????n");
pDevEnum->Release();
CoUninitialize();
return -1;
}
// ??????????r?f?I?L???v?`???f?o?C?X??I?u?W?F?N?g??
// ?C???^?t?F?[?X????
pClassEnum->Next(1, &pMoniker, &cFetched);
pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pbf);
// ---- ?t?B???^?O???t?????----
// ?t?B???^?O???t????A?C???^?[?t?F?[?X????
CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC,
IID_IGraphBuilder, (void **) &pGraph);
pGraph->QueryInterface(IID_IMediaControl, (LPVOID *) &pMC);
// ?L???v?`???t?B???^??t?B???^?O???t????
pGraph->AddFilter(pbf, L"Video Capture");
// ????s?????L???v?`???t?B???^??Q??????[?X
pbf->Release();
// ---- ?O???o?t?B???^?????----
// ?O???o?t?B???^????
CoCreateInstance( CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
IID_IBaseFilter, (LPVOID *)&pF);
pF->QueryInterface( IID_ISampleGrabber, (void **)&pGrab );
// ?O???o?t?B???^??}??????????????
ZeroMemory(&amt, sizeof(AM_MEDIA_TYPE));
amt.majortype = MEDIATYPE_Video;
amt.subtype = MEDIASUBTYPE_RGB24;
amt.formattype = FORMAT_VideoInfo;
pGrab->SetMediaType( &amt );
// ?O???o?t?B???^??t?B???^?O???t????
pGraph->AddFilter(pF, L"SamGra");
// ---- ?L???v?`???O???t?????----
// ?L???v?`???O???t????
CoCreateInstance( CLSID_CaptureGraphBuilder2 , NULL, CLSCTX_INPROC,
IID_ICaptureGraphBuilder2, (void **) &pCapture );
// ?t?B???^?O???t??L???v?`???O???t??g?????
pCapture->SetFiltergraph( pGraph );
// ?L???v?`???O???t????A?O???o??????_?????O?????
pCapture->RenderStream (&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video,
pbf, NULL, pF);
// ?r?b?g?}?b?v?????
pGrab->GetConnectedMediaType( &amt );
// ?r?f?I ?w?b?_?[???|?C???^??l????
VIDEOINFOHEADER *pVideoHeader = (VIDEOINFOHEADER*)amt.pbFormat;
// ?r?f?I ?w?b?_?[???C?r?b?g?}?b?v???????
// ?r?b?g?}?b?v???BITMAPINFO ?\????R?s?[???
BITMAPINFO BitmapInfo;
ZeroMemory( &BitmapInfo, sizeof(BitmapInfo) );
CopyMemory( &BitmapInfo.bmiHeader, &(pVideoHeader->bmiHeader),
sizeof(BITMAPINFOHEADER));
//?L???v?`???o?b?t?@??T?C?Y????
buffer_size = BitmapInfo.bmiHeader.biSizeImage;
//?L???v?`???o?b?t?@????????????m??
buffer = new unsigned char[buffer_size];
// ---- ?L???v?`???J? ----
pGrab->SetBufferSamples(TRUE); // ?O???u?J?
pMC->Run(); // ?????_?????O?J?
return 0;
}
//------------------------------------------------------------------------------
// Name : DShow::GetCaptureBuffer
// Function : ?L???v?`????s??A?o?b?t?@??????i?[???
// Argument : unsigned char *buf : ?o?b?t?@??i?[??
// Return : ???
// Comment : ???t??????i??????????????????j
//------------------------------------------------------------------------------
void DShow::GetCaptureBuffer(unsigned char *buf)
{
// ?O???u
pGrab->GetCurrentBuffer(&buffer_size, (long *)buffer);
// REVERSE_IMAGE ???`???????A???????t????
// ??`?????????????R?s?[
#ifdef REVERSE_IMAGE
//???t????R?s?[
int byte = buffer_size/capture_size_y;
for(int y=0; y<capture_size_y; y++) {
memcpy(buf+(capture_size_y-1-y)*byte, buffer+y*byte,byte);
}
#else
memcpy(buf, buffer, buffer_size);
#endif
}
//------------------------------------------------------------------------------
// Name : DShow::GetCaptureIplImage
// Function : ?L???v?`????s??A?????plImage????
// Argument : ???
// Return : IplImage : ?L???v?`?????
// Comment : ???t??????i??????????????????j
//------------------------------------------------------------------------------
IplImage *DShow::GetCaptureIplImage()
{
IplImage *image = cvCreateImage(cvSize(capture_size_x, capture_size_y), 8, 3);
GetCaptureBuffer( (unsigned char *)image->imageData);
return image;
}
//------------------------------------------------------------------------------
// Name : DShow::Release
// Function : ?J?????
// Argument : ???
// Return : ???
// Comment :
//------------------------------------------------------------------------------
void DShow::Release()
{
pMC->Stop();
pGrab->SetBufferSamples(0);
// ---- ????? ----
// ?C???^?[?t?F?[?X??????[?X
pMC->Release();
pDevEnum->Release();
pGraph->Release();
pCapture->Release();
pF->Release();
pGrab->Release();
// COM??????[?X
CoUninitialize();
delete(buffer);
}
cv.cpp
#include <stdio.h>
#include <cv.h>
#include <highgui.h>
#include "dshow.h"
// ???C?u??????????
#pragma comment(lib,"cv.lib")
#pragma comment(lib,"cxcore.lib")
#pragma comment(lib,"cvaux.lib")
#pragma comment(lib,"highgui.lib")
// ???
#define CAPTURE_SIZE_X 320
#define CAPTURE_SIZE_Y 240
int main()
{
//DShow?N???X????
DShow dshow(CAPTURE_SIZE_X, CAPTURE_SIZE_Y);
char* window_name = "Capture for DirectShow";
//????x?\ヲ?p
CvFont dfont;
char message[64] = "";
//?t?H???g??????
cvInitFont (&dfont, CV_FONT_HERSHEY_SIMPLEX , 1.0f, 1.0f, 0.0f, 2, CV_AA);
//OpenCV?p???????m??
IplImage *frame = cvCreateImage(cvSize(CAPTURE_SIZE_X, CAPTURE_SIZE_Y),
8, 3);
IplImage *image = cvCreateImage(cvSize(CAPTURE_SIZE_X, CAPTURE_SIZE_Y),
8, 3);
//?E?C???h?E??J??
cvNamedWindow(window_name, CV_WINDOW_AUTOSIZE);
//?????[?v
while(1) {
//??????Z?p
double t = (double)cvGetTickCount();
//?L???v?`??
frame = dshow.GetCaptureIplImage();
cvCopy(frame, image);
//?L?[??????
int c = cvWaitKey(10);
if( (char)c == 27 ) { //Ecs?L?[??I??
break;
}
//?O??cvGetTickCount() ???s????????o??????Z?
t = (double)cvGetTickCount() - t;
sprintf(message, "%gms", t/((double)cvGetTickFrequency()*1000.) );
//?e?L?X?g??\ヲ
cvPutText(image, message, cvPoint(50, 50), &dfont, CV_RGB(255, 255, 255));
//????\ヲ
cvShowImage(window_name, image);
}
//?????
cvDestroyWindow("hoge");
cvReleaseImage(&image);
}