CV02-07:OpenCV視頻采集

??OpenCV的機器視覺包含靜態(tài)圖像處理(2D與3D)與動態(tài)視頻處理恰起,本主題主要梳理下C++的視頻采集處理淮逻。


OpenCV視頻處理結(jié)構(gòu)

結(jié)構(gòu)圖

OpenCV視頻在處理結(jié)構(gòu)

核心類說明

VideoCapture類

  • 負責抓取視頻刨沦,抓取源支持:照相機,視頻文件敏释,圖形序列等骂澄。

VideoWriter

  • 負責寫視頻數(shù)據(jù)到文件,包括壓縮等挣柬。

VideoCapture視頻抓取

構(gòu)造器

  • 一共三個構(gòu)造器
    1. 默認構(gòu)造器
    2. 視頻設備構(gòu)造器
    3. 視頻文件構(gòu)造器器
  1. 默認構(gòu)造器
    • 默認構(gòu)造器沒有初始化設備潮酒,需要調(diào)用open函數(shù)初始化設備。

    cv::VideoCapture::VideoCapture( )   

  1. 視頻設備構(gòu)造器
    
    cv::VideoCapture::VideoCapture( 
        int     index,                                                  // 視頻設備編號邪蛔,從0開始
        int     apiPreference = CAP_ANY                     // 視頻處理的底層API急黎。FFMPEG,IMAGES侧到,DSHOW
    )
        
  • FFMPEG:開源的視頻處理框架勃教;
  • IMAGES:圖片序列(比如:GIF);
  • DSHOW:微軟的DirectX中視頻模塊DSHOW匠抗;
  1. 視頻文件構(gòu)造器

    cv::VideoCapture::VideoCapture( 
        const String &       filename,                              // 視頻文件路徑故源。
        int                       apiPreference = CAP_ANY      // 視頻處理的底層API。
    )

設備初始化

  • 使用open函數(shù)實現(xiàn)設備初始化汞贸。
    • 與構(gòu)造器相同心软。
  1. 使用視頻文件初始化
    virtual bool open (const String &filename, int apiPreference=CAP_ANY)
  1. 使用視頻設備初始化
    virtual bool open (int index, int apiPreference=CAP_ANY)

判別設備是否初始化

  • isOpened函數(shù)
    virtual bool    isOpened () const

讀取數(shù)據(jù)

  • 讀取數(shù)據(jù)兩種方式
    1. 直接讀取
    2. 多設備情況下,需要先抓取緩沖著蛙,然后讀壬玖濉;

直接讀取數(shù)據(jù)

  • 使用read函數(shù)與操作符讀忍けぁ猎唁;
  1. read函數(shù)讀取
    virtual bool read (OutputArray image)
  • OutputArray image返回抓取的視頻圖像。
  1. >>操作符讀取
    virtual VideoCapture& cv::VideoCapture::operator >>(Mat &   image   )   

緩沖讀取

  • 緩沖讀取分成兩步:
    1. 使用grap函數(shù)抓取到緩沖顷蟆;
    2. 使用retrieve函數(shù)返回視頻圖像诫隅;
  1. grap函數(shù)
    • 抓取視頻圖像成功,返回true帐偎;否則返回false
    virtual bool    grab ()
  1. retrieve 函數(shù)
    • 返回抓取的圖像逐纬,比read多一個讀取標記;
    virtual bool retrieve (
        OutputArray image, 
        int flag=0)                 // 用來指定圖像的幀索引削樊,或者底層IP的讀取標記豁生;

屬性處理

  • 提供了set/get來設置與獲取設備與底層屬性
  1. set函數(shù)
     virtual bool   set (int propId, double value)
  1. get函數(shù)
    virtual double  get (int propId) const

釋放設備

  • 使用release函數(shù)釋放
    virtual void    release()

視頻抓取應用例子

  • 例子的思路:
    • 創(chuàng)建一個線程兔毒,不同抓取視頻圖像,然后用信號的方式發(fā)送給窗體顯示甸箱;

抓取圖像的線程

  1. 頭文件
    #ifndef VIDEO_THRWAD_H
    #define VIDEO_THRWAD_H
    #include <opencv2/opencv.hpp>
    #include <QThread>

    class VideoThread : public QThread{
        Q_OBJECT
    public:
        VideoThread();
        VideoThread(int deviceid);
        ~VideoThread();

    private:
        cv::VideoCapture  *device;
    protected:
        virtual void run();

    // 信號
    signals:
        void video(cv::Mat img);
    };
    #endif // !VIDEO_THRWAD_H

  1. 實現(xiàn)文件
    #include "videoth.h"
    #include<iostream>

    // 構(gòu)造器
    VideoThread::VideoThread():
        device(new cv::VideoCapture(0)){
    }
    VideoThread::VideoThread(int deviceid):
        device(new cv::VideoCapture(deviceid)){

    }
    // 析構(gòu)器
    VideoThread::~VideoThread(){
        device->release();
        delete device;
    }

    // 線程主方法
    void VideoThread::run(){
        while(true){
            // 抓取圖像育叁,發(fā)送信息
            cv::Mat img;
            device->read(img);
            emit video(img);
            QThread::usleep(100);

        }
    }

