【OpenCV3】視訊讀寫cv::VideoCapture和cv::VideoWriter

bbzz2發表於2017-07-17

OpenCV3和OpenCV2類似,視訊的讀、寫操作,分別通過cv::VideoCapture和cv::VideoWriter兩個類來實現。


1、視訊的讀取操作cv::VideoCapture

cv::VideoCapture既支援視訊檔案的讀取,也支援從攝像機中視訊的讀取。cv::VideoCapture物件的建立方式有以下三種:

  1. cv::VideoCapture capture(  
  2. const string& filename, // 輸入檔名  
  3. );  
  4. cv::VideoCapture capture(  
  5. int device // 視訊捕捉裝置 id  
  6. );  
  7. cv::VideoCapture capture();  


第一種方式是從檔案(.MPG或.AVI格式)中讀取視訊,物件建立以後,OpenCV將會開啟檔案並做好準備讀取它,如果開啟成功,我們將可以開始讀取視訊的幀,並且cv::VideoCapture的成員函式isOpened()將會返回true(建議在開啟視訊或攝像頭時都使用該成員函式判斷是否開啟成功)。

第二種方式是從攝像機中讀取視訊,這種情況下,我們會給出一個識別符號,用於表示我們想要訪問的攝像機,及其與作業系統的握手方式。對於攝像機而言,這個標誌符就是一個標誌數字——如果只有1個攝像機,那麼就是0,如果系統中有多個攝像機,那麼只要將其向上增加即可。識別符號另外一部分是攝像機域(camera domain),用於表示攝像機的型別,這個域值可以是下面任一預定義常量。


以這種方式建立視訊捕獲物件時,我們所傳遞的識別符號是域索引和攝像機索引的和。例如:

  1. cv::VideoCapture capture(cv::CAP_IEEE1394 + 1);  

這個例子中cv::VideoCapture將嘗試開啟第2個(編號從0開始)1394攝像機。多數情況下,由於我們只有一個攝像機,因此沒必要指定攝像機的域,此時使用cv::CAP_ANY是一種高效的方式(也即是0,所以不用特意指定)。

第三種方式僅僅建立一個捕獲物件,而不提供任何關於開啟的資訊。建立以後通過成員函式open()來設定開啟的資訊。open()操作也有以上兩種方式。

  1. cv::VideoCapture cap;  
  2. cap.open( "my_video.avi" );  

將視訊幀讀取到cv::Mat矩陣中,有兩種方式:一種是read()操作;另一種是 “>>”操作。

  1. cv::Mat frame;  
  2. cap.read(frame); //讀取方式一  
  3. cap >> frame; //讀取方式二  

下面是讀取視訊並顯示的示例程式碼:

  1. #include <opencv2/opencv.hpp>  
  2. #include <iostream>  
  3.   
  4. void video_capture_test()  
  5. {  
  6.     cv::VideoCapture capture("test.mp4");  
  7.   
  8.     if (!capture.isOpened())  
  9.     {  
  10.         std::cout << "Read video Failed !" << std::endl;  
  11.         return;  
  12.     }  
  13.   
  14.     cv::Mat frame;  
  15.     cv::namedWindow("video test");  
  16.   
  17.     int frame_num = capture.get(cv::CAP_PROP_FRAME_COUNT);  
  18.     std::cout << "total frame number is: " << frame_num << std::endl;  
  19.   
  20.     for (int i = 0; i < frame_num - 1; ++i)  
  21.     {  
  22.         capture >> frame;  
  23.         //capture.read(frame); 第二種方式  
  24.         imshow("video test", frame);  
  25.         if (cv::waitKey(30) == 'q')  
  26.         {  
  27.             break;  
  28.         }  
  29.     }  
  30.   
  31.     cv::destroyWindow("video test");  
  32.     capture.release();  
  33.     return;  
  34. }  

上面的程式碼,我們使用了cv::VideoCapture的成員函式get()並設定標識cv::CAP_PROP_FRAME_COUNT獲取了讀取視訊的幀總數。同樣,我們可以指定其他標識,來獲取讀取視訊或攝像頭的其他屬性。另外,我們也可以使用成員函式set(),設定相應屬性的值。cv::VideoCapture中提供的屬性標識如下圖所示。



2、視訊的寫操作cv::VideoWriter

