OpenCV的視頻讀取


現在找一個能拍攝視頻的設備真是太容易了。結果大家都用視頻來代替以前的序列圖像。視頻可能由兩種形式得到,一個是像網絡攝像頭那樣實時視頻流,或者由其他設備產生的壓縮編碼后的視頻文件。幸運的是,OpenCV可以使用相同的C++類、用同一種方式處理這些視頻信息。在接下來的教程里你將學習如何使用攝像頭或者視頻文件。

  • 如何打開和讀取視頻流
  • 兩種檢查相似度的方法:PSNR和SSIM

如何讀取一個視頻流(攝像頭或者視頻文件)?

        總的來說,視頻捕獲需要的所有函數都集成在 VideoCapture C++ 類里面。雖然它底層依賴另一個FFmpeg開源庫,但是它已經被集成在OpenCV里所以你不需要額外地關注它的具體實現方法。你只需要知道一個視頻由一系列圖像構成,我們用一個專業點兒的詞匯來稱呼這些構成視頻的圖像:“幀”(frame)。此外在視頻文件里還有個參數叫做“幀率”(frame rate)的,用來表示兩幀之間的間隔時間,幀率的單位是(幀/秒)。這個參數只和視頻的播放速度有關,對於單獨的一幀圖像來說沒有任何用途。

       你需要先定義一個 VideoCapture 類的對象來打開和讀取視頻流。具體可以通過 constructor 或者通過 open 函數來完成。如果使用整型數當參數的話,就可以將這個對象綁定到一個攝像機,將系統指派的ID號當作參數傳入即可。例如你可以傳入0來打開第一個攝像機,傳入1打開第二個攝像機,以此類推。如果使用字符串當參數,就會打開一個由這個字符串(文件名)指定的視頻文件。

結構體  CvCapture

  CvCapture 是一個結構體,用來保存圖像捕獲所需要的信息。 opencv提供兩種方式從外部捕獲圖像:

一種是從攝像頭中,
一種是通過解碼視頻得到圖像。
     兩種方式都必須從第一幀開始一幀一幀的按順序獲取,因此每獲取一幀后都要保存相應的狀態和參數。
     比如從視頻文件中獲取,需要保存視頻文件的文件名,相應的解碼器類型,下一次如果要獲取將需要解碼哪一幀等。
 這些信息都保存在CvCapture結構中,每獲取一幀后,這些信息都將被更新,獲取下一幀需要將新信息傳給獲取的 api接口
cvCreateFileCapture(char*name)
通過輸入要讀取的avi文件的路徑,然后,該函數返回一個指向 CvCapture結構體的指針。
cvQueryFrame(capture)
輸入一個CvCapture 類型的指針,該函數主要功能是將視頻文件的下一幀加載到內存。與 cvLoadImage的不同之處是,該函數不重新分配內存空間。
C=cvWaitKey(33)
當前幀被顯示后,等待 33毫秒。如果用戶觸發了一個按鍵, c會被設置成這個按鍵的 ASCII碼,否則會被設置成 -1。
cvWaitKey(33) 在此處的另外一個作用是,控制幀率。
cvReleaseCapture(&capture)
釋放為 CvCapture結構體開辟的內存空間
關閉打開的 AVI文件相關的文件句柄
VideoCapture類
用於從視頻文件或攝像機捕獲視頻.該類提供了用於從攝像機捕獲視頻或者讀取視頻文件的C++ API。

注意:在C API中使用黑盒子結構CvCapture來代替VideoCapture。