圖像處理類

  1. 頭文件
    #ifndef IMAGE_PROCESSING_H
    #define IMAGE_PROCESSING_H

    #include <opencv2/opencv.hpp>

    class ImageProcessing{
    public:
        ImageProcessing();
        ~ImageProcessing();
    public:
        void handle_filter2d(cv::InputArray img_src, cv::OutputArray img_out);
    };
    #endif // !IMAGE_PROCESSING_H
  1. 實現(xiàn)文件

    #include "imageprocessing.h"

    ImageProcessing::ImageProcessing(){

    }
    ImageProcessing::~ImageProcessing(){

    }
    void ImageProcessing::handle_filter2d(cv::InputArray img_src, cv::OutputArray img_dst){
        cv::Mat kernel = (cv::Mat_<int>(3,3) << 
            -1,-1,-1,
             0, 0, 0,
             1, 1, 1);

        cv::filter2D(
            img_src, 
            img_dst,
            -1,                 // 輸出圖像的深度
            kernel,             // 濾波核
            cv::Point2i(-1, -1),    // 錨點
            64.0,                  // 正向(加法運算)偏移值
            cv::BORDER_REFLECT_101
        );
    }

UI文件的設計

UI文件設計

信號傳遞的用戶類型處理

  1. 引入頭文件

    • #include<QMetaType>
  2. 申明需要注冊的類型

    • Q_DECLARE_METATYPE(cv::Mat);
  3. 注冊類型

    • qRegisterMetaType<cv::Mat>("Mat");
    • qRegisterMetaType<cv::Mat>("Mat&");
  4. 在主程序中注冊的完整代碼

    #include <QApplication>
    #include "dlgvideo.h"

    #include <iostream>
    #include<QMetaType>
    Q_DECLARE_METATYPE(cv::Mat);   

    int main(int argc, char* argv[]) {
        // 初始化QT應用
        QApplication app(argc, argv);
        qRegisterMetaType<cv::Mat>("Mat");
        qRegisterMetaType<cv::Mat>("Mat&");
        DlgVideo dlg;
        dlg.show();
        return app.exec();
    }

對話框類

  1. 頭文件
    #ifndef DLG_VIDEO_H
    #define DLG_VIDEO_H
    #include <opencv2/opencv.hpp>
    #include <QDialog>
    #include "ui_output.h"
    #include "videoth.h"
    #include "imageprocessing.h"

    class DlgVideo: public QDialog{
    Q_OBJECT
    public:
        DlgVideo(QWidget *parent = 0); 
        ~DlgVideo();
    private:
        Ui::dlg_video  *dlg;
        VideoThread *th;
        ImageProcessing  *proc;
    private slots:
        void record();
        void showImage(cv::Mat img);
    };
    #endif

  1. 實現(xiàn)文件
    #include "dlgvideo.h"
    #include <iostream>
    // 構(gòu)造器與析構(gòu)器
    DlgVideo::DlgVideo(QWidget *parent):
            QDialog(parent),
            dlg(new Ui::dlg_video()),
            th(new VideoThread()),
            proc(new ImageProcessing()){
            dlg->setupUi(this);  
            QObject::connect(th, SIGNAL(video(cv::Mat)), this, SLOT(showImage(cv::Mat)));
            th->start();
    }
    DlgVideo::~DlgVideo(){
            th->terminate();
            delete dlg;     // 釋放對話框
            delete th;      // 線程對象釋放
            delete proc;
    }

    // 線程信號發(fā)過來的圖像,并顯示
    void DlgVideo::showImage(cv::Mat img){
        if(img.empty()) return;   // 圖像非空才顯示
        cv::Mat img_src;
        proc->handle_filter2d(img, img_src);
        cv::Mat  m_out;
        // OpenCV到Qt的顏色格式轉(zhuǎn)換
        cv::cvtColor(img_src, m_out, cv::COLOR_BGR2RGBA); 
        // 轉(zhuǎn)換為Qt圖像
        QImage i_out(m_out.data, m_out.cols, m_out.rows, QImage::Format_RGBA8888);
        // 轉(zhuǎn)換為組件能處理的像素格式
        QPixmap p_out = QPixmap::fromImage(i_out);
        // 顯示圖像
        dlg->lbl_video->setPixmap(p_out);
        // 縮放圖像適應組件大小
        dlg->lbl_video->setScaledContents(true);
    }

    // 事件處理
    void DlgVideo::record(){

    }

