在本篇文章中, 筆者將說明如何使用 DirectShow 擷取影像. 當初使用 DirectShow 是因為
需要從事 Stereo vision相關的研究, 要從多個 camera 擷取影像, 且使用 OpenCV 2.2版, 但是這一版的 OpenCV 原生函式無法正確的擷取多個 camera 的影像. 因此才改用 DirectShow.
首先請下載 DirectShow 的影像擷取實作.
CameraDS.zip
解開 CameraDS.zip, 將 DirectShow 資料夾放至 \Project\Hello_OpenCV
CameraDS.cpp, CameraDS.h, stdafx.cpp, stdafx.h, targetver.h 放至 \Projects\Hello_OpenCV\Hello_OpenCV, 其中, CameraDS.cpp 要加入到 project 中.
如下圖所示;
修改 標頭檔路徑如下:
現在, 我們就可以開始使用 DirectShow撰寫影像擷取的程式了, 不用擔心對DirectShow 不熟, 因為 CameraDS.h, CameraDS.cpp 以及 DirectShow 資料夾中的程式碼, 已經幫我們把需要的功能包裝成 class, 只要直接使用就可以了, 十分方便.
將程式碼修改成使用 DirectShow 如下:
01 #include "StdAfx.h" 02 #include "CameraDS.h" 03 #include <cv.h> 04 #include <highgui.h> 05 06 07 #include <stdio.h> 08 09 #define CAP_WIDTH 320 // 640 // 176 10 #define CAP_HEIGHT 240 // 480 // 144 11 12 int 13 main() 14 { 15 IplImage* capimg; 16 CvCapture *capture; 17 int loop = 1; 18 int file_idx = 0; 19 int key; 20 int DeviceCamCount; 21 22 char filename[256]; 23 char fileidx[10]; 24 25 int CamCount = 0; 26 int CamIndex[10]; 27 CCameraDS *pCamDS = NULL; 28 29 pCamDS = new CCameraDS(); 30 DeviceCamCount = pCamDS->CameraCount(); 31 if( DeviceCamCount == 0 ) 32 { 33 printf( "No Camera detected....\n" ); 34 return(-1); 35 } 36 37 for(int i = 0, j = 0; i < DeviceCamCount; i++) 38 { 39 char szCamName[1024]; 40 41 int retval = pCamDS->CameraName(i, szCamName, sizeof(szCamName)); 42 43 if(retval >0) 44 { 45 printf("Camera #%d's Name is '%s'.\n", i, szCamName); 46 if( !strcmp( szCamName, "USB µø°T¸Ë¸m" ) ) 47 { 48 CamIndex[ j++ ] = i; 49 CamCount++; 50 } 51 } 52 else 53 { 54 printf("Can not get Camera #%d's name.\n", i); 55 } 56 } 57 58 if(pCamDS->OpenCamera(CamIndex[0], false, CAP_WIDTH, CAP_HEIGHT)==false) 59 { 60 printf("Camera do not support w=%d:h=%d\n", CAP_WIDTH, CAP_HEIGHT ); 61 return (-1); 62 } 63 64 cvNamedWindow( "camera0", 1 ); 65 66 while( loop ) 67 { 68 capimg=pCamDS->QueryFrame(); 69 cvShowImage( "camera0", capimg ); 70 71 key = cvWaitKey( 5 ); 72 if( key == 27 ) 73 { 74 loop = 0; 75 } 76 else if(key =='s' || key=='S' ) 77 { 78 sprintf( fileidx, "%03d", file_idx++ ); 79 strcpy( filename, "SAVE_IMG" ); 80 strcat( filename, fileidx ); 81 strcat( filename, ".bmp" ); 82 83 cvSaveImage( filename, capimg ); 84 printf("Image file %s saved.\n", filename); 85 } 86 } 87 88 if( pCamDS ) 89 { 90 pCamDS->CloseCamera(); 91 delete pCamDS; 92 } 93 cvDestroyWindow( "camera0" ); 94 return(0); 95 }
程式碼 27~35 行, CCameraDS class 的 pCam 物件使用 CameraCount function 查詢系統上的裝置數目, 此時 不只一般的 USB webcam, 電視卡也會被計數為裝置之一. 在 37~56行會 log 所有的裝置名稱並且從所有裝置中過濾出我們需要的 USB webcam.
例如在筆者的 PC 上, 列出的裝置如下圖. 只有第二個 "USB 視訊裝置" 才是我們需要的.
在 46~50 行過濾出我們需要的 USB webcam 之後, 就可以在 58行開啟 camera 並且在 68 行 擷 取影像了.
沒有留言:
張貼留言