http://blog.csdn.net/chenyusiyuan/article/details/4643313

因項目需要采集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 (shiqi.yu@gmail.com)
//        HardyAI@OpenCV China
//        flymanbox@OpenCV 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);elseprintf("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 。

OpenCV學習筆記(6)基於 VC+OpenCV+DirectShow 的多個攝像頭同步工作相关推荐

  1. android 直接v4l2驱动,基於V4L2驅動程序的USB攝像頭Android(JNI)的編寫(三)

    在上兩篇文章基於V4L2驅動程序的USB攝像頭Android(JNI)的編寫(一)和基於V4L2驅動程序的USB攝像頭Android(JNI)的編寫(二)中,我詳細介紹了如何配置V4L2的環境.設置捕 ...

  2. java中集合什么时候有索引,JavaSE中Collection集合框架學習筆記(1)——具有索引的List...

    前言:因為最近要重新找工作,Collection(集合)是面試中出現頻率非常高的基礎考察點,所以好好惡補了一番. 復習過程中深感之前的學習不系統,而且不能再像剛畢業那樣死背面試題,例如:String是 ...

  3. c#學習筆記--Visual Studio 使用

     一.新建項目 ① 在visual studio 的文件工具欄中,能夠創建新的項目,打開已有項目,打開文件夾和最近的項目 2010express版本可新建的項目包括: Windows Forms Ap ...

  4. python操作txt找到最便宜的素菜_Python線性模型學習筆記

    歡迎關注Python愛好者社區,我們是專註於商業智能BI,大數據,數據分析領域的垂直社區,學習,問答.求職一站式搞定! 天善學院618活動正在進行中!天善學院618大禮包,大數據.數據分析與數據挖掘. ...

  5. hf标签什么意思 html,HF HTMLCSS第2版學習筆記(陸續更新)

    第一章 認識HTML HTML的全稱是Hyper Text Makeup Language,簡稱HTML,譯名超文本標記語言 Web服務器(把文件放到Web服務器上,瀏覽器就可以通過互聯網得到你的We ...

  6. GeekBand c++學習筆記之四(conversion fuction vs non-explicit-one-arguement ctor)

    大家好,因為這一周所講述的課程點比較分散,所以我就記錄與分享一下我比較深刻與個人覺得比較有趣的部份,這個部分就conversion fuction和non-explicit-one-arguement ...

  7. easyuefi添加linux分区,linux學習筆記(一)——使用easyBCD或easyUEFI引導從硬盤安裝Ubuntu系統...

    Table of Contents windows系統安裝ubuntu會出現引導問題,windows系統不希望有其他系統和windows系統共存.所以我們得自己作一個引導.接下來主要介紹兩種引導,ea ...

  8. FileMaker中的腳本觸發器學習筆記

    脚本触发器 **脚本触发器是始终绑定到用户布局接口.对于数据表或者字段.只有在而已接口才能触发. **如果某一个布局或者对象上包含触发器,则其右下角会有触发器图标 **当触发一个事件时,有且仅有一个触 ...

  9. 《深入浅出Mysql》學習筆記--日志

    四种日志 错误日志 二进制日志 慢查询日志 查询日志 1. 错误日志(.err) 严重错误信息记录 more x.err 2. 二进制日志(binlog) 记录DDL,DML(select除外) 用于 ...

最新文章

  1. 上传一份个人学习struts2的历程笔记
  2. 老公,等儿子长大,我去天堂找你(推荐)
  3. iptables如何添加容许某个端口的访问
  4. oracle的工具cmd,数据库命令行工具DBCLI
  5. ubuntu python3 mysql_ubuntu14.04 python3.*连接mysql
  6. linux后台执行shell脚本
  7. python怎么看待_如何看待将Python作为少儿编程的基础语言?
  8. B站(IT速成之JAVA速成班 300分钟算法面试)跟做笔记
  9. java视频上传,播放预览,解决苹果手机视频无法预览的问题
  10. 整理12种电脑有趣屏保
  11. 虚拟机VirtualBox中Ubuntu和windows共享文件夹访问权限问题
  12. 第8章 HDFS HA高可用
  13. html颜色(背景,字体等)
  14. hdu1175连连看
  15. 计算机三维成像在哪些领域有运用,【图】三维动画类别及运用领域,三维动画分类介绍...
  16. ubuntu下查看电脑内存硬盘CPU显卡驱动等配置命令
  17. Git 使用的一些命令以及Git commit 注释格式
  18. webpack command not found 的意外的坑 - 原因是从node开始
  19. # nest笔记四:文件的上传与下载
  20. 计算机绘图论文范文大全集,计算机绘图实习报告范文

热门文章

  1. c语言中如何将字体弄大,CFree怎样调大字体
  2. 七年时间,微软智能云在中国走过的“大江大河”
  3. 趣图:程序员的鄙视链/图
  4. golang:%v,%+v,%#v的区别
  5. 微信小程序:微信零钱模拟器微信小程序源码下载查收充电器自动充钱
  6. Axure高级功能(变量、动态面板[轮播图]、中继器)
  7. 一款产品经理很好用的产品原型Axure配合软件--墨刀,将产品原型Axure,添加到墨刀,可以/预览/设计/编辑/共享/协同设计
  8. 机器学习(周志华) 第一章 引言
  9. Android实现资源动态加载的两种方式
  10. html图片动态案例,10个强大的纯CSS3动画案例分享