多个摄像头同步工作【转】

因项目需要采集2个摄像头的数据进行双目检测,一开始采用以下代码来测试:

#include "stdafx.h"

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

int main(int argc, _TCHAR* argv[])
{
CvCapture* capture1 = cvCreateCameraCapture( 0 );
CvCapture* capture2 = cvCreateCameraCapture( 1 );

double w = 320, h = 240;
cvSetCaptureProperty ( capture1, CV_CAP_PROP_FRAME_WIDTH, w );
cvSetCaptureProperty ( capture1, CV_CAP_PROP_FRAME_HEIGHT, h );
cvSetCaptureProperty ( capture2, CV_CAP_PROP_FRAME_WIDTH, w );
cvSetCaptureProperty ( capture2, CV_CAP_PROP_FRAME_HEIGHT, h );

cvNamedWindow( "Camera_1", CV_WINDOW_AUTOSIZE );
cvNamedWindow( "Camera_2", CV_WINDOW_AUTOSIZE );

IplImage* frame1;
IplImage* frame2;

int n = 2;
while(1)
{
frame1 = cvQueryFrame( capture1 );
if( !frame1 ) break;
cvShowImage( "Camera_1", frame1 );

frame2 = cvQueryFrame( capture2 );
if( !frame2 ) break;
cvShowImage( "Camera_2", frame2 );

int key = cvWaitKey(30);
if( key == 27 ) break;
}
cvReleaseCapture( &capture1 );
cvReleaseCapture( &capture2 );
cvDestroyWindow( "Camera_1" );
cvDestroyWindow( "Camera_2" );

return 0;
}

这个程序在使用不同类型的摄像头时,例如我使用一个普通的网络摄像头,另外一个是手机上的摄像头(这款手机具有网络摄像头功能),这样的话程序就能正常运行;但如果摄像头是相同类型时,就只能读取其中一个摄像头的数据了,第二个窗口则是一片灰色。查阅开发文档资料得知
cvCreateCameraCapture(int index) 函数可以选择摄像头,但实际测试发现 cvCreateCameraCapture 只接受 –1
和 0 两种参数,其他值,如1,2,101,102,201,202...全都无法正确的切换到第二个接入的摄像头。如果两个 capture 都使用
cvCreateCameraCapture(-1),是可以切换到第二个摄像头,但当第二次执行 cvCreateCameraCapture()
函数时,会强行弹出选择摄像头的对话框要你手动选择,而且以后再添加摄像头的话,还得修改代码重新build,实际项目中肯定不能这样处理。在OpenCV中文论坛上找到的解释是,如果摄像头的名称是“USB视频设备
#*”,则 OpenCV  只能读取其中一个的数据。

查阅opencv的cvcam官方文档,找到一些资料:

/*
Begin work with cvcam, you can select single or multiple cameras in 2 ways.
The first is using a camera selection dialog with cvcamSelectCamera. See an example below:
*/

//Prototype
/*
Pops up a camera(s) selection dialog
Return value - number of cameras selected (0,1 or 2);
Argument: an array of selected cameras numbers
NULL if none selected. Should be released with free() when not needed.
if NULL passed, not used.
*/
CVCAM_API int cvcamSelectCamera(int** out);
Function ThatSelectsCamera()
{
int* out;
int nselected = cvcamSelectCamera(&out);
if(nselected>0)
printf("the 1-st selected camera is camera number %d", out[0]);
if(nselected == 2)
printf("the 2-nd selected camera is camera number %d", out[1]);
free(out);
return;
}

/*
Note: if you don’t need selected cameras numbers, simply call cvcamSelectCamera(NULL)
Note2: Linux version of cvcam currently has no implementation of cvcamSelectCamera.
*/

//The second, non-dialog way is to use CVCAM_PROP_ENABLE property like this:
int desiredcamera = 0;//for example cvcamSetProperty(desiredcamera, CVCAM_PROP_ENABLE,CVCAMTRUE);

根据上述说明,我找到了下面这段对应的代码,不过应该是用 VC6+OpenCV1.0
写的,在我的机子上(VS2008+OpenCV2.0)运行不了,不能验证是否有效,不过还是贴出来供大家讨论:

#include <cvcam.h>
#include <cv.h>
#include <highgui.h>
#include "stdio.h"
#include <windows.h>

void StereoCallback(IplImage *frame1,IplImage *frame2);
void onMouse(int Event,int x,int y,int flags,void *param);

IplImage *image1,*image2;