Makefile

  • 這個文件使用了文件處理函數(shù)芍殖,來生成moc文件豪嗽;因為有多個moc文件需要生成,所以還采用了循環(huán)豌骏。
  • opencv的視頻處理需要的共享庫:opencv_videoio

INCLUDES    =-I/Users/yangqiang/Qt512/5.12.1/Src/qtbase/include \
             -I/Users/yangqiang/Qt512/5.12.1/Src/qtbase/include/QtCore \
             -I/Users/yangqiang/Qt512/5.12.1/Src/qtbase/include/GtGui \
             -I/Users/yangqiang/Qt512/5.12.1/Src/qtbase/include/QtWidgets \
             -I/Users/yangqiang/Qt512/5.12.1/Src/qtbase/include/QThread \
             -I/usr/local/include/opencv4/
LIBS        =-lopencv_core \
             -lopencv_highgui \
             -lopencv_imgcodecs \
             -lopencv_imgproc \
             -lopencv_videoio
FRAMEWORKS  =-F/Users/yangqiang/Qt512/5.12.1/clang_64/lib \
             -framework QtCore  \
             -framework QtGui  \
             -framework QtWidgets
LD_ARGS     =-Wl,-rpath,/Users/yangqiang/Qt512/5.12.1/clang_64/lib
UICTOOL     =/usr/local/Qt-5.12.1/bin/uic
MOCTOOL     =/usr/local/Qt-5.12.1/bin/moc
HEADER      =dlgvideo.h videoth.h
MOCS        =$(HEADER:%.h=moc_%.cpp)
SOURCES     =main.cpp dlgvideo.cpp videoth.cpp imageprocessing.cpp
UICS        =ui_output.ui
UICH        =$(UICS:%.ui=%.h)

main: $(SOURCES) $(UICH) $(MOCS)
    g++ -omain $(SOURCES) $(MOCS) -std=c++11 $(INCLUDES) $(LIBS)  $(FRAMEWORKS) $(LD_ARGS)

$(MOCS): $(HEADER)
    $(foreach VAR, $(HEADER), $(MOCTOOL) -o $(VAR:%.h=moc_%.cpp) $(VAR);)

$(UICH): $(UICS)
    $(UICTOOL) -o $(UICS:%.ui=%.h)  $(UICS)

clean:
    rm -f main $(MOCS)  $(UICS:%.ui=%.h)  moc_*.cpp


視頻采集效果:添加了Prewitt查分計算

VideoWriter視頻存儲

  • 視頻存儲的API與VideoCapture類似龟梦,主要包含:
    1. 構(gòu)造器
    2. 初始化
      • virtual bool open (const String &filename, int fourcc, double fps, Size frameSize, bool isColor=true)
    3. 是否初始化
      • virtual bool isOpened () const
    4. 寫入
      • virtual void write (InputArray image)
      • virtual VideoWriter & operator<< (const Mat &image)
    5. 釋放;
      • virtual void release ()
    6. 屬性設置
      • virtual double get (int propId) const
      • virtual bool set (int propId, double value)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末窃躲,一起剝皮案震驚了整個濱河市变秦,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌框舔,老刑警劉巖蹦玫,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異刘绣,居然都是意外死亡樱溉,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門纬凤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來福贞,“玉大人,你說我怎么就攤上這事停士⊥诹保” “怎么了?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵恋技,是天一觀的道長拇舀。 經(jīng)常有香客問我,道長蜻底,這世上最難降的妖魔是什么骄崩? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮薄辅,結(jié)果婚禮上要拂,老公的妹妹穿的比我還像新娘。我一直安慰自己站楚,他們只是感情好脱惰,可當我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著窿春,像睡著了一般拉一。 火紅的嫁衣襯著肌膚如雪采盒。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天舅踪,我揣著相機與錄音纽甘,去河邊找鬼良蛮。 笑死抽碌,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的决瞳。 我是一名探鬼主播货徙,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼皮胡!你這毒婦竟也來了痴颊?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤屡贺,失蹤者是張志新(化名)和其女友劉穎蠢棱,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體甩栈,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡泻仙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了量没。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片玉转。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖殴蹄,靈堂內(nèi)的尸體忽然破棺而出究抓,到底是詐尸還是另有隱情,我是刑警寧澤袭灯,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布刺下,位于F島的核電站,受9級特大地震影響稽荧,放射性物質(zhì)發(fā)生泄漏怠李。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一蛤克、第九天 我趴在偏房一處隱蔽的房頂上張望捺癞。 院中可真熱鬧,春花似錦构挤、人聲如沸髓介。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽唐础。三九已至箱歧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間一膨,已是汗流浹背呀邢。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留豹绪,地道東北人价淌。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像瞒津,于是被迫代替她去往敵國和親蝉衣。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,490評論 2 348

推薦閱讀更多精彩內(nèi)容