MFC窗口视频显示方法--OpenCV DirectShow模式

来源:互联网 发布:北京大学软件共享平台 编辑:程序博客网 时间:2024/06/12 18:30

OpenCV DirectShow模式,中文OpenCv提供了一个 CameraDS类

 

代码如下:

CameraDS.h

//////////////////////////////////////////////////////////////////////// Video Capture using DirectShow// Author: Shiqi Yu (shiqi.yu@gmail.com)// Thanks to://HardyAI@OpenCV China//flymanbox@OpenCV China (for his contribution to function CameraName, and frame width/height setting)// Last modification: April 9, 2009////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 使用说明://   1. 将CameraDS.h CameraDS.cpp以及目录DirectShow复制到你的项目中//   2. 菜单 Project->Settings->Settings for:(All configurations)->C/C++->Category(Preprocessor)->Additional include directories//      设置为 DirectShow/Include//   3. 菜单 Project->Settings->Settings for:(All configurations)->Link->Category(Input)->Additional library directories//      设置为 DirectShow/Lib//////////////////////////////////////////////////////////////////////#ifndef CCAMERA_H#define CCAMERA_H#define WIN32_LEAN_AND_MEAN#include <windows.h>#include <atlbase.h>#include <cxcore.h>#include "DirectShow/Include/qedit.h"#include "DirectShow/Include/dshow.h"#define MYFREEMEDIATYPE(mt){if ((mt).cbFormat != 0)\{CoTaskMemFree((PVOID)(mt).pbFormat);\(mt).cbFormat = 0;\(mt).pbFormat = NULL;\}\if ((mt).pUnk != NULL)\{\(mt).pUnk->Release();\(mt).pUnk = NULL;\}}class CCameraDS  {private:IplImage * m_pFrame;bool m_bConnected;int m_nWidth;int m_nHeight;bool m_bLock;bool m_bChanged;long m_nBufferSize;CComPtr<IGraphBuilder> m_pGraph;CComPtr<IBaseFilter> m_pDeviceFilter;CComPtr<IMediaControl> m_pMediaControl;CComPtr<IBaseFilter> m_pSampleGrabberFilter;CComPtr<ISampleGrabber> m_pSampleGrabber;CComPtr<IPin> m_pGrabberInput;CComPtr<IPin> m_pGrabberOutput;CComPtr<IPin> m_pCameraOutput;CComPtr<IMediaEvent> m_pMediaEvent;CComPtr<IBaseFilter> m_pNullFilter;CComPtr<IPin> m_pNullInputPin;private:bool BindFilter(int nCamIDX, IBaseFilter **pFilter);void SetCrossBar();public:CCameraDS();virtual ~CCameraDS();//打开摄像头,nCamID指定打开哪个摄像头,取值可以为0,1,2,...//bDisplayProperties指示是否自动弹出摄像头属性页//nWidth和nHeight设置的摄像头的宽和高,如果摄像头不支持所设定的宽度和高度,则返回falsebool CCameraDS::OpenCamera(int nCamID, bool bDisplayProperties=true, int nWidth=320, int nHeight=240);//关闭摄像头,析构函数会自动调用这个函数void CloseCamera();//返回摄像头的数目//可以不用创建CCameraDS实例,采用int c=CCameraDS::CameraCount();得到结果。static int CameraCount(); //根据摄像头的编号返回摄像头的名字//nCamID: 摄像头编号//sName: 用于存放摄像头名字的数组//nBufferSize: sName的大小//可以不用创建CCameraDS实例,采用CCameraDS::CameraName();得到结果。static int CCameraDS::CameraName(int nCamID, char* sName, int nBufferSize);//返回图像宽度int GetWidth(){return m_nWidth;} //返回图像高度int GetHeight(){return m_nHeight;}//抓取一帧,返回的IplImage不可手动释放!//返回图像数据的为RGB模式的Top-down(第一个字节为左上角像素),即IplImage::origin=0(IPL_ORIGIN_TL)IplImage * QueryFrame();};#endif 