char *strleft[4]={"left1.bmp","left2.bmp","left3.bmp","left4.bmp"};
char *strright[4]={"right1.bmp","right2.bmp","right3.bmp","right4.bmp"};

void main()
{
HWND CaptureWindow1=0;
HWND CaptureWindow2=0;

//int ncams=cvcamGetCamerasCount(); //获取摄像头的个数
//用对话框的形式来选取摄像头 int *CameraNumber;
int nSelected = cvcamSelectCamera(&CameraNumber);

/* //灰色图像
image1=cvCreateImage(cvSize(320,240),IPL_DEPTH_8U,1);
image2=cvCreateImage(cvSize(320,240),IPL_DEPTH_8U,1);
*/

//彩色图像 image1=cvCreateImage(cvSize(320,240),IPL_DEPTH_8U,3);
image2=cvCreateImage(cvSize(320,240),IPL_DEPTH_8U,3);

//初始化两个摄像头 cvNamedWindow("cvcam1 Window",1);
CaptureWindow1=(HWND)cvGetWindowHandle("cvcam1 Window");
cvcamSetProperty(CameraNumber[0], CVCAM_PROP_ENABLE, CVCAMTRUE);
cvcamSetProperty(CameraNumber[0], CVCAM_PROP_RENDER, CVCAMTRUE);
cvcamSetProperty(CameraNumber[0], CVCAM_PROP_WINDOW, &CaptureWindow1);
cvSetMouseCallback("cvcam1 Window",onMouse,0);

cvNamedWindow("cvcam2 Window",1);
CaptureWindow2=(HWND)cvGetWindowHandle("cvcam2 Window");
cvcamSetProperty(CameraNumber[1], CVCAM_PROP_ENABLE, CVCAMTRUE);
cvcamSetProperty(CameraNumber[1], CVCAM_PROP_RENDER, CVCAMTRUE);
cvcamSetProperty(CameraNumber[1], CVCAM_PROP_WINDOW, &CaptureWindow2);

//让两个摄像头同步 cvcamSetProperty(CameraNumber[0], CVCAM_STEREO_CALLBACK,(void *)&StereoCallback);

//启动程序 cvcamInit();
cvcamStart();
cvWaitKey(0);

cvcamStop();
cvcamExit();
free(CameraNumber);
cvDestroyWindow("cvcam1 Window");
cvDestroyWindow("cvcam2 Window");
}

void StereoCallback(IplImage* frame1,IplImage *frame2)
{
/* //把图像转换成灰度图并保存到image中
cvCvtColor(frame1,image1,CV_RGB2GRAY);
cvCvtColor(frame2,image2,CV_RGB2GRAY);
*/

//拷贝图像到全局变量image中 该函数这样用存在问题 cvCopy(frame1,image1);
cvCopy(frame2,image2);
// image1=cvCloneImage(frame1);
// image2=cvCloneImage(frame2);
//对截取的图像翻转 cvFlip(image1,image1,0);
cvFlip(image2,image2,0);
}

void onMouse(int Event,int x,int y,int flags,void *param)
{
static int num=0;
if(Event==CV_EVENT_LBUTTONDOWN)
{
if(num==4)num=0;//只是固定定义了保存4张图片,为了不让程序非法而设置的复原 cvcamPause();
//图像保存 cvSaveImage(strleft[num],image1);
cvSaveImage(strright[num],image2);
// cvSaveImage("left.bmp",image1);
// cvSaveImage("right.bmp",image2);
}
if(Event==CV_EVENT_RBUTTONDOWN)
{
cvcamResume();
num++;
}
}

