2012年7月14日 星期六

OpenCV 影像擷取


本文介紹如何使用 OpenCV 進行影像擷取,  在前一篇文章中 Hello_OpenCV 從檔案將圖檔讀入並且顯示, 現在, 我們進一步擴充 Hello_OpenCV, 把原先的從檔案讀取圖檔改成從 WebCAM 擷取影像.
OpenCV 提供的影像擷取函式有兩個, 分別是
                               CvCapture* cvCaptureFromCAM(int index);
以及
                               IplImage* cvQueryFrame( CvCapture* capture );




cvCaptureFromCAM 分配並初始化 CvCapture 型別的 structure 以便從 camera 讀取 video stream.
index 代表 camera 的編號, OpenCV 2.2 目前可使用的 index 值是 0 以及 1.
cvQueryFrame 擷取影像並返回影像資料. 以下是簡單的程式代碼.
Hello_OpenCV.cpp Hello_OpenCV.cpp
01 #include <highgui.h>
02 #include <cv.h>
03 
04 #include <stdio.h>
05 
06 
07 void 
08 main()
09 {
10  IplImage* capimg;
11  CvCapture *capture;
12 
13  //img = cvLoadImage( img_file_name, 1 );
14  capture = cvCaptureFromCAM(0);
15  if( ! capture )
16  {
17   fprintf( stderr, "unable to create camera 0 \n" );
18   exit( 1 );
19  }
20 
21  cvNamedWindow( "camera0", 1 );
22  capimg=cvQueryFrame(capture);
23  cvShowImage(  "camera0", capimg );
24  cvWaitKey( 0 );
25  cvDestroyWindow( "camera0" );
26  cvReleaseCapture(&capture);
27 }
留意代碼中, 將第 13 行 的 cvLoadImage 替換成 第 14行的 cvCaptureFromCAM 並且在第 22 行
使用 cvQueryFrame , 從 WebCAM 抓取一張影像 顯示在第 21 行產生的 window 上.
這樣的程式碼產生的效果很像照相機, capture 一張影像後, 程式就準備結束了.
將程式略作修改如下.
Hello_OpenCV.cpp
01 #include <highgui.h>
02 #include <cv.h>
03 
04 #include <stdio.h>
05 
06 
07 void 
08 main()
09 {
10  IplImage* capimg;
11  CvCapture *capture;
12 
13  //img = cvLoadImage( img_file_name, 1 );
14  capture = cvCaptureFromCAM(0);
15  if( ! capture )
16  {
17   fprintf( stderr, "unable to create camera 0 \n" );
18   exit( 1 );
19  }
20 
21  cvNamedWindow( "camera0", 1 );
22 
23  while(  cvWaitKey( 5 ) != 27 )
24  {
25    capimg=cvQueryFrame(capture);
26    cvShowImage(  "camera0", capimg );
27  }
28  
29  cvDestroyWindow( "camera0" );
30  cvReleaseCapture(&capture);
31 }
如此就可以連續從 WebCAM 抓取影像並更新到 window 上了. 要結束程式, 就按下 Esc 鍵.
另外, 我們也可以增加 screenshot 的功能.
Hello_OpenCV.cpp
01 #include <highgui.h>
02 #include <cv.h>
03 
04 #include <stdio.h>
05 
06 
07 void 
08 main()
09 {
10  IplImage*  capimg = NULL;
11  CvCapture* capture= NULL;
12  int loop     = 1;
13  int file_idx = 0;
14  int key;
15 
16  char filename[256];
17  char fileidx[10];
18 
19  //img = cvLoadImage( img_file_name, 1 );
20  capture = cvCaptureFromCAM(0);
21  if( ! capture )
22  {
23   fprintf( stderr, "unable to create camera 0 \n" );
24   exit( 1 );
25  }
26 
27  cvNamedWindow( "camera0", 1 );
28 
29  while(loop)
30  {
31    capimg=cvQueryFrame(capture);
32    cvShowImage(  "camera0", capimg );
33 
34    key = cvWaitKey( 5 );
35    if( key == 27 )
36    {
37            loop = 0;
38    }
39    else if(key =='s' || key=='S' )
40    {
41      sprintf( fileidx, "%03d", file_idx++ );
42      strcpy( filename, "SAVE_IMG" );
43      strcat( filename, fileidx );
44      strcat( filename, ".bmp" );
45 
46      cvSaveImage( filename, capimg );
47      printf("Image file %s saved.\n", filename);
48    }
49  }
50  
51  cvDestroyWindow( "camera0" );
52  cvReleaseCapture(&capture);
53 }
以上的基本程式代碼可以將 window 中的影像處存成檔名為 SAVE_IMGxxx.bmp 的 bmp 檔.


結語
OpenCV 擷取影像的原生函式提供良好的方便性, 讓我們可以把注意力集中在影像處理或是計算機視覺的演算法上, 但若要以產品的標準來看, OpenCV 所提供的影像擷取原生函式在效能上有所不足, 另外在 2.2 版的 OpenCV也無法正常的擷取多支Camera. 當我們要開發 stereo相關的應用或是演算法時, 會遇到這個問題(2.3以後的版本可正常擷取)在往後的文章中, 筆者將介紹使用其他的 函式庫 來進行  影像串流的擷取.







9 則留言: