CV02-07:OpenCV视频采集

  OpenCV的机器视觉包含静态图像处理(2D与3D)与动态视频处理,本主题主要梳理下C++的视频采集处理。


OpenCV视频处理结构

结构图

OpenCV视频在处理结构

核心类说明

VideoCapture类

  • 负责抓取视频,抓取源支持:照相机,视频文件,图形序列等。

VideoWriter

  • 负责写视频数据到文件,包括压缩等。

VideoCapture视频抓取

构造器

  • 一共三个构造器
    1. 默认构造器
    2. 视频设备构造器
    3. 视频文件构造器器
  1. 默认构造器
    • 默认构造器没有初始化设备,需要调用open函数初始化设备。

    cv::VideoCapture::VideoCapture( )   

  1. 视频设备构造器
    
    cv::VideoCapture::VideoCapture( 
        int     index,                                                  // 视频设备编号,从0开始
        int     apiPreference = CAP_ANY                     // 视频处理的底层API。FFMPEG,IMAGES,DSHOW
    )
        
  • FFMPEG:开源的视频处理框架;
  • IMAGES:图片序列(比如:GIF);
  • DSHOW:微软的DirectX中视频模块DSHOW;
  1. 视频文件构造器

    cv::VideoCapture::VideoCapture( 
        const String &       filename,                              // 视频文件路径。
        int                       apiPreference = CAP_ANY      // 视频处理的底层API。
    )

设备初始化

  • 使用open函数实现设备初始化。
    • 与构造器相同。
  1. 使用视频文件初始化
    virtual bool open (const String &filename, int apiPreference=CAP_ANY)
  1. 使用视频设备初始化
    virtual bool open (int index, int apiPreference=CAP_ANY)

判别设备是否初始化

  • isOpened函数
    virtual bool    isOpened () const

读取数据

  • 读取数据两种方式
    1. 直接读取
    2. 多设备情况下,需要先抓取缓冲,然后读取;

直接读取数据

  • 使用read函数与操作符读取;
  1. read函数读取
    virtual bool read (OutputArray image)
  • OutputArray image返回抓取的视频图像。
  1. >>操作符读取
    virtual VideoCapture& cv::VideoCapture::operator >>(Mat &   image   )   

缓冲读取

  • 缓冲读取分成两步:
    1. 使用grap函数抓取到缓冲;
    2. 使用retrieve函数返回视频图像;
  1. grap函数
    • 抓取视频图像成功,返回true;否则返回false
    virtual bool    grab ()
  1. retrieve 函数
    • 返回抓取的图像,比read多一个读取标记;
    virtual bool retrieve (
        OutputArray image, 
        int flag=0)                 // 用来指定图像的帧索引,或者底层IP的读取标记;

属性处理

  • 提供了set/get来设置与获取设备与底层属性
  1. set函数
     virtual bool   set (int propId, double value)
  1. get函数
    virtual double  get (int propId) const

释放设备

  • 使用release函数释放
    virtual void    release()

视频抓取应用例子

  • 例子的思路:
    • 创建一个线程,不同抓取视频图像,然后用信号的方式发送给窗体显示;

抓取图像的线程

  1. 头文件
    #ifndef VIDEO_THRWAD_H
    #define VIDEO_THRWAD_H
    #include 
    #include 

    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. 实现文件
    #include "videoth.h"
    #include

    // 构造器
    VideoThread::VideoThread():
        device(new cv::VideoCapture(0)){
    }
    VideoThread::VideoThread(int deviceid):
        device(new cv::VideoCapture(deviceid)){

    }
    // 析构器
    VideoThread::~VideoThread(){
        device->release();
        delete device;
    }

    // 线程主方法
    void VideoThread::run(){
        while(true){
            // 抓取图像,发送信息
            cv::Mat img;
            device->read(img);
            emit video(img);
            QThread::usleep(100);

        }
    }

图像处理类

  1. 头文件
    #ifndef IMAGE_PROCESSING_H
    #define IMAGE_PROCESSING_H

    #include 

    class ImageProcessing{
    public:
        ImageProcessing();
        ~ImageProcessing();
    public:
        void handle_filter2d(cv::InputArray img_src, cv::OutputArray img_out);
    };
    #endif // !IMAGE_PROCESSING_H
  1. 实现文件

    #include "imageprocessing.h"

    ImageProcessing::ImageProcessing(){

    }
    ImageProcessing::~ImageProcessing(){

    }
    void ImageProcessing::handle_filter2d(cv::InputArray img_src, cv::OutputArray img_dst){
        cv::Mat kernel = (cv::Mat_(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
  2. 申明需要注册的类型

    • Q_DECLARE_METATYPE(cv::Mat);
  3. 注册类型

    • qRegisterMetaType("Mat");
    • qRegisterMetaType("Mat&");
  4. 在主程序中注册的完整代码

    #include 
    #include "dlgvideo.h"

    #include 
    #include
    Q_DECLARE_METATYPE(cv::Mat);   

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

对话框类

  1. 头文件
    #ifndef DLG_VIDEO_H
    #define DLG_VIDEO_H
    #include 
    #include 
    #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. 实现文件
    #include "dlgvideo.h"
    #include 
    // 构造器与析构器
    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;
    }

    // 线程信号发过来的图像,并显示
    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的颜色格式转换
        cv::cvtColor(img_src, m_out, cv::COLOR_BGR2RGBA); 
        // 转换为Qt图像
        QImage i_out(m_out.data, m_out.cols, m_out.rows, QImage::Format_RGBA8888);
        // 转换为组件能处理的像素格式
        QPixmap p_out = QPixmap::fromImage(i_out);
        // 显示图像
        dlg->lbl_video->setPixmap(p_out);
        // 缩放图像适应组件大小
        dlg->lbl_video->setScaledContents(true);
    }

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

    }

Makefile

  • 这个文件使用了文件处理函数,来生成moc文件;因为有多个moc文件需要生成,所以还采用了循环。
  • 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. 构造器
    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)

你可能感兴趣的:(CV02-07:OpenCV视频采集)