2012年7月21日 星期六

OpenCV 影像擷取 - 使用 DirectShow


在本篇文章中, 筆者將說明如何使用 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 如下:
Source1.cpp
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 行 擷 取影像了.














沒有留言:

張貼留言