cv::VideoWriter物件的建立有兩種方式,第一種是使用建構函式的形式,第二種使用open()的方式,具體如下:

  1. cv::VideoWriter out(  
  2.     const string& filename, // 輸入檔名  
  3.     int fourcc, // 編碼形式,使用 CV_FOURCC()巨集  
  4.     double fps, // 輸出視訊幀率  
  5.     cv::Size frame_size, // 單幀圖片的大小  
  6.     bool is_color = true // 如果是false,可傳入灰度影像   
  7. );  
  8.   
  9. cv::VideoWriter out;  
  10. out.open(  
  11.     "my_video.mpg"//輸出檔名  
  12.     CV_FOURCC('D','I','V','X'), // MPEG-4 編碼  
  13.     30.0, // 幀率 (FPS)  
  14.     cv::Size( 640, 480 ), // 單幀圖片解析度為 640x480  
  15.     true // 只輸入彩色圖  
  16. );  

同樣,向建立後的cv::VideoWriter物件寫入影像也有兩種方式,即write()操作和“<<”操作:

  1. cv::VideoWriter::write(  
  2.     const Mat& image // 寫入影像作為下一幀  
  3. );  
  4.   
  5. my_video_writer << my_frame;  

opencv3.0 播放視訊和開啟攝像頭程式碼



    //cv::VideoCapture capture(0); // 開啟攝像頭
    cv::VideoCapture capture(fName);// 開啟視訊fName 視訊路徑
    cv::Mat imageTemp;
    capture>>imageTemp;


    printf("Image size: [%d %d]\n", imageTemp.cols, imageTemp.rows);

    // 獲取視訊的總幀率數
    int allCount = (int)capture.get(CV_CAP_PROP_FRAME_COUNT);

    int countFram = 0;
    Timer mTimer;
    while(1)
    {
        capture>>imageTemp;
        cv::imshow("show", imageTemp);
        cv::waitKey(30);
        countFram ++;
        if(countFram == allCount - 2)
        {
            capture.release();
            break;
        }
    }

OpenCV讀取視訊:

  使用opencv讀取視訊主要用到這幾個函式:cvCreateFileCapture  cvQueryFrame (或cvGrabFrame cvRetrieveFrame)  cvReleaseCapture。

1:簡單介紹:

CvCapture是一個結構體,用來儲存影像捕獲所需要的資訊,opencv提供了兩種方式從外部捕獲影像

         一種是從攝像頭中,另一種是通過解碼視訊得到影像

         兩種方式都必須從第一幀開始一幀一幀的按順序獲取,因此每獲取一幀後都要儲存相應的狀態和引數。比如從視訊檔案中獲取,需要儲存視訊檔案的檔名,相應的解碼器型別,下一次如果要獲取將需要解碼哪一幀等。這些資訊都儲存在CvCapture結構體中,每獲取一幀後,這些資訊都將被更新,獲取下一幀需要將新資訊傳給獲取的api介面

讀取攝像頭          只需將cvCreateFileCapture改為cvCreateCameraCapture即可。該函式的輸入引數是一個ID號,只有存在多個攝像頭時才起作用。當ID=-1時,表示隨機選擇一個。

2 程式碼:

  1. #include <iostream>  
  2. #include "cxcore.h"  
  3. #include "cv.h"  
  4. #include "highgui.h"  
  5.   
  6. using namespace std;  
  7.   
  8. int main()  
  9. {  
  10.     cvNamedWindow("video",0);  
  11.     CvCapture *capture = cvCreateFileCapture("F:\\download\\itudou\\xx5.avi");  
  12.     IplImage *image;  
  13.     while(1){  
  14.         //image = cvQueryFrame(capture);    //這裡不進行記憶體的重新分配 這裡是兩種方法哦  
  15.         cvGrabFrame(capture);  
  16.         image = cvRetrieveFrame(capture);  
  17.         if(!image)break;  
  18.         cvShowImage("video",image);  
  19.         char c = cvWaitKey(33);   // == 視訊的幀率為30幀/s  
  20.         if(c == 27)break;  
  21.     }  
  22.     cvReleaseCapture(&capture);  
  23.     cvDestroyWindow("video");  
  24.     return 0;  
  25.   
  26.   
  27. }  

視訊播放控制

opencv進行視訊控制主要用的函式有cvCreateFileCapture  cvGetCaptureProperty  cvCreateTrackbar。這些可以檢視opencv中文api。連結在http://download.csdn.net/detail/lu597203933/6480693