CameraDS.cpp

//////////////////////////////////////////////////////////////////////// Video Capture using DirectShow// Author: Shiqi Yu (shiqi.yu@gmail.com)// Thanks to://HardyAI@OpenCV China//flymanbox@OpenCV China (for his contribution to function CameraName, and frame width/height setting)// Last modification: April 9, 2009////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 使用说明://   1. 将CameraDS.h CameraDS.cpp以及目录DirectShow复制到你的项目中//   2. 菜单 Project->Settings->Settings for:(All configurations)->C/C++->Category(Preprocessor)->Additional include directories//      设置为 DirectShow/Include//   3. 菜单 Project->Settings->Settings for:(All configurations)->Link->Category(Input)->Additional library directories//      设置为 DirectShow/Lib//////////////////////////////////////////////////////////////////////// CameraDS.cpp: implementation of the CCameraDS class.////////////////////////////////////////////////////////////////////////#include "CameraDS.h"#pragma comment(lib,"Strmiids.lib") //////////////////////////////////////////////////////////////////////// Construction/Destruction//////////////////////////////////////////////////////////////////////CCameraDS::CCameraDS(){m_bConnected = false;m_nWidth = 0;m_nHeight = 0;m_bLock = false;m_bChanged = false;m_pFrame = NULL;m_nBufferSize = 0;m_pNullFilter = NULL;m_pMediaEvent = NULL;m_pSampleGrabberFilter = NULL;m_pGraph = NULL;CoInitialize(NULL);}CCameraDS::~CCameraDS(){CloseCamera();CoUninitialize();}void CCameraDS::CloseCamera(){if(m_bConnected)m_pMediaControl->Stop();m_pGraph = NULL;m_pDeviceFilter = NULL;m_pMediaControl = NULL;m_pSampleGrabberFilter = NULL;m_pSampleGrabber = NULL;m_pGrabberInput = NULL;m_pGrabberOutput = NULL;m_pCameraOutput = NULL;m_pMediaEvent = NULL;m_pNullFilter = NULL;m_pNullInputPin = NULL;if (m_pFrame)cvReleaseImage(&m_pFrame);m_bConnected = false;m_nWidth = 0;m_nHeight = 0;m_bLock = false;m_bChanged = false;m_nBufferSize = 0;}bool CCameraDS::OpenCamera(int nCamID, bool bDisplayProperties, int nWidth, int nHeight){HRESULT hr = S_OK;CoInitialize(NULL);// Create the Filter Graph Manager.hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC,IID_IGraphBuilder, (void **)&m_pGraph);hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (LPVOID *)&m_pSampleGrabberFilter);hr = m_pGraph->QueryInterface(IID_IMediaControl, (void **) &m_pMediaControl);hr = m_pGraph->QueryInterface(IID_IMediaEvent, (void **) &m_pMediaEvent);hr = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER,IID_IBaseFilter, (LPVOID*) &m_pNullFilter);hr = m_pGraph->AddFilter(m_pNullFilter, L"NullRenderer");hr = m_pSampleGrabberFilter->QueryInterface(IID_ISampleGrabber, (void**)&m_pSampleGrabber);AM_MEDIA_TYPE   mt;ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));mt.majortype = MEDIATYPE_Video;mt.subtype = MEDIASUBTYPE_RGB24;mt.formattype = FORMAT_VideoInfo; hr = m_pSampleGrabber->SetMediaType(&mt);MYFREEMEDIATYPE(mt);m_pGraph->AddFilter(m_pSampleGrabberFilter, L"Grabber"); // Bind Device Filter.  We know the device because the id was passed inBindFilter(nCamID, &m_pDeviceFilter);m_pGraph->AddFilter(m_pDeviceFilter, NULL);CComPtr<IEnumPins> pEnum;m_pDeviceFilter->EnumPins(&pEnum); hr = pEnum->Reset();hr = pEnum->Next(1, &m_pCameraOutput, NULL); pEnum = NULL; m_pSampleGrabberFilter->EnumPins(&pEnum);pEnum->Reset();hr = pEnum->Next(1, &m_pGrabberInput, NULL); pEnum = NULL;m_pSampleGrabberFilter->EnumPins(&pEnum);pEnum->Reset();pEnum->Skip(1);hr = pEnum->Next(1, &m_pGrabberOutput, NULL); pEnum = NULL;m_pNullFilter->EnumPins(&pEnum);pEnum->Reset();hr = pEnum->Next(1, &m_pNullInputPin, NULL);//SetCrossBar();if (bDisplayProperties) {CComPtr<ISpecifyPropertyPages> pPages;HRESULT hr = m_pCameraOutput->QueryInterface(IID_ISpecifyPropertyPages, (void**)&pPages);if (SUCCEEDED(hr)){PIN_INFO PinInfo;m_pCameraOutput->QueryPinInfo(&PinInfo);CAUUID caGUID;pPages->GetPages(&caGUID);OleCreatePropertyFrame(NULL, 0, 0,L"Property Sheet", 1,(IUnknown **)&(m_pCameraOutput.p),caGUID.cElems,caGUID.pElems,0, 0, NULL);CoTaskMemFree(caGUID.pElems);PinInfo.pFilter->Release();}pPages = NULL;}else {//////////////////////////////////////////////////////////////////////////////// 加入由 lWidth和lHeight设置的摄像头的宽和高 的功能,默认320*240// by flymanbox @2009-01-24//////////////////////////////////////////////////////////////////////////////   int _Width = nWidth, _Height = nHeight;   IAMStreamConfig*   iconfig;    iconfig = NULL;   hr = m_pCameraOutput->QueryInterface(IID_IAMStreamConfig,   (void**)&iconfig);            AM_MEDIA_TYPE* pmt;       if(iconfig->GetFormat(&pmt) !=S_OK)    {  //printf("GetFormat Failed ! \n");  return   false;      }         VIDEOINFOHEADER*   phead;   if ( pmt->formattype == FORMAT_VideoInfo)      {   phead=( VIDEOINFOHEADER*)pmt->pbFormat;   phead->bmiHeader.biWidth = _Width;   phead->bmiHeader.biHeight = _Height;   if(( hr=iconfig->SetFormat(pmt)) != S_OK )   {return   false;}}   iconfig->Release();   iconfig=NULL;   MYFREEMEDIATYPE(*pmt);}hr = m_pGraph->Connect(m_pCameraOutput, m_pGrabberInput);hr = m_pGraph->Connect(m_pGrabberOutput, m_pNullInputPin);if (FAILED(hr)){switch(hr){case VFW_S_NOPREVIEWPIN :break;case E_FAIL :break;case E_INVALIDARG :break;case E_POINTER :break;}}m_pSampleGrabber->SetBufferSamples(TRUE);m_pSampleGrabber->SetOneShot(TRUE);    hr = m_pSampleGrabber->GetConnectedMediaType(&mt);if(FAILED(hr))return false;VIDEOINFOHEADER *videoHeader;videoHeader = reinterpret_cast<VIDEOINFOHEADER*>(mt.pbFormat);m_nWidth = videoHeader->bmiHeader.biWidth;m_nHeight = videoHeader->bmiHeader.biHeight;m_bConnected = true;pEnum = NULL;return true;}bool CCameraDS::BindFilter(int nCamID, IBaseFilter **pFilter){if (nCamID < 0)return false;     // enumerate all video capture devicesCComPtr<ICreateDevEnum> pCreateDevEnum;HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,IID_ICreateDevEnum, (void**)&pCreateDevEnum);if (hr != NOERROR){return false;}    CComPtr<IEnumMoniker> pEm;    hr = pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,        &pEm, 0);    if (hr != NOERROR) {return false;    }    pEm->Reset();    ULONG cFetched;    IMoniker *pM;int index = 0;    while(hr = pEm->Next(1, &pM, &cFetched), hr==S_OK, index <= nCamID)    {IPropertyBag *pBag;hr = pM->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pBag);if(SUCCEEDED(hr)) {VARIANT var;var.vt = VT_BSTR;hr = pBag->Read(L"FriendlyName", &var, NULL);if (hr == NOERROR) {if (index == nCamID){pM->BindToObject(0, 0, IID_IBaseFilter, (void**)pFilter);}SysFreeString(var.bstrVal);}pBag->Release();}pM->Release();index++;    }pCreateDevEnum = NULL;return true;}//将输入crossbar变成PhysConn_Video_Compositevoid CCameraDS::SetCrossBar(){int i;IAMCrossbar *pXBar1 = NULL;ICaptureGraphBuilder2 *pBuilder = NULL; HRESULT hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL,CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (void **)&pBuilder);if (SUCCEEDED(hr)){hr = pBuilder->SetFiltergraph(m_pGraph);}hr = pBuilder->FindInterface(&LOOK_UPSTREAM_ONLY, NULL, m_pDeviceFilter,IID_IAMCrossbar, (void**)&pXBar1);if (SUCCEEDED(hr)) {  long OutputPinCount;long InputPinCount;long PinIndexRelated;long PhysicalType;long inPort = 0;long outPort = 0;pXBar1->get_PinCounts(&OutputPinCount,&InputPinCount);for( i =0;i<InputPinCount;i++){pXBar1->get_CrossbarPinInfo(TRUE,i,&PinIndexRelated,&PhysicalType);if(PhysConn_Video_Composite==PhysicalType) {inPort = i;break;}}for( i =0;i<OutputPinCount;i++){pXBar1->get_CrossbarPinInfo(FALSE,i,&PinIndexRelated,&PhysicalType);if(PhysConn_Video_VideoDecoder==PhysicalType) {outPort = i;break;}}  if(S_OK==pXBar1->CanRoute(outPort,inPort)){pXBar1->Route(outPort,inPort);}pXBar1->Release();  }pBuilder->Release();}/*The returned image can not be released.*/IplImage* CCameraDS::QueryFrame(){long evCode;long size = 0;m_pMediaControl->Run();m_pMediaEvent->WaitForCompletion(INFINITE, &evCode); m_pSampleGrabber->GetCurrentBuffer(&size, NULL);//if the buffer size changedif (size != m_nBufferSize){if (m_pFrame)cvReleaseImage(&m_pFrame);m_nBufferSize = size;m_pFrame = cvCreateImage(cvSize(m_nWidth, m_nHeight), IPL_DEPTH_8U, 3);}m_pSampleGrabber->GetCurrentBuffer(&m_nBufferSize, (long*)m_pFrame->imageData);cvFlip(m_pFrame);return m_pFrame;}int CCameraDS::CameraCount(){int count = 0; CoInitialize(NULL);   // enumerate all video capture devicesCComPtr<ICreateDevEnum> pCreateDevEnum;    HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,IID_ICreateDevEnum, (void**)&pCreateDevEnum);    CComPtr<IEnumMoniker> pEm;    hr = pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,        &pEm, 0);    if (hr != NOERROR) {return count;    }    pEm->Reset();    ULONG cFetched;    IMoniker *pM;    while(hr = pEm->Next(1, &pM, &cFetched), hr==S_OK)    {count++;    }pCreateDevEnum = NULL;pEm = NULL;return count;}int CCameraDS::CameraName(int nCamID, char* sName, int nBufferSize){int count = 0; CoInitialize(NULL);   // enumerate all video capture devicesCComPtr<ICreateDevEnum> pCreateDevEnum;    HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,IID_ICreateDevEnum, (void**)&pCreateDevEnum);    CComPtr<IEnumMoniker> pEm;    hr = pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,        &pEm, 0);    if (hr != NOERROR) return 0;    pEm->Reset();    ULONG cFetched;    IMoniker *pM;    while(hr = pEm->Next(1, &pM, &cFetched), hr==S_OK)    {if (count == nCamID){IPropertyBag *pBag=0;hr = pM->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pBag);if(SUCCEEDED(hr)){VARIANT var;var.vt = VT_BSTR;hr = pBag->Read(L"FriendlyName", &var, NULL); //还有其他属性,像描述信息等等...            if(hr == NOERROR)        {        //获取设备名称WideCharToMultiByte(CP_ACP,0,var.bstrVal,-1,sName, nBufferSize ,"",NULL);                SysFreeString(var.bstrVal);        }    pBag->Release();}pM->Release();break;}count++;    }pCreateDevEnum = NULL;pEm = NULL;return 1;}


 

