Visual C++编程实现摄像头视频捕捉要点
- 格式:doc
- 大小:55.00 KB
- 文档页数:12
Visual Studio2010在MFC中用opencv实现对视频中动态目标的追踪第二步,建立一个MFC的对话框程序,做两个按钮,一个“打开视频文件”,一个“运动跟踪处理”。
具体操作:1 建立MFC对话框程序的框架:File ->New -> MFC AppWizard(exe),选取工程路径,并取工程名“VideoProcesssing”-> Next -> 选择Dialog based后,去掉使用Unicode库的勾,选择在静态库中使用 MFC,点Finish,点OK.2 添加按钮:直接Delete掉界面默认的两个“确定”“取消”按钮。
然后添加两个button,分别名为“打开视频”,“运动跟踪处理”,其ID分别设为IDC_OPEN_VIDEO,IDC_TRACKING.3 添加消息响应函数:双击按钮“打开视频文件”,自动生成响应函数名OnOpenVideo,点Ok。
然后添加如下代码:CFileDialog dlg(true,"*.avi",NULL,NULL,"*.avi|*.avi||");if (dlg.DoModal()==IDOK){strAviFilePath = dlg.GetPathName();}else{return;}同样,双击“运动跟踪处理”按钮,选择默认的响应函数名,然后添加代码://声明IplImage指针IplImage* pFrame = NULL;IplImage* pFrImg = NULL;IplImage* pBkImg = NULL;CvMat* pFrameMat = NULL;CvMat* pFrMat = NULL;CvMat* pBkMat = NULL;CvCapture* pCapture = NULL;int nFrmNum = 0;//打开AVI视频文件if(strAviFilePath=="") //判断文件路径是否为空{MessageBox("请先选择AVI视频文件!");return;}else{if(!(pCapture = cvCaptureFromFile(strAviFilePath))) {MessageBox("打开AVI视频文件失败!");return;}}//创建窗口cvNamedWindow("Video", 1);cvNamedWindow("Background",1);cvNamedWindow("Foreground",1);//使窗口有序排列,窗口宽330cvMoveWindow("Video", 30, 0);cvMoveWindow("Background", 360, 0);cvMoveWindow("Foreground", 690, 0);//逐帧读取视频while(pFrame = cvQueryFrame( pCapture )){nFrmNum++;//如果是第一帧,需要申请内存,并初始化if(nFrmNum == 1){pBkImg = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U,1); // 存放背景图像(灰度)pFrImg = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U,1); // 存放中间图像(灰度)pBkMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);pFrMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);pFrameMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);//转化成单通道图像再处理(灰度)cvCvtColor(pFrame, pBkImg, CV_BGR2GRAY);cvCvtColor(pFrame, pFrImg, CV_BGR2GRAY);cvConvert(pFrImg, pFrameMat);cvConvert(pFrImg, pFrMat);cvConvert(pFrImg, pBkMat);}else{cvCvtColor(pFrame, pFrImg, CV_BGR2GRAY); //转化成单通道图像再处理(灰度)cvConvert(pFrImg, pFrameMat);//高斯滤波先,以平滑图像//cvSmooth(pFrameMat, pFrameMat, CV_GAUSSIAN, 3, 0, 0);//当前帧跟背景图相减(求背景差并取绝对值)cvAbsDiff(pFrameMat, pBkMat, pFrMat);//二值化前景图(这里采用特定阈值进行二值化)cvThreshold(pFrMat, pFrImg, 60, 255.0, CV_THRESH_BINARY);//进行形态学滤波,去掉噪音cvErode(pFrImg, pFrImg, 0, 1);cvDilate(pFrImg, pFrImg, 0, 1);//滑动平均更新背景(求平均)cvRunningAvg(pFrameMat, pBkMat, 0.003, 0);//将背景转化为图像格式,用以显示cvConvert(pBkMat, pBkImg);// 保持原图像的旋转方向pBkImg->origin = pFrImg->origin = pFrame->origin;//显示图像cvShowImage("Video", pFrame);cvShowImage("Background", pBkImg);cvShowImage("Foreground", pFrImg);//如果有按键事件,则跳出循环//此等待也为cvShowImage函数提供时间完成显示//等待时间可以根据CPU速度调整if( cvWaitKey(200) >= 0 )break;}}//销毁窗口cvDestroyWindow("Video");cvDestroyWindow("Background");cvDestroyWindow("Foreground");//释放图像和矩阵cvReleaseImage(&pFrImg);cvReleaseImage(&pBkImg);cvReleaseMat(&pFrameMat);cvReleaseMat(&pFrMat);cvReleaseMat(&pBkMat);cvReleaseCapture(&pCapture);4 选fileview选项卡中VideoProcessingDlg.h,在CVideoProcessingDlg类中添加公有类成员:CString strAviFilePath;5 选fileview选项卡中VideoProcessingDlg.cpp,添加opencv头文件#include "cv.h"#include "highgui.h"#include "cxcore.h"6 编译执行,成功!还可以添加一个”录制视频”的按钮,修改ID号为IDC_RECORD,双击“录制视频”按钮,选择默认的响应函数名,然后添加代码:CvCapture* capture=cvCaptureFromCAM(-1); //打开摄像头CvVideoWriter* video=NULL;IplImage* frame=NULL;int n;if(!capture) //如果不能打开摄像头给出警告{cout<<"Can not open the camera."<<endl;return ;}else{frame=cvQueryFrame(capture); //首先取得摄像头中的一帧video=cvCreateVideoWriter("camera.avi", CV_FOURCC('X', 'V', 'I', 'D'), 25,cvSize(frame->width,frame->height)); //创建CvVideoWriter对象并分配空间//保存的文件名为camera.avi,编码要在运行程序时选择,大小就是摄像头视频的大小,帧频率是32if(video) //如果能创建CvVideoWriter对象则表明成功{cout<<"VideoWriter has created."<<endl;}cvNamedWindow("Camera Video",1); //新建一个窗口int i = 0;while(i <= 200) // 让它循环200次自动停止录取{frame=cvQueryFrame(capture); //从CvCapture中获得一帧if(!frame){cout<<"Can not get frame from the capture."<<endl;break;}n=cvWriteFrame(video,frame); //判断是否写入成功,如果返回的是1,表示写入成功cout<<n<<endl;cvShowImage("Camera Video",frame); //显示视频内容的图片i++;if(cvWaitKey(2)>0)break; //有其他键盘响应,则退出}cvReleaseVideoWriter(&video);cvReleaseCapture(&capture);cvDestroyWindow("Camera Video");}return ;第二步,建立一个编程环境,然后加载opencv的库路径等等。
VFW视频采集方案VFW是Microsoft于1992年推出的数字视频软件包,它不依赖于专用的硬件设备,提供了通用的数字视频开发方案。
VFW主要由、、、、等库文件组成,这些库提供了相关视频、音频、AVI文件的函数,本节将介绍如何利用这些函数进行视频采集。
2.2.1 开发流程分析VFW使用的视频函数被封装在库文件中,该库文件默认情况下没有被连接到MFC工程中,因此使用VFW进行视频开发的第一步是导入库文件。
方法如下:(1)引用头文件。
#include ""(2)导入库文件。
#pragma comment (lib,"vfw32")步骤2也可以在通过工程选项窗口的连接选项卡进行设置。
如图所示。
连接库文件图工程选项窗口在导入库文件后便可以使用视频函数了。
首先调用capCreateCaptureWindow函数创建具有WS_POPUP风格的视频捕捉窗口。
然后调用capDriverConnect函数连接驱动程序,设置视频捕捉窗口的大小、显示位置。
最后调用capPreviewRate函数设置预览速率,调用capPre view函数进行视频预览。
总结上述流程分析,VFW视频捕捉开发流程具体步骤如下:(1)引用“”头文件并导入库。
(2)创建一个线程,在线程函数中调用capCreateCaptureWindow创建视频捕捉窗口。
(3)调用capDriverConnect连接驱动程序,设置视频捕捉窗口风格、大小及父窗口。
(4)调用capPreviewRate函数设置预览速度,调用capPreview函数开始预览。
2.2.2 视频窗口创建在进行视频程序开发时,第一步需要创建一个视频预览窗口。
在程序中可以使用capCreate CaptureWindow函数来创建视频预览窗口,该函数语法如下:HWND VFWAPI capCreateCaptureWindow(LPCSTR lpszWindowName, DWORD dwStyle, int x,int y, int nWidth, int nHeight, HWND hWnd, int nID);参数说明:lpszWindowName:表示视频捕捉窗口的名称。
【编程分析】微软为软件开发人员提供了一个专门用于视频捕获的VFW (Video for Windows) SDK,她为在Windows系统中实现视频捕获提供了标准的接口,从而大大降低了程序的开发难度。
一、VFW简介VFW是微软公司推出的关于数字视频的一个软件包,它能使应用程序通过数字化设备从传统的模拟视频源得到数字化的视频剪辑。
VFW的一个关键思想是播放时不需要专用硬件,为了解决数字视频数据量大的问题,需要对数据进行压缩。
它引进了一种叫A VI的文件标准,该标准未规定如何对视频进行捕获、压缩及播放,仅规定视频和音频该如何存储在硬盘上,以及在AVI文件中交替存储视频帧和与之相匹配的音频数据。
VFW使程序员能通过发送消息或设置属性来捕获、播放和编辑视频剪辑。
VFW主要由以下6个模块组成:1、A VICAP32.DLL:包含执行视频捕获的函数,它给AVI文件的I/O处理和视频、音频设备驱动程序提供一个高级接口;2、MSVIDEO.DLL:包含一套特殊的DrawDib函数,用来处理屏幕上的视频操作;3、MCIAVI.DRV:包括对VFW的MCI命令解释器的驱动程序;4、A VIFILE.DLL:包含由标准多媒体I/O(mmio)函数提供的更高的命令,用来访问.A VI 文件;5、压缩管理器(ICM):用于管理的视频压缩/解压缩的编译码器(Codec);6、音频压缩管理器ACM:提供与ICM相似的服务,适用于波形音频。
本程序将使用第一个模块A VICAP32.DLL,她是Windows API应用程序接口相关模块,用于对摄像头和其它视频硬件进行AVI电影和视频的截取。
她的A VICap窗口类支持实时的视频流捕获和单帧捕获,并提供对视频源的控制,而且能直接访问视频缓冲区,不需要生成中间文件,实时性很强,效率很高,同时,她还可将数字视频捕获到一个文件中。
要使用该动态库,在程序中需要对其中的各个常量和API函数进行声明,由于不再提倡使用API函数,其集成环境也没有API浏览器了,故本文所使用的全部常量和函数的声明都可以在代码包中察看。
//此源码是我更改过的基于VFW(Video for Windows)的源码,使用了定时器能实时的显示图像,从网上可搜到原版源码,但是原版的功能是保存为一个文件,且不能实时显示,此版本虽然能显示,但感觉反应速度不是很快,没有基于DirectShow的程序更新速度快,不过在WM_PAINT消息处理里加while(1){capGrabFrame(ghWndCap);}刷新速度就快很多了,但是这样程序就进入死循环不能再处理其他消息,至于怎样改进,就靠读者你了。
//源码的任何部分都可以在MSDN里查到,请参考MSDN。
#include <windows.h>#include <stdio.h>#include <vfw.h>#pragma comment(lib,"vfw32.lib")HWND ghWndCap ; //捕获窗的句柄CAPSTATUS gCapStatus ; //捕获窗的状态CAPDRIVERCAPS gCapDriverCaps ; //视频驱动的能力char gachBuffer[20];//char szCaptureFile[] = "CamCapture.AVI";///////////////////////////////////////////////////////////////////// //// StatusCallbackProc: 状态回调函数,使用capSetCallbackOnStatus宏来注册这个回调函数。
// hWnd: 捕获窗体句柄// nID: 当前状态的状态码// lpStatusText: 当前状态的文本字符///////////////////////////////////////////////////////////////////// //LRESULT CALLBACK StatusCallbackProc(HWND hWnd,int nID,LPSTR lpStatusText){if(!ghWndCap)return FALSE;//获得捕获窗的状态capGetStatus(ghWndCap,&gCapStatus,sizeof(CAPSTATUS));//更新捕获窗的大小,得到消息WM_CAP_GET_STATUSSetWindowPos(ghWndCap,NULL,0,0,gCapStatus.uiImageWidth,gCapStatus.uiI mageHeight,SWP_NOZORDER|SWP_NOMOVE);if(nID==0){//清除旧的状态信息SetWindowText(ghWndCap,(LPSTR)"hello");return (LRESULT)TRUE;}//显示状态ID和状态文本wsprintf(gachBuffer,"Status# %d: %s",nID,lpStatusText); SetWindowText(ghWndCap,(LPSTR)gachBuffer);return (LRESULT)TRUE;}///////////////////////////////////////////////////////////////////// /////////// ErrorCallbackProc: 错误回调函数,过capSetCallbackOnError宏来注册回调// hWnd: 捕获窗口句柄// nErrID: 错误代码// lpErrorText: 关于错误的文本信息///////////////////////////////////////////////////////////////////// //////////LRESULT CALLBACK ErrorCallbackProc(HWND hWnd,int nErrID,LPSTR lpErrorText){if(!ghWndCap)return FALSE;if(nErrID==0)return TRUE;//清除旧的错误wsprintf(gachBuffer,"Error# %d",nErrID);//显示错误标识和文本MessageBox(hWnd, lpErrorText, gachBuffer,MB_OK | MB_ICONEXCLAMATION); return (LRESULT) TRUE;}///////////////////////////////////////////////////////////////////// /////////// FrameCallbackProc: 帧回调函数,通过capSetCallbackFrame宏来注册回调函数// hWnd: 捕获窗体句柄// lpVHdr: 指向一个包含帧信息的数据结构体///////////////////////////////////////////////////////////////////// ////////////LRESULT CALLBACK FrameCallbackProc(HWND hWnd,LPVIDEOHDR lpVHdr){FILE *fp;fp=fopen("caram.dat","w");if(!ghWndCap)return FALSE;//假设fp为一打开的.dat文件指针fwrite(lpVHdr->lpData,1,lpVHdr->dwBufferLength,fp);return (LRESULT)TRUE;}///////////////////////////////////////////////////////////////////// ///////////TimerProc函数处理定时器,在这里抓取并显示图像///////////////////////////////////////////////////////////////////// /////////VOID CALLBACK TimerProc(HWND hwnd, // handle to windowUINT uMsg, // WM_TIMER messageUINT_PTR idEvent, // timer identifierDWORD dwTime // current system time){capGrabFrame(ghWndCap);}////////////////////////////////////////////////////////////////////主回调函数////////////////////////////////////////////////////////////////// LRESULT CALLBACK WindowProc(HWND hwnd, // handle to windowUINT uMsg, // message identifierWPARAM wParam, // first message parameterLPARAM lParam // second message parameter){// HDC hdc;// PAINTSTRUCT ps;// RECT rect;switch(uMsg){case WM_CREATE:ghWndCap=capCreateCaptureWindow((LPSTR)"Capture Window",WS_CHILD|WS_VISIBLE,0,0,320,240,(HWND)hwnd,(int)0);capSetCallbackOnError(ghWndCap,(FARPROC)ErrorCallbackProc);capSetCallbackOnStatus(ghWndCap,(FARPROC)StatusCallbackProc);capSetCallbackOnFrame(ghWndCap,(FARPROC)FrameCallbackProc);capDriverConnect(ghWndCap,0); // 将捕获窗同驱动连接capDriverGetCaps(ghWndCap,&gCapDriverCaps,sizeof(CAPDRIVERCAPS));/ /获得驱动的能力,相关的信息放在结构变量gCapDriverCaps中capPreviewRate(ghWndCap, 66); //uses this macro to set the frame display rate for preview mode to 66 milliseconds per framecapPreview(ghWndCap, TRUE); //and then uses the capPreview macro to place the capture window in preview mode.if(gCapDriverCaps.fHasOverlay) //检查驱动器是否有叠加能力capOverlay(ghWndCap,TRUE); //启动Overlay模式if(gCapDriverCaps.fHasDlgVideoSource)capDlgVideoSource(ghWndCap); //Video source 对话框if(gCapDriverCaps.fHasDlgVideoFormat)capDlgVideoFormat(ghWndCap); // Video format 对话框if(gCapDriverCaps.fHasDlgVideoDisplay)capDlgVideoDisplay(ghWndCap); // Video display 对话框// capFileSetCaptureFile( ghWndCap, szCaptureFile); //将要保存的文件名设为本源文件开头处的全局字符串常量// capFileAlloc(ghWndCap, (1024L * 1024L * 5)); //为捕获文件分配存储空间capCaptureSequence(ghWndCap); //开始捕获视频序列// capGrabFrame(ghWndCap); //捕获单帧图像SetTimer(hwnd,1,10,TimerProc);break;case WM_PAINT:capGrabFrame(ghWndCap);/* hdc=BeginPaint(hwnd,&ps);GetClientRect(hwnd,&rect);DrawText(hdc,TEXT("Hello,Windows XP!"),-1,&rect,DT_SINGLELINE|DT_CENTER|DT_VCENTER);EndPaint(hwnd,&ps);*/break;case WM_CLOSE:if(IDYES==MessageBox(hwnd,"Sure exit ?","CamCapture",MB_YESNO)){DestroyWindow(hwnd);}break;case WM_DESTROY:KillTimer(hwnd,1);capSetCallbackOnStatus(ghWndCap,NULL);capSetCallbackOnError(ghWndCap,NULL);capSetCallbackOnFrame(ghWndCap,NULL);capCaptureAbort(ghWndCap);//停止捕获capDriverDisconnect(ghWndCap); //将捕获窗同驱动断开PostQuitMessage(0);break;default:return DefWindowProc(hwnd,uMsg,wParam,lParam);}return 0;}//主函数int WINAPI WinMain(HINSTANCE hInstance, // handle to current instanceHINSTANCE hPrevInstance, // handle to previous instanceLPSTR lpCmdLine, // command lineint nCmdShow // show state){static TCHAR szAppName[]=TEXT("CamCapture");WNDCLASS wndcls;HWND hwnd;MSG msg;wndcls.cbClsExtra=0;wndcls.cbWndExtra=0;wndcls.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);wndcls.hCursor=LoadCursor(NULL,IDC_CROSS);wndcls.hIcon=LoadIcon(NULL,IDI_QUESTION);wndcls.hInstance=hInstance;wndcls.lpfnWndProc=WindowProc;wndcls.lpszClassName="CamCapture";wndcls.lpszMenuName=NULL;wndcls.style=CS_HREDRAW | CS_VREDRAW;if(!RegisterClass(&wndcls)){MessageBox(NULL,TEXT("This program requires Windows NT!"),szAppName,MB_ICONERROR);return 0;}hwnd=CreateWindow("CamCapture","CamCapture",WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,CW_USEDEFAULT,320,240,NULL,NULL,hInstance,NULL);ShowWindow(hwnd,nCmdShow);UpdateWindow(hwnd);while(GetMessage(&msg,NULL,0,0)){TranslateMessage(&msg);DispatchMessage(&msg);}return 0;}。
C语言视频编程掌握在C语言中处理视频数据的方法C语言是一种广泛应用于嵌入式系统和底层编程的编程语言,它也可以用于处理和操控视频数据。
在本文中,我们将重点介绍C语言中处理视频数据的方法和技巧。
一、视频数据的表示和存储在C语言中处理视频数据之前,我们首先需要了解视频数据的表示和存储方式。
视频数据通常由一系列图像帧组成,每个图像帧由像素组成。
常见的视频存储格式包括AVI、MP4等,它们在存储视频数据时采用了特定的压缩算法。
二、读取视频文件要在C语言中处理视频数据,我们首先需要读取视频文件。
可以利用C语言提供的文件操作函数来读取二进制文件,对于视频文件来说,我们需要了解其文件结构和格式,然后使用相应的文件操作函数读取并解析视频文件的头部信息和帧数据。
三、处理视频帧当成功读取视频文件后,我们需要对每一帧的像素进行处理。
视频帧通常采用RGB、YUV等格式来表示。
在C语言中,我们可以利用指针和数组来访问和修改视频帧中的像素。
例如,可以使用双层循环遍历每个像素,并对像素进行操作,如图像增强、滤波等。
四、视频编码和解码在视频处理过程中,编码和解码是不可或缺的环节。
视频编码是将视频数据压缩为较小的文件大小,以方便存储和传输;而视频解码则是将压缩后的视频数据还原为原始的视频图像。
在C语言中,我们可以使用第三方库或自行实现视频编码和解码算法,如使用FFmpeg库进行视频编码和解码操作。
五、视频特效处理除了基本的视频处理操作外,C语言还可以实现一些高级的视频特效处理。
例如,可以使用C语言实现图像变形、颜色转换、镜像翻转等特效操作。
这些特效处理可以为视频增添艺术效果,提升用户的观看体验。
六、视频合成和输出当完成视频的处理后,我们需要将处理后的视频重新合成为一个完整的视频文件,并输出到显示设备或保存到磁盘中。
在C语言中,可以使用文件操作函数创建新的视频文件,并将处理好的视频帧逐帧写入到文件中,最终生成一个输出视频文件。
小结:在本文中,我们介绍了C语言中处理视频数据的方法和技巧。
一、你要有视频捕捉设备二、正确安装在你的电脑上。
三、新建一个VB项目,添加一个ModulePrivate Declare Function capCreateCaptureWindow Lib "avicap32.dll" _ Alias "capCreateCaptureWindowA" ( _ByVal lpszWindowName As String, _ByVal dwStyle As Long, _ByVal x As Long, _ByVal y As Long, _ByVal nWidth As Long, _ByVal nHeight As Long, _ByVal hWndParent As Long, _ByVal nID As Long) As LongPrivate Const WS_CHILD = &H40000000Private Const WS_VISIBLE = &H10000000Private Const WM_USER = &H400Private Const WM_CAP_START = &H400Private Const WM_CAP_EDIT_COPY = (WM_CAP_START + 30)Private Const WM_CAP_DRIVER_CONNECT = (WM_CAP_START + 10) Private Const WM_CAP_SET_PREVIEWRATE = (WM_CAP_START + 52) Private Const WM_CAP_SET_OVERLAY = (WM_CAP_START + 51) Private Const WM_CAP_SET_PREVIEW = (WM_CAP_START + 50) Private Const WM_CAP_DRIVER_DISCONNECT = (WM_CAP_START + 11)Private Declare Function SendMessage Lib "user32" _Alias "SendMessageA" ( _ByVal hwnd As Long, _ByVal wMsg As Long, _ByVal wParam As Long, _lParam As Any) As LongPrivate Preview_Handle As LongPublic Function CreateCaptureWindow( _hWndParent As Long, _Optional x As Long = 0, _Optional y As Long = 0, _Optional nWidth As Long = 320, _Optional nHeight As Long = 240, _Optional nCameraID As Long = 0) As LongPreview_Handle = capCreateCaptureWindow("Video", _WS_CHILD + WS_VISIBLE, x, y, _nWidth, nHeight, hWndParent, 1)SendMessage Preview_Handle, WM_CAP_DRIVER_CONNECT, nCameraID, 0 SendMessage Preview_Handle, WM_CAP_SET_PREVIEWRATE, 30, 0SendMessage Preview_Handle, WM_CAP_SET_OVERLAY, 1, 0SendMessage Preview_Handle, WM_CAP_SET_PREVIEW, 1, 0CreateCaptureWindow = Preview_HandleEnd FunctionPublic Function CapturePicture(nCaptureHandle As Long) As StdPictureClipboard.ClearSendMessage nCaptureHandle, WM_CAP_EDIT_COPY, 0, 0Set CapturePicture = Clipboard.GetDataEnd FunctionPublic Sub Disconnects(nCaptureHandle As Long, _Optional nCameraID = 0)SendMessage nCaptureHandle, WM_CAP_DRIVER_DISCONNECT, _nCameraID, 0End Sub四、在form上添加一个PictureBox命名为PicCapture,一个按钮,Caption设为Save Pic Dim Video_Handle As LongPrivate Sub Form_Load()Video_Handle = CreateCaptureWindow(PicCapture.hwnd)End SubPrivate Sub Command1_Click()Dim x As StdPictureSet x = CapturePicture(Video_Handle)SavePicture x, "c:\a.bmp"End SubPrivate Sub Form_Unload(Cancel As Integer)Disconnect Video_HandleEnd Sub。
、吣。
多媒体技术及其应用..。
..本栏目责任编辑:李桂瑾基于VB6.0下的对网络摄像头视频捕捉王海峰。
章怡(江苏技术师范学院信息与教育技术中心,江苏常州213001)摘要:随着通信技术与多媒体技术的飞速发展,以多媒体视频为主的应用得到了广阔的发展,在这些视频应用领域中,若想进行图像处理就要先进行视频捕获。
鉴于此.文章对windows系统下的vFw体系结构进行了论述、给出了视频开发的相关windowsAPI函数,分析了视频捕获的工作流程:并用Ⅶ来设计和实现视频捕捉程序,具体的给出了程序的代码,最后给出了测试结果,证明是可以捕捉的关键词:VFW;视频捕捉;WindowsApI;AVICap中图分类号:TP393文献标识码:A文章编号:1009—3044(2007)15—3854一02VideOCaOtureofNetwork—vidicOnBasedOnVB6。
0WANGHai—feng,ZHANGYi(InfomntionandEducationalTechniqueCenter,Jian铲uTeachersuniverSicyofTechn0109y’Changzhou213001,china)’AbStract:WiththerapiddeveIopmentofcommunjcationandmultimediatechnique,theapphca七ionofthemultimediaVideogotbroadde—velopment,inthedomainof试deoapplication,supposetocarryirmgemampuladon,must丘rstimplementtheVideocapture.consequently,thearticlehasca玎iedtheelaborationtoVFW郸stemstmctureundertheWindowssystem,hasproducedWmdowsAPIfunctionaboutvideocapcure,hasanalyzedcheworbngprocessofchevideocapcure;videocapcurepmgmmmehasbeendesignedandjmplemencwi出Ⅷ,programmecode如§beenproduced.Finally,theresultofVideo乒aptureisfeasibl己Keywords:VpW;videocapture;WindowsAPImnction;AVICap1引言1992年.Microsoft公司发布了VideoforWindowsf以下简称VFWl,使得任何PC机都能在无特定硬件支持的条件下播放视频画面。
#include"cv.h"#include"cxcore.h"#include"highgui.h"#include<iostream>using namespace std;int main(){CvCapture* capture1=cvCaptureFromCAM(0);CvCapture* capture2=cvCaptureFromCAM(1);CvVideoWriter* video1=NULL;CvVideoWriter* video2=NULL;IplImage* frame1=NULL;IplImage* frame2=NULL;int m, n;if((!capture1)||(!capture1)) //如果不能打开摄像头则给出警告{cout<<"Can not open the camera."<<endl;return -1;}else{frame1=cvQueryFrame(capture1); //首先取得摄像头的一帧frame2=cvQueryFrame(capture2);video1=cvCreateVideoWriter("camera1.avi", CV_FOURCC('X', 'V', 'I', 'D'), 25, cvSize(frame1->width,frame1->height));video2=cvCreateVideoWriter("camera2.avi", CV_FOURCC('X', 'V', 'I', 'D'), 25, cvSize(frame2->width,frame2->height)); //创建CvVideoWriter对象并分配存储空间if(video1&&video2) // {cout<<"VideoWriter has created."<<endl;}cvNamedWindow("Camera1 Video",1);cvNamedWindow("Camera2 Video",1);while(1){frame1=cvQueryFrame(capture1);frame2=cvQueryFrame(capture2);if((!frame1) || (!frame2)){cout<<"Can not get frame from the capture."<<endl;break;}m=cvWriteFrame(video1,frame1);n=cvWriteFrame(video2,frame2);cout<<m<<endl;cout<<n<<endl;cvShowImage("Camera1 Video",frame1);cvShowImage("Camera2 Video",frame2);if(cvWaitKey(2)>0)break;}cvReleaseVideoWriter(&video1);cvReleaseVideoWriter(&video2);cvReleaseImage(&frame1);cvReleaseImage(&frame2);cvReleaseCapture(&capture1);cvReleaseCapture(&capture2);cvDestroyWindow("Camera1 Video");cvDestroyWindow("Camera2 Video");}return 0;}。
c++ 编写连接摄像头的通用方法摘要:1.摄像头连接概述2.准备工作3.实现通用连接方法4.代码示例及解析5.总结与拓展正文:【摄像头连接概述】在本文中,我们将介绍一种通用的C++编写连接摄像头的方法。
摄像头连接主要包括以下几个步骤:准备工作、实现通用连接方法、代码示例及解析、总结与拓展。
通过本文,读者可以了解到如何使用C++编写程序实现摄像头连接,并实现基本视频捕捉功能。
【准备工作】在进行摄像头连接之前,我们需要做好以下准备工作:1.安装适当的驱动程序:根据摄像头型号和操作系统,确保安装了正确的驱动程序。
2.导入必要的库:我们需要使用一些库来实现摄像头连接,如OpenCV。
在使用OpenCV之前,需要先安装相应版本的库文件。
3.配置开发环境:安装C++编译器,并配置好开发环境。
【实现通用连接方法】在C++中,我们可以使用以下通用方法连接摄像头:1.初始化库:引入OpenCV库,并初始化cv::VideoCapture对象。
2.打开摄像头:使用cv::VideoCapture::open()方法尝试打开摄像头。
3.检查摄像头是否成功打开:通过检查cv::VideoCapture对象的是否为null来判断摄像头是否成功打开。
4.释放资源:在程序结束时,释放摄像头资源,关闭cv::VideoCapture对象。
【代码示例及解析】以下是一个简单的C++代码示例,演示了如何实现摄像头连接:```cpp#include <iostream>#include <opencv2/opencv.hpp>int main() {// 初始化库cv::Mat frame;cv::VideoCapture cap(0); // 0表示默认摄像头// 检查摄像头是否成功打开if (!cap.isOpened()) {std::cout << "摄像头未打开,请检查摄像头是否正确连接。
前言DirectShow是微软公司提供的一套在Windows平台上进行流媒体处理的开发包,与DirectX开发包一起发布。
DirectShow为多媒体流的捕捉和回放提供了强有力的支持。
用DirectShow开发应用程序,我们可以很方便地从支持WDM驱动模型的采集卡上捕获数据,并且进行相应的后期处理乃至存储到文件中。
DirectShow是基于COM的,为了编写DirectShow应用程序,需要了解COM客户程序编写的基础知识。
DirectShow提供了大量的接口,但在编程中发现还是不够方便,如果能构建一个视频捕捉类把常用的一些动作封装起来,那么就更方便了。
编程思路为了更加容易建立视频捕捉应用程序,DirectShow提供了一个叫做Capture Graph Builder的对象,Capture Graph Builder提供IcaptureGraphBuilder2接口,该接口可以建立和控制Capture Graph。
建立视频捕捉程序,必须首先获取并初始化IcaptureGraphBuilder2接口,然后选择一个适当的视频捕捉设备。
选择好设备后,为该设备创建Capture filter,然后调用AddFilter把Capture filter添加到Filter Graph。
如果仅仅希望用摄像头来进行实时监控的话,只需要在上面的基础上调用DirectShow提供了一个捕捉静态图像的方法:使用Sample Grabber filter。
依次按照以下三个步骤就可以了:第一步, 定义一个类实现Sample Grabber的回调接口IsampleGrabberCB:第二步、调用RenderStream依次把Still pin、Sample Grabber和系统默认Renderer Filter连接起来。
第三步、配置Sample Grabber以捕获数据。
视频捕捉类CCaptureVideo的具体实现// CCaptureVideo视频捕捉类头文件/////////////////////////////////////////////////////////////////////#if !defined(AFX_CAPTUREVIDEO_H__F5345AA4_A39F_4B07_B843_3D87C4287AA0__INC LUDED_)#defineAFX_CAPTUREVIDEO_H__F5345AA4_A39F_4B07_B843_3D87C4287AA0__INCLUDED_/////////////////////////////////////////////////////////////////////// CaptureVideo.h : header file/////////////////////////////////////////////////////////////////////#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000#include <atlbase.h>#include <windows.h>#include <dshow.h>#ifndef SAFE_RELEASE#define SAFE_RELEASE( x ) \if ( NULL != x ) \{ \x->Release( ); \x = NULL; \}#endifclass CSampleGrabberCB;class CCaptureVideo : public CWnd{friend class CSampleGrabberCB;public:void GrabOneFrame(BOOL bGrab);HRESULT Init(int iDeviceID,HWND hWnd);int EnumDevices(HWND hList);CCaptureVideo();virtual ~CCaptureVideo();private:HWND m_hWnd;IGraphBuilder *m_pGB;ICaptureGraphBuilder2* m_pCapture;IBaseFilter* m_pBF;IMediaControl* m_pMC;IVideoWindow* m_pVW;CComPtr<ISampleGrabber> m_pGrabber;protected:void FreeMediaType(AM_MEDIA_TYPE& mt);bool BindFilter(int deviceId, IBaseFilter **pFilter);void ResizeVideoWindow();HRESULT SetupVideoWindow();HRESULT InitCaptureGraphBuilder();};#endif// !defined(AFX_CAPTUREVIDEO_H__F5345AA4_A39F_4B07_B843_3D87C4287AA0__INCL UDED_)//-------------------------------------------------------------------// CCaptureVideo视频捕捉类实现文件CaptureVideo.cpp//-------------------------------------------------------------------// CaptureVideo.cpp: implementation of the CCaptureVideo class.///////////////////////////////////////////////////////////////////////#include "stdafx.h"#include "CaptureVideo.h"#ifdef _DEBUG#undef THIS_FILEstatic char THIS_FILE[]=__FILE__;#define new DEBUG_NEW#endifBOOL bOneShot=FALSE;//全局变量class CSampleGrabberCB : public ISampleGrabberCB{public:long lWidth;long lHeight;TCHAR m_szFileName[MAX_PATH];// 位图文件名称CSampleGrabberCB( ){strcpy(m_szFileName, "c:\\donaldo.bmp");}STDMETHODIMP_(ULONG) AddRef() { return 2; }STDMETHODIMP_(ULONG) Release() { return 1; }STDMETHODIMP QueryInterface(REFIID riid, void ** ppv){if( riid == IID_ISampleGrabberCB || riid == IID_IUnknown ){*ppv = (void *) static_cast<ISampleGrabberCB*> ( this );return NOERROR;}return E_NOINTERFACE;}STDMETHODIMP SampleCB( double SampleTime, IMediaSample * pSample ){ return 0;}STDMETHODIMP BufferCB( double dblSampleTime, BYTE * pBuffer, long lBufferSize ){ if( !bOneShot )return 0;if (!pBuffer)return E_POINTER;SaveBitmap(pBuffer, lBufferSize);bOneShot = FALSE;return 0;}//创建位图文件BOOL SaveBitmap(BYTE * pBuffer, long lBufferSize ){HANDLE hf = CreateFile(m_szFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL,CREATE_ALWAYS, NULL, NULL );if( hf == INVALID_HANDLE_VALUE )return 0;// 写文件头BITMAPFILEHEADER bfh;memset( &bfh, 0, sizeof( bfh ) );bfh.bfType = ’MB’;bfh.bfSize = sizeof( bfh ) + lBufferSize + sizeof( BITMAPINFOHEADER );bfh.bfOffBits = sizeof( BITMAPINFOHEADER ) + sizeof( BITMAPFILEHEADER );DWORD dwWritten = 0;WriteFile( hf, &bfh, sizeof( bfh ), &dwWritten, NULL );// 写位图格式BITMAPINFOHEADER bih;memset( &bih, 0, sizeof( bih ) );bih.biSize = sizeof( bih );bih.biWidth = lWidth;bih.biHeight = lHeight;bih.biPlanes = 1;bih.biBitCount = 24;WriteFile( hf, &bih, sizeof( bih ), &dwWritten, NULL );// 写位图数据WriteFile( hf, pBuffer, lBufferSize, &dwWritten, NULL );CloseHandle( hf );return 0;}};CSampleGrabberCB mCB;//////////////////////////////////////////////////////////////////////// Construction/Destruction//////////////////////////////////////////////////////////////////////CCaptureVideo::CCaptureVideo(){//COM Library Intializationif(FAILED(CoInitialize(NULL))) /*, COINIT_APARTMENTTHREADED)))*/{AfxMessageBox("CoInitialize Failed!\r\n");return;}m_hWnd = NULL;m_pVW = NULL;m_pMC = NULL;m_pGB = NULL;m_pCapture = NULL;}CCaptureVideo::~CCaptureVideo(){// Stop media playbackif(m_pMC)m_pMC->Stop();if(m_pVW){m_pVW->put_Visible(OAFALSE);m_pVW->put_Owner(NULL);}SAFE_RELEASE(m_pCapture);SAFE_RELEASE(m_pMC);SAFE_RELEASE(m_pGB);SAFE_RELEASE(m_pBF);CoUninitialize( );}int CCaptureVideo::EnumDevices(HWND hList){if (!hList)return -1;int id = 0;//枚举视频扑捉设备ICreateDevEnum *pCreateDevEnum;HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,CLSCTX_INPROC_SERVER,IID_ICreateDevEnum, (void**)&pCreateDevEnum);if (hr != NOERROR)return -1;CComPtr<IEnumMoniker> pEm;hr = pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,&pEm, 0);if (hr != NOERROR)return -1;pEm->Reset();ULONG cFetched;IMoniker *pM;while(hr = pEm->Next(1, &pM, &cFetched), hr==S_OK){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){TCHAR str[2048];id++;WideCharToMultiByte(CP_ACP,0,var.bstrVal, -1, str, 2048, NULL, NULL);::SendMessage(hList, CB_ADDSTRING, 0,(LPARAM)str);SysFreeString(var.bstrVal);}pBag->Release();}pM->Release();}return id;}HRESULT CCaptureVideo::Init(int iDeviceID, HWND hWnd){HRESULT hr;hr = InitCaptureGraphBuilder();if (FAILED(hr)){AfxMessageBox("Failed to get video interfaces!");return hr;}// Bind Device Filter. We know the device because the id was passed inif(!BindFilter(iDeviceID, &m_pBF))return S_FALSE;hr = m_pGB->AddFilter(m_pBF, L"Capture Filter");// hr = m_pCapture->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video,// m_pBF, NULL, NULL);// create a sample grabberhr = m_pGrabber.CoCreateInstance( CLSID_SampleGrabber );if( !m_pGrabber ){AfxMessageBox("Fail to create SampleGrabber, maybe qedit.dll is not registered?");return hr;}CComQIPtr< IBaseFilter, &IID_IBaseFilter > pGrabBase( m_pGrabber );//设置视频格式AM_MEDIA_TYPE mt;ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));mt.majortype = MEDIATYPE_Video;mt.subtype = MEDIASUBTYPE_RGB24;hr = m_pGrabber->SetMediaType(&mt);if( FAILED( hr ) ){AfxMessageBox("Fail to set media type!");return hr;}hr = m_pGB->AddFilter( pGrabBase, L"Grabber" );if( FAILED( hr ) ){AfxMessageBox("Fail to put sample grabber in graph");return hr;}// try to render preview/capture pinhr = m_pCapture->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video,m_pBF,pGrabBase,NULL);if( FAILED( hr ) )hr = m_pCapture->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video,m_pBF,pGrabBase,NULL);if( FAILED( hr ) ){AfxMessageBox("Can’t build the graph");return hr;}hr = m_pGrabber->GetConnectedMediaType( &mt );if ( FAILED( hr) ){AfxMessageBox("Failt to read the connected media type");return hr;}VIDEOINFOHEADER * vih = (VIDEOINFOHEADER*) mt.pbFormat;mCB.lWidth = vih->bmiHeader.biWidth;mCB.lHeight = vih->bmiHeader.biHeight;FreeMediaType(mt);hr = m_pGrabber->SetBufferSamples( FALSE );hr = m_pGrabber->SetOneShot( FALSE );hr = m_pGrabber->SetCallback( &mCB, 1 );//设置视频捕捉窗口m_hWnd = hWnd ;SetupVideoWindow();hr = m_pMC->Run();//开始视频捕捉if(FAILED(hr)){AfxMessageBox("Couldn’t run the graph!");return hr;}return S_OK;}bool CCaptureVideo::BindFilter(int deviceId, IBaseFilter **pFilter){if (deviceId < 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 <= deviceId){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 == deviceId){pM->BindToObject(0, 0, IID_IBaseFilter, (void**)pFilter);}SysFreeString(var.bstrVal);}pBag->Release();}pM->Release();index++;}return true;}HRESULT CCaptureVideo::InitCaptureGraphBuilder(){HRESULT hr;// 创建IGraphBuilder接口hr=CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&m_pGB);// 创建ICaptureGraphBuilder2接口hr = CoCreateInstance (CLSID_CaptureGraphBuilder2 , NULL, CLSCTX_INPROC,IID_ICaptureGraphBuilder2, (void **) &m_pCapture);if (FAILED(hr))return hr;m_pCapture->SetFiltergraph(m_pGB);hr = m_pGB->QueryInterface(IID_IMediaControl, (void **)&m_pMC);if (FAILED(hr))return hr;hr = m_pGB->QueryInterface(IID_IVideoWindow, (LPVOID *) &m_pVW);if (FAILED(hr))return hr;return hr;}HRESULT CCaptureVideo::SetupVideoWindow(){HRESULT hr;hr = m_pVW->put_Owner((OAHWND)m_hWnd);if (FAILED(hr))return hr;hr = m_pVW->put_WindowStyle(WS_CHILD | WS_CLIPCHILDREN);if (FAILED(hr))return hr;ResizeVideoWindow();hr = m_pVW->put_Visible(OATRUE);return hr;}void CCaptureVideo::ResizeVideoWindow(){if (m_pVW){//让图像充满整个窗口CRect rc;::GetClientRect(m_hWnd,&rc);m_pVW->SetWindowPosition(0, 0, rc.right, rc.bottom);}}void CCaptureVideo::GrabOneFrame(BOOL bGrab){bOneShot = bGrab;}void CCaptureVideo::FreeMediaType(AM_MEDIA_TYPE& mt){if (mt.cbFormat != 0) {CoT askMemFree((PVOID)mt.pbFormat);// Strictly unnecessary but tidiermt.cbFormat = 0;mt.pbFormat = NULL;}if (mt.pUnk != NULL) {mt.pUnk->Release();mt.pUnk = NULL;}}如何使用视频捕捉类CCaptureVideo构建CCaptureVideo类以后,使用就方便多了,我们在编程中只需要是要下面三个类成员函数就可以实现用摄像头进行视频捕捉:①int EnumDevices(HWND hList); //hList是下拉列表框的句柄,本函数用于枚举当前系统安装的所有视频捕捉设备②HRESULT Init(int iDeviceID,HWND hWnd);//iDeviceID是视频捕捉设备序号,hWnd是视频捕捉窗口的句柄③void GrabOneFrame(BOOL bGrab);//调用GrabOneFrame(true)就可以捕获当前的静态图像并保存到硬盘上具体示例:用MFC AppWizard(exe)创建一个对话框应用程序,取名为ds,给对话框添加一个下拉列表框(IDC_COMBO1)、两个按钮(IDC_PHOTO、IDC_HAVEALOOK)和一个Picture控件(ID:IDC_STATIC_SCREEN,Type: Rectangle,Color:Gray)。