1: 什麼是回撥函式

回撥函式就是一個通過函式指標呼叫的函式。如果你把函式的指標(地址)作為引數傳遞給另外一個函式,當這個指標被用為呼叫它所指向的函式時,我們就說這是回撥函式。回撥函式不是由該函式的實現方直接呼叫,而是在特定的事件或條件發生時由另外的一方呼叫的,用於對該事件或條件進行響應

2:程式碼:

  1. #include <iostream>  
  2. #include "cxcore.h"  
  3. #include "cv.h"  
  4. #include "highgui.h"  
  5. using namespace std;  
  6.   
  7. CvCapture *capture = NULL;  
  8. int frame_count = 0;  
  9. int g_capture;  
  10.   
  11. void track_change(int pos){  
  12.     cvSetCaptureProperty(capture, CV_CAP_PROP_POS_FRAMES, pos);  
  13.     frame_count = pos;  
  14. }  
  15.   
  16. int main()  
  17. {  
  18.     cvNamedWindow("show");  
  19.     capture = cvCreateFileCapture("F:\\download\\itudou\\xx5.avi");  
  20.     int frame_sum = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_COUNT);  
  21.     if(frame_sum != 0){  
  22.         cvCreateTrackbar("track_name""show", &g_capture, frame_sum, track_change);  
  23.     }  
  24.     IplImage *image = NULL;  
  25.     while(1){  
  26.         image = cvQueryFrame(capture);  
  27.         if(!image){  
  28.             break;  
  29.         }  
  30.         cvShowImage("show",image);  
  31.         char c = cvWaitKey(33);  
  32.         if(c == 27)   
  33.         {  
  34.             break;  
  35.         }  
  36.         cvCreateTrackbar("track_name""show", &frame_count, frame_sum, track_change);  
  37.         //cvSetTrackbarPos("track_name","show", frame_count);  //執行兩幀就結束了  為什麼呢?  
  38.         frame_count ++;  
  39.   
  40.       
  41.     }  
  42.     cvReleaseCapture(&capture);  
  43.     cvDestroyWindow("show");  
  44.     return 0;  
  45.       
  46. }  

其中程式碼的註釋處有個問題,當使用是cvSetTrackbarPos的時候,程式碼執行了兩幀就結束了,這個我還沒弄明白為什麼,可能是幀率的問題,如果有知道的可以告訴我哈哈

opencv寫視訊

opencv寫視訊主要用到的函式有CvCreateVideoWriter  cvWriteFrame  cvReleaseVideoWriter。

程式碼:

  1. #include <iostream>  
  2. #include "cv.h"  
  3. #include "highgui.h"  
  4. #include "cxcore.h"  
  5. #include <sstream>  
  6. #include <string>  
  7. using namespace std;  
  8. double fps = 20;  
  9. int width = 480;  
  10. int height = 360;  
  11. char name[500];  
  12. int main()  
  13. {  
  14.     CvVideoWriter *writer = cvCreateVideoWriter("E:\\study_opencv_video\\lesson6_1\\out.avi", CV_FOURCC('I''Y''U''V'), fps, cvSize(width, height), 1);  
  15.     IplImage *image = NULL;  
  16.     int i = 0;  
  17.     cvNamedWindow("show");  
  18.     string str ;  
  19.     stringstream ss;  
  20.     while(1){  
  21.         str = "E:\\study_opencv_video\\lesson6_1\\orig";  
  22.         ss << str;  
  23.         ss << i;  
  24.         ss << ".jpg";  
  25.         ss >> name;  
  26.         image = cvLoadImage(name);  
  27.         if(!image){  
  28.             cout << i <<endl;  
  29.             break;  
  30.         }  
  31.         cvShowImage("show",image);  
  32.         char c = cvWaitKey(33);  
  33.         if(c == 27){  
  34.             break;  
  35.         }  
  36.         cvWriteFrame(writer, image);  
  37.         i++;  
  38.         ss.clear();  
  39.         cvReleaseImage(&image);  
  40.     }  
  41.     cvReleaseVideoWriter(&writer);  
  42.     cvDestroyWindow("show");  
  43.     return 0;  
  44. }  

以上是我的簡單學習總結,如有問題可以和我交流哈

作者:小村長  出處:http://blog.csdn.net/lu597203933 歡迎轉載或分享,但請務必宣告文章出處。 (新浪微博:小村長zack, 歡迎交流!)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

相關文章