在论坛上找了很久,最终找到了解决办法,即利用于仕琪老师提供的DirectShow视频采集方案(http://www.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。

利用该方案提供的例程,结合上一篇笔记中单窗口显示多个视频子图像的程序,就实现了读取两个摄像头的数据、并进行实时边缘检测的功能,主函数代码如下:

//////////////////////////////////////////////////////////////////////// Multiple Cameras Capture using DirectShow
// Author: Yuhua Zou
// Thanks to:
// Shiqi Yu ([email protected])
// [email protected] China
// [email protected] China (for his contribution to function CameraName, and frame width/height setting)
// Last modification: October 8, 2009//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////// 使用说明:
// 在 VC6 开发环境下的使用说明:
// 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
// 在 VS2005/2008 开发环境下的使用说明:
// 1. 将CameraDS.h CameraDS.cpp复制到你的项目中
// 2. 将DirectShow复制到你的opencv根目录下,菜单 工具->选项->项目和解决方案->vc++目录,把..(你的opencv安装目录)/DirectShow/Include添加到
// “引用文件”中$(VCInstallDir)PlatformSDK/include和$(FrameworkSDKDir)include下面任意位置
// 3. 菜单 工具->选项->项目和解决方案->vc++目录,把..(你的opencv安装目录)/DirectShow/Lib添加到“库文件”下面。也可参考使用说明3。//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "camerads.h"
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
#include <stdio.h>
#include <stdarg.h>
#include <time.h>

// 单窗口显示多幅图像的函数void cvShowMultiImages(char* title, int nArgs, ...)
{
// 略,详见学习笔记(5)}

int main( int argc, char** argv )
{
int cam_count;

//仅仅获取摄像头数目 cam_count = CCameraDS::CameraCount();
printf("There are %d cameras./n", cam_count);

//获取所有摄像头的名称 for(int i=0; i < cam_count; i++)
{
char camera_name[1024];
int retval = CCameraDS::CameraName(i, camera_name, sizeof(camera_name) );

if(retval >0)
printf("Camera #%d‘s Name is ‘%s‘./n", i, camera_name);
else
printf("Can not get Camera #%d‘s name./n", i);
}

if(cam_count==0)
return -1;

// 创建2个摄像头类 CCameraDS camera1;
CCameraDS camera2;

//打开第一个摄像头
//if(! camera.OpenCamera(0, true)) //弹出属性选择窗口 if(! camera1.OpenCamera(0, false, 320,240)) //不弹出属性选择窗口,用代码制定图像宽和高 {
fprintf(stderr, "Can not open camera./n");
return -1;
}
//打开第二个摄像头 camera2.OpenCamera(1, false, 320,240);

cvNamedWindow("Multiple Cameras");

// 初始化在子图像中显示字符的字体格式 CvFont tFont;
cvInitFont(&tFont, CV_FONT_HERSHEY_COMPLEX, 0.5f,0.7f,0,1,8);

char cam1str[] = "Camera #1";
char cam2str[] = "Camera #2";

// 为读取系统时间信息分配内存 char timestr[25];
memset(timestr, 0, 25 * sizeof(char));

while(1)
{
//获取一帧 IplImage *pFrame1 = camera1.QueryFrame();
IplImage *pFrame2 = camera2.QueryFrame();

// 获取当前帧的灰度图 IplImage* frame_gray_1 = cvCreateImage(cvGetSize(pFrame1),pFrame1->depth,1);
IplImage* frame_gray_2 = cvCreateImage(cvGetSize(pFrame2),pFrame2->depth,1);
cvCvtColor(pFrame1,frame_gray_1,CV_RGB2GRAY);
cvCvtColor(pFrame2,frame_gray_2,CV_RGB2GRAY);

// 对灰度图像进行Canny边缘检测
// 然后将图像通道数改为三通道 IplImage* frame_canny_1 = cvCreateImage(cvGetSize(pFrame1),pFrame1->depth,1);
IplImage* frame_canny_2 = cvCreateImage(cvGetSize(pFrame2),pFrame2->depth,1);
IplImage* frame1 = cvCreateImage(cvGetSize(pFrame1),pFrame1->depth,pFrame1->nChannels);
IplImage* frame2 = cvCreateImage(cvGetSize(pFrame2),pFrame2->depth,pFrame2->nChannels);
cvCanny(frame_gray_1,frame_canny_1,20,75,3);
cvCanny(frame_gray_2,frame_canny_2,20,75,3);
cvCvtColor(frame_canny_1,frame1,CV_GRAY2BGR);
cvCvtColor(frame_canny_2,frame2,CV_GRAY2BGR);

// 获取系统时间信息 time_t rawtime;
struct tm* timeinfo;

rawtime = time( NULL );
timeinfo = localtime( &rawtime );
char* p = asctime( timeinfo );

// 字符串 p 的第25个字符是换行符 ‘/n‘
// 但在子图像中将乱码显示
// 故仅读取 p 的前 24 个字符 for (int i = 0; i < 24; i++)
{
timestr[i] = *p;
p++;
}
p = NULL;

// 在每个子图像上显示摄像头序号以及系统时间信息 cvPutText( pFrame1, cam1str, cvPoint(95,15), &tFont, CV_RGB(255,0,0) );
cvPutText( pFrame2, cam2str, cvPoint(95,15), &tFont, CV_RGB(255,0,0) );
cvPutText( frame1, cam1str, cvPoint(95,15), &tFont, CV_RGB(255,0,0) );
cvPutText( frame2, cam2str, cvPoint(95,15), &tFont, CV_RGB(255,0,0) );

cvPutText( pFrame1, timestr, cvPoint(5,225), &tFont, CV_RGB(255,0,0) );
cvPutText( pFrame2, timestr, cvPoint(5,225), &tFont, CV_RGB(255,0,0) );
cvPutText( frame1, timestr, cvPoint(5,225), &tFont, CV_RGB(255,0,0) );
cvPutText( frame2, timestr, cvPoint(5,225), &tFont, CV_RGB(255,0,0) );

// 显示实时的摄像头视频 cvShowMultiImages( "Multiple Cameras", 4, pFrame1, pFrame2, frame1, frame2 );

//cvWaitKey(33); int key = cvWaitKey(33);
if( key == 27 ) break;

cvReleaseImage(&frame1);
cvReleaseImage(&frame2);
cvReleaseImage(&frame_gray_1);
cvReleaseImage(&frame_gray_2);
cvReleaseImage(&frame_canny_1);
cvReleaseImage(&frame_canny_2);
}

camera1.CloseCamera(); //可不调用此函数,CCameraDS析构时会自动关闭摄像头 camera2.CloseCamera();

cvDestroyWindow("Multiple Cameras");

return 0;
}

在 Project -> Properties -> Configuration Properties -> Linker ->
Input 的 Additional Dependencies
中,需要添加以下库文件:
odbc32.lib 
odbccp32.lib 
cv200.lib 
cxcore200.lib 
highgui200.lib

在编译以上程序时,可能会出现以下几种错误(参见 http://topic.csdn.net/u/20081022/12/30fb745f-332b-42f7-bbee-02a760c48132.html):

1> ../../../winnt.h(222) : error C4430: missing type specifier - int
assumed. Note: C++ does not support 
2> ../../../winnt.h(222) : error
C2146: syntax error : missing ‘;‘ before identifier ‘PVOID64‘
3>
../../../winnt.h(5940) : error C2146: syntax error : missing ‘;‘ before
identifier ‘Buffer‘

对于第1类错误,可以用wd4430来解决,具体的在Project -> Properties -> Configuration
Properties -> Linker -> Command Line的 Additional Options 中添加
‘/wd4430’  即可。

对于第2类错误,一般可通过调整 DirectShow/Include 在 Tools -> Options -> Projects and
Solutions -> VC++ Directories -> Show Directories for –> Include Files
中的位置(把它下移到最下面),然后把 Project -> Properties -> Configuration Properties –>
C/C++ 中的 Additional Include Directories
里面的内容(../../../../include)删掉,重新编译,PVOID64的错误就会消失,原因如下:

POINTER_64 是一个宏,在64位编译下起作用,它包含在SDK目录下的BASETSD.H中(Microsoft Visual Studio
8/VC/PlatformSDK/Include/basetsd.h(23):#define POINTER_64
__ptr64),但DXSDK自己也带了一个basetsd.h,里面没有定义POINTER_64,从而导致出错,只需要改变 include files
的优先级即可。

当然,也可以改写 winnt.h 中的代码,在下面这两行: 
typedef  void 
*PVOID;  
typedef  void  *POINTER_64 
PVOID64; 
之前增加一行: 
#define  POINTER_64 
__ptr64 
不过最好不要轻易改写 winnt.h 。

http://blog.csdn.net/wanglp094/article/details/7635904

多个摄像头同步工作【转】,布布扣,bubuko.com

时间: 2024-10-13 02:59:20

多个摄像头同步工作【转】的相关文章

摄像头不能工作的解决方法

突然发现用qq的时候无法找到摄像头,提示启动摄像头失败!请检查驱动程序是否正确,或者有别的应用程序在占用此设备. 我的系统是windows8.1,驱动是官方的肯定没错,之前也一直用的好好的,肯定是软件问题. 查看了设备管理器,摄像头驱动有一个小的感叹号.双击后属性里显示 Windows cannot start this hardware device because its configuration information(in the registry)is incomplete or d

主从同步工作过程?(binlog日志)

在从数据库服务器的/var/lib/mysql/master.info   记录连接主数据库服务器信息文件mail-relay-bin.XXXXXX   中继日志文件(记录SQL)mail-relay-bin.index    索引文件(记录已有的中继日志文件)relay-log.info     记录日志信息文件start  slave; Slave_IO_Running: Yes负责把master数据库服务器上binlog日志里SQL命令同步到本 机的中继日志文件. 出错: 连接不是主数据库

双目测距的基本原理(转http://blog.csdn.net/chenyusiyuan/article/details/5961769)

双目测距的基本原理 如上图所示,双目测距主要是利用了目标点在左右两幅视图上成像的横向坐标直接存在的差异(即视差)与目标点到成像平面的距离Z存在着反比例的关系:Z=fT/d.“@scyscyao :在OpenCV中,f的量纲是像素点,T的量纲由定标板棋盘格的实际尺寸和用户输入值确定,一般是以毫米为单位(当然为了精度提高也可以设置为0.1毫米量级),d=xl-xr的量纲也是像素点.因此分子分母约去,Z的量纲与T相同. ” 假设目标点在左视图中的坐标为(x,y),在左右视图上形成的视差为d,目标点在以

android camera(二):摄像头工作原理、s5PV310 摄像头接口(CAMIF)

一.摄像头工作原理 上一篇我们讲了摄像头模组的组成,工作原理,做为一种了解.下面我们析摄像头从寄存器角度是怎么工作的.如何阅读摄像头规格书(针对驱动调节时用到关键参数,以GT2005为例). 规格书,也就是一个器件所有的说明,精确到器件每一个细节,软件关心的寄存器.硬件关心的电气特性.封装等等.单单驱动方面,我们只看对我们有用的方面就可以了,没必要全部看完.主要这样资料全都是鸟语(En),全部看完一方面时间上会用的比较多,找到关键的地方就行了. 1.camera的总体示意图如下:控制部分为摄像头

详细的摄像头模组工作原理!!!

来源于:http://www.ccm99.com/thread-3492-1-1.html 作者:xubin341719(欢迎转载,请注明作者)." Y: @# [& h: n 一.摄像头工作原理 上一篇我们讲了摄像头模组的组成,工作原理,做为一种了解.下面我们析摄像头从寄存器角度是怎么工作的.如何阅读摄像头规格书(针对驱动调节时用到关键参数,以GT2005为例). 规格书,也就是一个器件所有的说明,精确到器件每一个细节,软件关心的寄存器.硬件关心的电气特性.封装等等.单单驱动方面,我们

转:摄像头camera 7660/7670/7225/9650以及程序流程(一)

转 http://www.cnblogs.com/crazybingo/archive/2012/05/11/2495680.html 调试了好多摄像头,OV7660.OV7670.OV7225这3款是30万的摄像头 还有一个130万的OV9650摄像头 移植在ARM平台上的数据,都调试成功了,7寸模拟屏显示,希望有用 调试的要点: AGC:图像自动增益控制,调节的东西有增益范围.增益上限下限大小等等,具体的要看应用场合来调试效果 一般会把增益开大一些,对暗的环境会有明显改善,看的清楚一些,不至

Java进击C#——语法之线程同步

上一章我们讲到关于C#线程方向的应用.但是笔者并没有讲到多线程中的另一个知识点--同步.多线程的应用开发都有可能发生脏数据.同步的功能或多或少都会用到.本章就要来讲一下关于线程同步的问题.根据笔者这几年来的.NET开发可以了解到的同步方式至少有四种以上.如.lock.volatile.Monitor等. lock方式 对lock的关键字作用跟JAVA的synchronized关键字类似.但有一定的差别.JAVA的synchronized关键字可能修饰在方法上面.可惜C#却不能修饰在方法上面.用法

Linux的rsync远程数据同步工具

Rsync(remote synchronize) 是一个远程数据同步工具,可以使用"Rsync算法"同步本地和远程主机之间的文件. rsync的好处是只同步两个文件不同的部分,相同的部分不在传递.类似于增量备份, 这使的在服务器传递备份文件或者同步文件,比起scp工具要省好多时间. OS:ubuntu server 10.04 server:192.168.64.128 client:192.168.64.145 server 1.ubuntu  server 10.04默认已安装r

MySQL主从同步(复制)的配置

1.主从复制的原理: *Master,记录数据更改操作 - 启用binlog记录模式 - 允许Slave读取binlog日志 *Slave运行2个同步线程 - Slave_IO:负责连接Master,复制其binlog日志文件到本机的relay-log文件 - Slave_SQL:执行本机relay-log文件里的SQL语句,重现Master的数据操作 2.基本构建思路: 1)初始化现有库:将主库导入从库,确保数据一致性 2)配置Master,主服务器:调整运行参数,授权一个同步用户 3)配置S