鄙人今日尝试使用openCV调用摄像头做图片中圆的圆心位置检测时,意外发现程序能成功调用笔记的集成摄像头,但却无法调用外接的USB摄像头。(使用的为OpenCV1.0 + VC6.0)
使用程序如下:
#include"cv.h"
#include"highgui.h"
#include"cvcam.h"
#include"iostream"
using namespace std;
int main(int argc,char* argv[])
{
CvCapture* cap;
cap=cvCaptureFromCAM(0);
//cap=cvCreateCameraCapture(1); //使用该函数与上面函数效果一样
if(!cap)
{
cout<<"create camera capture error"<<endl;
system("pause");
exit(-1);
}
cvNamedWindow("example",1);
IplImage* img;
//sleep(2000);
while(1)
{
img=cvQueryFrame(cap);//捕获相机的视频帧,并进行解码操作
// img=cvLoadImage("F:\\360云盘\\图片\\20083281447418_2.jpg"); //直接读取图片
if(!img)
break;
if(img->origin==IPL_ORIGIN_TL)//如果图片原点在左上角,将其沿X轴翻转,使左下角
{
cvFlip(img,img);
}
cvShowImage("example",img);
cvWaitKey(30);
IplImage*gray =cvCreateImage( cvGetSize(img),8,1);
CvMemStorage*storage = cvCreateMemStorage(0);
cvCvtColor(img,gray,CV_BGR2GRAY);
cvSmooth(gray,gray,CV_GAUSSIAN,5,15);
CvSeq*circles = cvHoughCircles(gray,storage,CV_HOUGH_GRADIENT,2,gray->height/4,200,100);
int i;
for (i=0; i< circles->total; i++)
{
float*p = (float*)cvGetSeqElem(circles,i);
cvCircle(img, cvPoint(cvRound(p[0]),cvRound(p[1])),3, CV_RGB(0,255,0), -1, 8, 0);
cvCircle(img, cvPoint(cvRound(p[0]),cvRound(p[1])),cvRound(p[2]), CV_RGB(255,0,0), 3, 8, 0);
cout<<"圆心坐标x="<<cvRound(p[0])<<endl<<"圆心坐标y= "<<cvRound(p[1])<<endl;
cout<<"半径="<<cvRound(p[2])<<endl;
}
cout<<"圆数量= "<<circles->total<<endl;
cvWaitKey(10);
}
cvReleaseCapture(&cap);
cvDestroyAllWindows();
cvReleaseImage(&img);
return 0;
}
关于程序中函数cap=cvCaptureFromCAM(0) 的参数,有人认为设置为0时调用的是集成摄像头,设置为1的时候调用的是USB摄像头,只有一个摄像头时则设置为-1;
但在本机上实验时发现,设置为0和-1时均调用的是集成摄像头,而设置为1时则显示调用错误“create camera capture error”;
目前解决办法主要有两条
1、采用VS2010 + OpenCV2.3.1的配置显示可以调用USB摄像头,成功时出现Support SSE4.3的字符串。
另外网上有人提出可能是使用的是win7的原因不支持OpenCV1.0,改为采用XP系统能解决该问题。但本人在xp系统上尝试却是不成功的,说明系统兼容性并不是问题的根本。 分析更有可能是之前openCV低版本无法支撑高版本的USB摄像头。
2、采用DirectShow可以直接在win7 + VC6.0 + OpenCV1.0上显示USB摄像头,
使用程序如下:
#include "cxcore.h"
#include "cvcam.h"
#include "windows.h"
#include "cv.h"
#include "highgui.h"
#include "iostream"
using namespace std;
IplImage* image;
void callback(IplImage* image);
int main()
{
int ncams = cvcamGetCamerasCount( );//返回可以访问的摄像头数目
int width=640;
int height=480;
HWND MyWin;
// 设置系统属性
cvcamSetProperty(0, CVCAM_PROP_ENABLE, CVCAMTRUE); //Enable视讯
//0:欲设置属性的摄像头序号; 第二个参数是属性名字;
//第三个参数是指向设置值的指针
cvcamSetProperty(0, CVCAM_PROP_RENDER, CVCAMTRUE); //启用视讯
// MyWin 是窗口 HWND 的类型
MyWin = (HWND) cvGetWindowHandle("cvcam window");
cvcamSetProperty(0, CVCAM_PROP_WINDOW, &MyWin); // Selects a window
cvcamSetProperty(0,CVCAM_RNDWIDTH,&width);
cvcamSetProperty(0,CVCAM_RNDHEIGHT,&height);
//video rendering
//回调函数将处理每一帧
cvcamSetProperty(0, CVCAM_PROP_CALLBACK, callback);
cvcamInit( );
cvcamStart( );
IplImage*gray =cvCreateImage( cvGetSize(image),8,1);
CvMemStorage*storage = cvCreateMemStorage(0);
cvCvtColor(image,gray,CV_BGR2GRAY);
cvSmooth(gray,gray,CV_GAUSSIAN,5,15);
CvSeq*circles = cvHoughCircles(gray,storage,CV_HOUGH_GRADIENT,2,gray->height/4,200,100);
int i;
for (i=0; i< circles->total; i++)
{
float*p = (float*)cvGetSeqElem(circles,i);
cvCircle(image, cvPoint(cvRound(p[0]),cvRound(p[1])),3, CV_RGB(0,255,0), -1, 8, 0);
cvCircle(image, cvPoint(cvRound(p[0]),cvRound(p[1])),cvRound(p[2]), CV_RGB(255,0,0), 3, 8, 0);
cout<<"圆心坐标x="<<cvRound(p[0])<<endl<<"圆心坐标y= "<<cvRound(p[1])<<endl;
cout<<"半径="<<cvRound(p[2])<<endl;
}
cout<<"圆数量= "<<circles->total<<endl;
cvWaitKey(100);
// 现在程序开始工作
cvWaitKey(0);
cvcamStop( );
cvcamExit( );
return 0;
}
// 回调函数
void callback(IplImage* image)
{
cvcamPause();
cvcamGetProperty(0,"raw_image",&image);
cvcamResume();
}
但是上段程序中摄像头每帧图像的地址还不清楚是不是*image,故目前仍然没有将圆心位置检测的程序段加入进去。
DirectShow是微软公司在ActiveMovie和Video for Windows的基础上推出的新一代基于COM(Component Object Model)的流媒体处理的开发包,与DirectX开发包一起发布。而OpenCV是一个计算机视觉的处理库,被广泛应用到各种计算机视觉的研究和应用当中。OpenCV可以利用DirectShow来采集摄像头视频,这比采用OpenCV里的采集视频数据函数要好用。这是我个人的看法。