1:将这两个文件复制到您的项目,同时复制有DirectShow的Include目录

2:在项目属性设置包含目录

3:在代码中

#include <cv.h>
#include <highgui.h>

#include "camerads.h"

4:代码实现如下

void CEVisionDlg::OpenVideo_CDS(){int cam_count= CCameraDS::CameraCount();//仅仅获取摄像头数目if(cam_count==0) return ;CCameraDS camera;HWND hWnd;HWND hParent;RECT rcDlg; //ScreenToClientint vWndType1Height;int vWndType1Windth;int intCamSRCWidth,intCamSRCHeight;int intImgSRCHeight,intImgSRCWindth;intCamSRCWidth=640;intCamSRCHeight=480;intImgSRCWindth=640;intImgSRCHeight=480;//打开第一个摄像头//if(! camera.OpenCamera(0, true)) //弹出属性选择窗口if(! camera.OpenCamera(0, false, intCamSRCWidth,intCamSRCHeight)) return ;//不弹出属性选择窗口,用代码制定图像宽和高GetDlgItem(IDC_SHOW_IMG)->GetWindowRect(&rcDlg);vWndType1Windth = rcDlg.right - rcDlg.left -10;vWndType1Height = vWndType1Windth * intImgSRCHeight;vWndType1Height = vWndType1Height / intImgSRCWindth; cvNamedWindow("AIWndSrcCamera", CV_WINDOW_AUTOSIZE);//创建一个新窗口hWnd = (HWND) cvGetWindowHandle("AIWndSrcCamera");  //通过名字获取窗口句柄hParent = ::GetParent(hWnd);//该函数获得一个指定子窗口的父窗口句柄::SetParent(hWnd, GetDlgItem(IDC_SHOW_IMG)->m_hWnd);  //该函数改变某个子窗口的父窗口,HWND SetParent(HWND hWndChild,HWND hWndNewParent);::ShowWindow(hParent, SW_HIDE);cvResizeWindow("AIWndSrcCamera", vWndType1Windth,vWndType1Height);IplImage* m_pFrame = cvCreateImage( cvSize(intImgSRCWindth,intImgSRCHeight), IPL_DEPTH_8U, 3);while (true){m_CameraFrame =camera.QueryFrame();if(!m_CameraFrame)return;else{if( m_CameraFrame->origin == IPL_ORIGIN_TL )cvResize (m_CameraFrame, m_pFrame, CV_INTER_NN);elsecvFlip( m_CameraFrame, m_pFrame, 0 );cvShowImage("AIWndSrcCamera", m_pFrame);if ((cvWaitKey(10) & 255) == 27 ) return ; }}camera.CloseCamera(); //可不调用此函数,CCameraDS析构时会自动关闭摄像头cvReleaseImage(&m_pFrame);cvDestroyWindow("AIWndSrcCamera");}