在Opencv中文网站上有关于directShow和opencv结合采集图像的教程,地址:http://wiki.opencv.org.cn/index.php/%e4%bd%bf%e7%94%a8DirectShow%e9%87%87%e9%9b%86%e5%9b%be%e5%83%8f
但是该配置比较老,本文讲述如何基于该教程在 VS2012和opencv2.4.9上进行配置和修改,完成USB摄像头的驱动。
文末有完整代码的下载地址
在Opencv中文网站上有关于directShow和opencv结合采集图像的教程,地址:http://wiki.opencv.org.cn/index.php/%e4%bd%bf%e7%94%a8DirectShow%e9%87%87%e9%9b%86%e5%9b%be%e5%83%8f
但说明中的“本文档介绍的CCameraDS类调用采集函数可直接返回IplImage,使用更方便,且集成了DirectShow,勿需安装庞大的DirectX/Platform SDK”并不靠谱,DirectShow 似乎已经开始被微软给淘汰了,最后存在是在多年前的 DirectX 9.0b 包里。
注意这里并不需要下载DirectX 9.0包,下面介绍在VS2012和opencv2.4.9下的配置过程。
按照网上流行的配置即可,如http://www.sigvc.org/bbs/thread-529-1-1.html 。配置好之后尝试运行一个打开图片的小程序检测opencv环境是否配置成功。
新建工程,配置好Opencv环境,随后将从Opencv中文网上下载的 CameraDS.h 和 CameraDS.cpp 文件分别添加到项目的头文件和源文件中。
VS2012旗舰版是自带了 SDK 的,在 C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Include。
打开建立的VS2012项目的属性页,找到“VC++目录”,在“包含目录”里添加 (FrameworkSDKDir)Include,在“库目录”里添加 (FrameworkSDKDir)Lib。
发现#include “qedit.h”报错,原因是现在的版本已经没有qedit.h这个头文件了,从网址:http://download.csdn.net/download/bcj296050240/9651955 中下载该文件,添加到项目的头文件中。
环境配置好之后,可以用 Opencv中文网 上下载的main.cpp运行,运行过程可能遇到const char* 无法转换的问题,将此处的代码去掉即可。
下面是本人编写的main函数,提供了USB相机的打开、监视、图像捕获功能。
参数是 CCameraDS 类的对象。该函数获取相机的数目并且显示相机名称。从输出中我们可以找到USB相机的编号,一般情况下编号为1。
//获取当前可用的摄像头并打开USB摄像头
int initAllCameras(CCameraDS &m_CamDS){
//仅仅获取摄像头数目
int m_iCamCount = CCameraDS::CameraCount();
printf("There are %d cameras.\n", m_iCamCount);
if(m_iCamCount == 0)
{
return -1;
}
//获取所有摄像头的名称
for(int i = 0; i < m_iCamCount; i++)
{
char szCamName[1024];
int retval = m_CamDS.CameraName(i, szCamName, sizeof(szCamName));
if(retval >0)
{
printf("Camera #%d's Name is '%s'.\n", i, szCamName);
}
else
{
printf("Can not get Camera #%d's name.\n", i);
}
}
return m_iCamCount;
}
运行结果如下所示:
There are 3 cameras.
Camera #0's Name is 'Lenovo EasyCamera'.
Camera #1's Name is '3D Camera'.
Camera #2's Name is 'Basler GenICam Source'.
从运行结果中可以看出,使用的3D相机的编号为1。
函数有四个参数,第一个参数为CcameraDS类的对象,camNum设置为1,表明现在要打开的USB相机,而不是电脑自带相机。camWidth和camHeight根据自己所使用相机的情况进行设置,设置为图像的宽度和高度。
代码如下:
// 打开 USB 相机 !! 在调用 camDisplay 和 camCapPic 之前必须调用该函数
// camNum = 1; // 摄像头编号为1,表示当前要使用的是 USB 摄像头
// camWidth = 2560; // 图片宽度
// camHeight = 720; // 图片高度
int openUsbCam(CCameraDS &m_CamDS, const int camNum=1, const int camWidth=2560, const int camHeight = 720){
// 获取当前可用的相机个数
// 在所有的相机中,一般编号为 0 的为电脑自带摄像头,编号为 1 的为要使用的 USB 摄像头
int m_iCamCount = initAllCameras(m_CamDS);
if(m_iCamCount == -1){
cout<<"没有可用的摄像头! 退出.."<return -1;
}
Mat pFrame;
// 打开相机并拍摄一幅图片
if((!m_CamDS.OpenCamera(camNum, false, camWidth, camHeight)) || (m_CamDS.QueryFrame() == NULL)){
cout<<"# "<" 号相机无法打开,程序退出..";
return -2;
}
return 1;
}
函数有两个参数,第一个参数是CcameraDS类的对象,第二个参数是时间,默认为每隔20ms拍摄一幅图片。
在显示的过程中,按任意键可以退出。可以根据自己的要求进行修改,比如修改成按任意键保存当前图片。
// 显示相机视场的内容 每隔20毫秒显示一帧
int camDisplay(CCameraDS &m_CamDS, const int t=20){
Mat pFrame;
while(1)
{
//获取一帧
pFrame = Mat(m_CamDS.QueryFrame());
//显示
imshow("Camera", pFrame);
//延迟,如果有键按下,退出
if(cv::waitKey(t) != -1)
break;
}
//m_CamDS.CloseCamera(); //可不调用此函数,CCameraDS析构时会自动关闭摄像头
cv::destroyAllWindows();
return 0;
}
实现获取一帧图片显示并保存,保存路径有filename设置。
// 抓取图片 并保存到 filename 路径中
int camCapPic(CCameraDS &m_CamDS, string filename="USBcam.jpg"){
Mat pFrame;
//获取一帧
pFrame = Mat(m_CamDS.QueryFrame());
//显示
imshow("抓取图片", pFrame);
waitKey(1000);
destroyAllWindows();
//抓取图片保存
imwrite(filename, pFrame);
//m_CamDS.CloseCamera(); //可不调用此函数,CCameraDS析构时会自动关闭摄像头
return 0;
}
调用顺序为,首先实例化对象,然后打开摄像头(调用openUsbCam函数)。
打开摄像头后,可以根据自己的需要调用不同的函数,如果要实时显示,则调用camDisplay函数,如果要抓取图像保存,则调用camCapPic函数。
注意在调用这些函数时,使用的是同一个CCameraDS的对象。
注意在函数中不要轻易调用CloseCamera()函数,该函数会释放打开的USB摄像头。如果释放后要重新捕获图片,需要再次调用openUsbCam函数。
int main(){
CCameraDS m_CamDS;
// 打开USB摄像头
openUsbCam(m_CamDS);
// 1.0 显示相机内容
cout<"显示相机内容..."<cout<<"显示相机内容 退出..."<// 2.0 抓取图片保存
string filename = "USBcam.jpg";
cout<<"抓取图片保存..."<cout<<"抓取图片保存 退出... 文件路径 "<cout<"结束..."<return 0;
}