構造函數
VideoCapture::VideoCapture()
VideoCapture::VideoCapture(const string& filename)//filename – 文件名
VideoCapture::VideoCapture(int device)//device – 捕獲視頻的編號. 如果只有一個設備,默認編號為0
open函數
打開視頻文件或捕獲設備進行視頻捕獲
bool VideoCapture::open(const string& filename)//filename – 文件名
bool VideoCapture::open(int device)//device – 捕獲視頻的編號. 如果只有一個設備,默認編號為0
isopened函數
如果視頻捕獲已經初始化,則返回true。
bool VideoCapture::isOpened()
release函數
關閉視頻文件或捕獲設備
void VideoCapture::release()
grap函數
從視頻文件或捕獲設備中捕獲下一幀
bool VideoCapture::grab()
retrieve函數
解碼並返回抓取的視頻幀
bool VideoCapture::retrieve(Mat& image, int channel=0)
read函數
抓取,解碼並返回下一個視頻幀
bool VideoCapture::read(Mat& image)
get函數
返回指定的VideoCapture屬性
double VideoCapture::get(int propId)//propId - 屬性標識符
CV_CAP_PROP_POS_MSEC - 視頻文件的當前位置(以毫秒為單位)或視頻捕獲時間戳。
CV_CAP_PROP_POS_FRAMES - 下一個要解碼/捕獲的幀的基於0的索引。
CV_CAP_PROP_POS_AVI_RATIO - 視頻文件的相對位置:0 - 電影的開始,1 - 電影的結束。
CV_CAP_PROP_FRAME_WIDTH - 視頻流中幀的寬度。
CV_CAP_PROP_FRAME_HEIGHT - 視頻流中幀的高度。
CV_CAP_PROP_FPS - 幀速率。
CV_CAP_PROP_FOURCC - 編解碼器的4個字符代碼。
CV_CAP_PROP_FRAME_COUNT - 視頻文件中的幀數。
CV_CAP_PROP_FORMAT -  retrieve()返回的Mat對象的格式。
CV_CAP_PROP_MODE - 指示當前捕獲模式的后端特定值。
CV_CAP_PROP_BRIGHTNESS - 圖像的亮度(僅適用於相機)。
CV_CAP_PROP_CONTRAST - 圖像的對比度(僅適用於相機)。
CV_CAP_PROP_SATURATION - 圖像的飽和度(僅適用於相機)。
CV_CAP_PROP_HUE - 圖像的色調(僅適用於攝像機)。
CV_CAP_PROP_GAIN - 圖像的增益(僅適用於攝像機)。
CV_CAP_PROP_EXPOSURE - 曝光(僅適用於相機)。
CV_CAP_PROP_CONVERT_RGB - 指示圖像是否應轉換為RGB的布爾標志。
CV_CAP_PROP_WHITE_BALANCE - 目前不支持
CV_CAP_PROP_RECTIFICATION - 立體相機的校正標志(注意:目前僅由DC1394 v 2.x后端支持)
set函數
設置VideoCapture中的屬性。
bool VideoCapture::set(int propertyId, double value)//propId - 屬性標識符,同get;value - 屬性的值。

  

簡單的讀寫視頻程序
#include<opencv2/opencv.hpp>
using namespace cv;


void main() {
    VideoCapture cap;
    cap.open("E:\\VS2015Opencv\\vs2015\\project\\video\\01.avi"); //打開視頻,以上兩句等價於VideoCapture cap("E://01.avi");

                           //cap.open("http://www.laganiere.name/bike.avi");//也可以直接從網頁中獲取圖片,前提是網頁有視頻,以及網速夠快
    if (!cap.isOpened())//如果視頻不能正常打開則返回
        return ;
    Mat frame;
    while (1)
    {
        cap >> frame;//等價於cap.read(frame);
        if (frame.empty())//如果某幀為空則退出循環
            break;
        imshow("video", frame);
        waitKey(20);//每幀延時20毫秒
    }
    cap.release();//釋放資源
}

#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;

void main() {
    VideoCapture cap;
    cap.open("E:\\VS2015Opencv\\vs2015\\project\\video\\01.avi"); 

    if (!cap.isOpened())
        return;

    int width = cap.get(CV_CAP_PROP_FRAME_WIDTH);  //幀寬度
    int height = cap.get(CV_CAP_PROP_FRAME_HEIGHT); //幀高度
    int frameRate = cap.get(CV_CAP_PROP_FPS);  //幀率 x frames/s
    int totalFrames = cap.get(CV_CAP_PROP_FRAME_COUNT); //總幀數

    cout << "視頻寬度=" << width << endl;
    cout << "視頻高度=" << height << endl;
    cout << "視頻總幀數=" << totalFrames << endl;
    cout << "幀率=" << frameRate << endl;
    

    Mat frame;
    while (1)
    {
        cap >> frame;//等價於cap.read(frame);
        if (frame.empty())
            break;
        imshow("video", frame);
        if (waitKey(33) != 255)
            break;
    }
    cap.release();
}

 

將左邊的waitkey(33)改成右邊的if(waitKey(20)>0)break;

 程序會直接跳出,不放視頻

opencv學習之等待按鍵事件-waitKey函數

waitkey(20) 如果不按鍵的時候是返回 oxff,這個無符號就是255,有符號就是-1

windows vs 的環境默認了這個為非符號數 即255,而opencv的新手書中,往往作者環境會認為是-1

解決方案:把原始代碼中循環讀取幀的

if (waitKey(33)>=0)break;

改為

if (waitKey(33) != 255)break;

或者把waitkey的返回值用有符號數去讀取。

 

參考:opencv學習之路(2)、讀取視頻,讀取攝像頭


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM