1.為什么使用DirectShow
筆者使用的是兩個USB攝像頭,單攝像頭視頻采集使用OpenCV的VideoCapture類沒有問題,但是雙攝像頭就有問題,一個正常,另外一個采集不到信息,顯示一片灰色。網上有種解決方法是逆序打開攝像頭,結果兩個窗口是可以采集到視頻信息,但是竟然是同一個攝像頭的視頻信息,無奈的只能使用DirectShow采集多攝像頭視頻信息。
先看看什么是DirectShow:
DirectShow 是 DirectX 的組件之一, DirectX 軟件開發(fā)包是 Microsoft 提供的一套在 Windows平臺上開發(fā)高性能圖形、聲音、輸入、輸出和網絡游戲的編程接口。這其中,DirectShow提供了應用程序從適當的硬件中捕捉和預覽音、視頻的能力。數據源包括: VCR、 Camera、 TV Tuner、 Microphone 或其他的數據源。應用程序可以立刻顯示捕捉的數據(預覽),或是保存到一個文件中。
攝像頭采集信息常用的軟件AMCap就是基于DirectShow SDK編寫的。查閱一下官方文檔,感覺好難的樣子,難道要新學一門“快過時”的技術嗎?幸好于仕琪老師寫了一個CCameraDS類,可直接返回IplImage,使用方便。
2.在VS2010中配置DirectShow并采集雙目攝像頭視頻
下載DirectShow相關文件,我已經共享在百度云盤,點擊下載。解壓以后copy到D:\opencv里(放在這里為了管理方便)
在解決資源管理器中的項目名稱處右鍵\屬性\配置屬性\VC++目錄,引用目錄中添加DirectShow的include文件夾,我添加的是D:\opencv\DirectShow\Include
在引用目錄下面有一個庫目錄,添加DirectShow的Lib文件夾,我添加的是D:\opencv\DirectShow\Lib;
下載CCameraDS類相關文件,點擊下載。解壓以后把CameraDS.h,CameraDS.cpp復制到已經配置好OpenCV庫的工程中,并添加到工程中。在解決資源管理器中,頭文件和源文件分別右鍵\添加\現有項,把CCameraDS的頭文件和源文件添加進去
main函數寫入如下內容
#include "stdafx.h"
#include
#include
#include
#include
#include
#include
#include "CameraDS.h"
using namespace cv;
int main()
{
int cam_count;
//僅僅獲取攝像頭數目
cam_count = CCameraDS::CameraCount();
printf("There are %d cameras.\n", cam_count);
}
編譯,error,一個一個解決
fatal error C1083: 無法打開包括文件:”dxtrans.h”: No such file or directory
下載的DirectShow包里面沒有該頭文件,全盤搜索Windows也沒有,后來發(fā)現使用該頭文件的是qedit.h,估計這個文件有問題。直接在網上重新down了一個qedit.h(點擊下載),替代了DirectShow自帶的qedit.h,路徑如下D:\opencv\DirectShow\Include\qedit.h。其它解決方法參考這里,也有效果
fatal error C1010:在查找預編譯頭時遇到意外的文件結尾。是否忘記了向源中添加“#include “StdAfx.h””?
在CameraDS.cpp最上面一行添加#include "StdAfx.h"即可
運行,結果如下:
改寫main函數,顯示兩個攝像頭內容
int main()
{
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;
CCameraDS camera1, camera2;
//手動打開攝像頭
// if(! camera1.OpenCamera(0, true)) //彈出屬性選擇窗口
//
{
//
fprintf(stderr, "Can not open camera1.\n");
//
return -1;
//
}
// if(! camera2.OpenCamera(1, true)) //彈出屬性選擇窗口
// {
//
fprintf(stderr, "Can not open camera2.\n");
//
return -1;
// }
//自動打開攝像頭
if(! camera1.OpenCamera(0, false, 320, 240)) //不彈出屬性選擇窗口,用代碼制定圖像寬和高
{
fprintf(stderr, "Can not open camera1.\n");
return -1;
}
if(! camera2.OpenCamera(1, false, 320, 240))//不彈出屬性選擇窗口,用代碼制定圖像寬和高
{
fprintf(stderr, "Can not open camera2.\n");
return -1;
}
while(1)
{
//獲取一幀
IplImage *pFrame1 = camera1.QueryFrame();
IplImage *pFrame2 = camera2.QueryFrame();
//顯示
cvShowImage("camera1", pFrame1);
cvShowImage("camera2", pFrame2);
if (cvWaitKey(20) == 'q')
break;
}
camera1.CloseCamera(); //可不調用此函數,CCameraDS析構時會自動關閉攝像頭
cvDestroyWindow("camera1");
camera2.CloseCamera();
cvDestroyWindow("camera2");
return 0;
}
運行結果如下:
3.總結
想要順利的讀取出雙攝像頭的視頻,必須明確地知道自己的攝像頭輸出的壓縮格式。比如我的雙目是用一根USB讀取兩個攝像頭的數據,雙目同時工作只支持yuy2的320*240分辨率,或者mjpg的1280*720和640*360分辨率
CCameraDS默認是yuy2格式,如果出現運行時錯誤八成是格式不匹配,可以下載AMCap軟件自己嘗試自己攝像頭支持的壓縮格式和分辨率
如果想要手動設置輸出格式和分辨率,將手動打開攝像頭的代碼注釋取消,再注釋自動打開攝像頭的代碼
如果自動打開攝像頭想要設置為mjpg格式,在OpenCamera函數中設置分辨率的語句后加上pmt->subtype = MEDIASUBTYPE_MJPG;
CCameraDSAPI查詢,
評論
查看更多