opencv學習筆記(2)視訊檔案的讀取與儲存
main 函式輸入引數 argc、argv 的意義(參見[1])
在學習筆記(1)中最後寫到:“在Debug完成後,應該把原始影象放到專案資料夾的 debug 資料夾中,使影象與exe程式在同一資料夾內,才能在執行程式時正確讀入並顯示影象。”其實是有誤的,影象不一定要與exe程式在同一資料夾內,在 cvLoadImage( argv[1] ) 中,可以把 argv[1] 改成專案資料夾裡的圖片的具體地址,若圖片與程式同一資料夾,直接寫圖片的檔名即可。
但是,這種在程式程式碼中寫檔名的方式很不方便,每次更改圖片檔案後都要重新編譯,實際上應該在跑程式時不改argv[1],而是在呼叫時輸入具體的檔名。要解決這個問題,就要理解好main 函式輸入引數 argc、argv 的意義。
int main(int argc, char** argv)
int main(int argc, char* argv[])
argc 是指命令列輸入引數的個數,argv 則儲存了所有的命令列引數。假如我的一個程式是video_test.exe,如果在命令列執行該程式(首先應該在命令列下用 cd 命令進入到 video_test.exe 檔案所在目錄),要處理的檔案有 v1.avi、v2.mpg,執行命令為:
video_test.exe v1.avi v2.mpg
那麼,argc的值是 3,argv[0]是"video_test.exe",argv[1]是"v1.avi",argv[2]是"v2.mpg"。
視訊檔案的讀取與基本處理
這裡主要是依照《Learning OpenCV》一書的例程修改實現的,其功能是讀取2個視訊檔案,分別在兩個視窗中播放,每個視窗都加入一個進度條,可以自行用滑鼠控制播放進度。程式碼如下:
建立一個Win32 Console專案
#include <iostream> #include <cv.h> //#include <cvaux.h> #include <cxcore.h> #include <highgui.h> // 使用標準名稱空間 using namespace std; // 初始化進度條的位置 int g_slider_position1 = 0; int g_slider_position2 = 0; CvCapture* g_capture1 = NULL; CvCapture* g_capture2 = NULL; // 定義回撥函式用於播放進度的控制 void onTrackbarSlide1( int pos1 ) { cvSetCaptureProperty( g_capture1, CV_CAP_PROP_POS_FRAMES, pos1 ); } void onTrackbarSlide2( int pos2 ) { cvSetCaptureProperty( g_capture2, CV_CAP_PROP_POS_FRAMES, pos2 ); } int main(int argc, char** argv ) { // 建立播放視窗 cvNamedWindow( "Video Test 1", CV_WINDOW_AUTOSIZE ); cvNamedWindow( "Video Test 2", CV_WINDOW_AUTOSIZE ); // 捕捉視訊檔案 g_capture1 = cvCreateFileCapture( "C:\\Users\\Administrator.PC-20131206COUD\\Desktop\\video\\1.mp4"); g_capture2 = cvCreateFileCapture( "C:\\Users\\Administrator.PC-20131206COUD\\Desktop\\video\\2.mp4" ); // 讀取、顯示視訊檔案的幀數 int frames1 = (int) cvGetCaptureProperty( g_capture1, CV_CAP_PROP_FRAME_COUNT ); cout << "frames1 = " << frames1 << endl; // 建立進度條 if( frames1 != 0 ) cvCreateTrackbar( "Position", "Video Test 1", &g_slider_position1, frames1, onTrackbarSlide1 ); int frames2 = (int) cvGetCaptureProperty( g_capture2, CV_CAP_PROP_FRAME_COUNT ); cout << "frames2 = " << frames2 << endl; if( frames2 != 0 ) cvCreateTrackbar( "Position", "Video Test 2", &g_slider_position2, frames2, onTrackbarSlide2 ); // 讀取視訊檔案資訊 double fps1 = (int) cvGetCaptureProperty( g_capture1, CV_CAP_PROP_FPS ); double fps2 = (int) cvGetCaptureProperty( g_capture2, CV_CAP_PROP_FPS ); CvSize size1 = cvSize( (int)cvGetCaptureProperty(g_capture1, CV_CAP_PROP_FRAME_WIDTH), (int)cvGetCaptureProperty(g_capture1, CV_CAP_PROP_FRAME_HEIGHT)); CvSize size2 = cvSize( (int)cvGetCaptureProperty(g_capture2, CV_CAP_PROP_FRAME_WIDTH), (int)cvGetCaptureProperty(g_capture2, CV_CAP_PROP_FRAME_HEIGHT)); // 建立 VideoWriter CvVideoWriter* wrVideo1 = cvCreateVideoWriter("3.mp4", CV_FOURCC('M','J','P','G'), fps1, size1); CvVideoWriter* wrVideo2 = cvCreateVideoWriter("4.mp4", CV_FOURCC('M','J','P','G'), fps2, size2); int frs = 0; // 開始播放並儲存視訊 IplImage* frame1; IplImage* frame2; while( frs < frames1 && frs < frames2 ) { // 獲取、顯示原始檔的幀畫面 frame1 = cvQueryFrame( g_capture1 ); if( !frame1 ) break; cvShowImage( "Video Test 1", frame1 ); frame2 = cvQueryFrame( g_capture2 ); if( !frame2 ) break; cvShowImage( "Video Test 2", frame2 ); // 儲存:將當前幀寫入到目標視訊檔案 cvWriteFrame( wrVideo1, frame1 ); cvWriteFrame( wrVideo2, frame2 ); // 若按下 ESC 鍵,則退出程式 char c = cvWaitKey(33); if( c==27 ) break; } // 釋放記憶體,關閉視窗 cvReleaseCapture( &g_capture1 ); cvReleaseCapture( &g_capture2 ); cvReleaseVideoWriter( &wrVideo1 ); cvReleaseVideoWriter( &wrVideo2 ); cvDestroyWindow( "Video Test 1" ); cvDestroyWindow( "Video Test 2" ); return 0; }