首页 > 作文

OpenCV2学习笔记之视频流读取与处理

更新时间:2023-04-04 11:19:14 阅读: 评论:0

目录
前言一. 读取视频序列二. 处理视频帧opencv:打开摄像头获取视频流总结

前言

由于项目需要,计划实现九路视频拼接,因此必须熟悉opencv对视频序列的处理。视频信号处理是图像处理的一个延伸,所谓的视频序列是由按一定顺序进行排放的图像组成,即帧(frame)。在这里,主要记录下如何使用qt+opencv读取视频中的每一帧,之后,在这基础上将一些图像处理的算法运用到每一帧上(如使用canny算子检测视频中的边缘)。

一. 读取视频序列

opencv提供了一个简便易用的框架以提取视频文件和usb摄像头中的图像帧,如果只是单单想读取某个视频,你只需要创建一个cv::videocapture实例,然后在循环中提取每一帧。新建一个qt控制台项目,直接在main函数添加:

#include <qcoreapplication>#include <opencv2/core/core.hpp>#include <opencv2/imgproc/imgproc.hpp>#include <opencv2/highgui/highgui.hpp>#include <qdebug>int main(int argc, char *argv[]){    qcoreapplication a(argc, argv);    // 读取视频流    cv::videocapture capture("e:/brokegirls.mkv");    // 检测视频是否读取成功    if (!capture.isopened())    {        qdebug() << "no input image";        return 1;    }    // 获取图像帧率    double rate= capture.get(cv_cap_prop_fps);    bool stop(fal);    cv::mat frame; // 当前视频帧    cv::namedwindow("extracted frame");    // 每一帧之间的延迟    int delay= 1000/rate;    // 遍历每一帧    while (!stop)    {        // 尝试读取下一帧        if (!capture.read(frame))            break;        cv::imshow("extracted frame",frame);        // 引入延迟        if (cv::waitkey(delay)>=0)                stop= true;    }        return a.exec();}

(注意:要正确打开视频文件,计算机中必须安装有对应的解码器,否则cv::videocapture无法理解视频格式!)运行后,将出现一个窗口,播放选定的视频(需要在创建cv::videocapture对象时指定视频的文件名)。

二. 处理视频帧

为了对视频的每一帧进行处理,这里创建自己的类videoprocessor,其中封装了opencv的视频获取框架,该类允许我们指定每帧调用的处理函数。

首先,我们希望指定一个回调处理函数,每一帧中都将调用它。该函数接受一个cv::mat对象,并输出处理后的cv::mat对象,其函数签名如下:

void processframe(cv::mat& img, cv::mat& out);

作为这样一个处理函数的例子,以下的canny函数计算图像的边缘,使用时直接添加在mian文件中即可:

    // 对视频的每帧做canny算子边缘检测void canny(cv::mat& img, cv::mat& out) {    // 先要把每帧图像转化为灰度图    cv::cvtcolor(img,out,cv_bgr2gray);    // 调用canny函数    cv::canny(out,out,100,200);    // 对像素进行翻转    cv::threshold(out,out,128,255,cv::thresh_binary_inv);}

现在我们需要创建一个videoprocessor类,用来部署视频处理模块。而在此之前,需要先另外创建一个类,即videoprocessor内部使用的帧处理类。这是因为在面向对象的上下文中,更适合使用帧处理类而不是一个帧处理函数,而使用类可以给程序员在涉及算法方面有更多的灵活度(书上介绍的)。将这个内部帧处理类命名为frameprocessor,其定义如下:

#ifndef frameprocessor_h#define frameprocessor_h#include <opencv2/core/core.hpp>#include <opencv2/highgui/highgui.hpp>class frameprocessor{public:    virtual 猫的英语单词void process(cv:: mat &input, cv:: mat &output)= 0;};#endif // frameprocessor_h

现在可以开始定义videoprocessor类了,以下为videoprocessor.h中的内容:

#ifndef videoprocessor_h#define videoprocessor_h#include <opencv2/core/core.hpp>#include <opencv2/imgproc/imgproc.hpp>#include <opencv2/highgui/highgui.hpp>#include <qdebug>#include "frameprocessor.h"class videoprocessor{  private:      // 创建视频捕获对象      cv::videocapture capture;      // 每帧调用的回调函数      void (*process)(cv::mat&, cv::mat&);      // frameprocessor接口      frameprocessor *frameprocessor;      // 确定是否调用回调函数的bool信号      bool callit;      // 输入窗口的名称      std::string windownameinput;      // 输出窗口的名称      std::string windownameoutput;      // 延迟      int delay;      // 已处理的帧数      long fnumber;      // 在该帧停止      long frametostop;      // 是否停止处理      bool stop;      // 当输入图像序列存储在不同文件中时,可使用以下设置      // 把图像文件名的数组作为输入      std::vector<std::string> images;      // 图像向量的迭加器      std::vector<std::string>::const_iterator itimg;      // 得到下一帧      // 可能来自:视频文件或摄像头      bool readnextframe(cv::mat &frame)      {          if (images.size()==0)              return capture.read(frame);          el {              if (itimg != images.end())              {                  frame=生活中的小镜头 cv::imread(*itimg);                  itimg++;                  return frame.data != 0;              }          }      }public:      // 默认设置 digits(0), frametostop(-1),      videoprocessor() : callit(fal), delay(-1),          fnumber(0), stop(fal),          process(0), frameprocessor(0) {}      // 创建输入窗口      void displayinput(std::string wt);      // 创建输出窗口      void displayoutput(std::string wn);      // 不再显示处理后的帧      void dontdisplay();      // 以下三个函数设置输入的图像向量      bool tinput(std::string filename);      // 若输入为摄像头,设置id      bool tinput(int id);      // 若输入为一组图像序列时,应用该函数      bool tinput(const std::vector<std::string>& imgs);      // 设置帧之间的延迟      // 0意味着在每一帧都等待按键响应      // 负数意味着没有延迟      void tdelay(int d);      // 返回图像的帧率      double getframerate();      // 需要调用回调函数      void callprocess();      // 不需要调用回调函数      void dontcallprocess();      // 设置frameprocessor实例      void tframeprocessor(frameprocessor* frameprocessorptr);      // 设置回调函数      void tframeprocessor(void (*frameprocessingcallback)(cv::mat&, cv::mat&));      // 停止运行      void stopit();      // 判断是否已经停止      bool isstopped();      // 是否开始了捕获设备?      bool isopened();      // 返回下一帧的帧数      long getframenumber();      // 该函数获取并处理视频帧      void run();};#endif // videoprocessor_h

然后,在videoprocessor.cpp中定义各个函数的功能:

#include "videoprocessor.h"// 创建输入窗口void videoprocessor::displayinput(std::string wt){    windownameinput= wt;    cv::namedwindow(windownameinput);}// 创建输出窗口void videoprocessor::displayoutput(std::string wn){    windownameoutput= wn;    cv::namedwindow(windownameoutput);}// 不再显示处理后的帧void videoprocessor::dontdisplay(){    cv::destroywindow(windownameinput);    cv::destroywindow(windownameoutput);    windownameinput.clear();    windownameoutput.clear();}// 设置输入的图像向量bool videoprocessor::tinput(std::string filename){  fnumber= 0;  // 释放之前打开过的视频资源  capture.relea();  images.clear();  // 打开视频  return capture.open(filename);}// 若输入为摄像头,设置idbool videoprocessor::tinput(int id){  fnumber= 0;  // 释放之前打开过的视频资源  capture.relea();  images.clear();  // 打开视频文件  return capture.open(id);}// 若输入为一组图像序列时,应用该函数bool videoprocessor::tinput(const std::vector<std::string>& imgs){  fnumber= 0;  // 释放之前打开过的视频资源  capture.relea();  // 输入将是该图像的向量  images= imgs;  itimg= images.begin();  return true;}// 设置帧之间的延迟// 0意味着在每一帧都等待按键响应// 负数意味着没有延迟void videoprocessor::tdelay(int d){    delay= d;}// 返回图像的帧率double videoprocessor::getframerate(){    if (images.size()!=0) return 0;    double r= capture.get(cv_cap_prop_fps);    return r;}// 需要调用回调函数void videoprocessor::callprocess(){    callit= true;}// 不需要调用回调函数void videoprocessor::dontcallprocess(){    callit= fal;}// 设置frameprocessor实例void videoprocessor::tframeprocessor(frameprocessor* frameprocessorptr){    // 使回调函数无效化    process= 0;    // 重新设置frameprocessor实例    frameprocessor= frameprocessorptr;    callprocess();}// 设置回调函数void videoprocessor::tframeprocessor(void (*frameprocessingcallback)(cv::mat&, cv::mat&)){    // 使frameprocessor实例无效化    frameprocessor= 0;    // 重新设置回调函数    process= frameprocessingcallback;    callprocess();}// 以下函数表示视频的读取状态// 停止运行void videoprocessor::stopit(){    stop= true;}// 判断是否已经停止bool videoprocessor::isstopped(){    return stop;}// 是否开始了捕获设备?bool videoprocessor::isopened(){    return capture.iso半圆的面积怎么算pened() || !images.empty();}// 返回下一帧的帧数long videoprocessor::getframenumber(){  if (images.size()==0)  {      // 得到捕获设备的信息      long f= static_cast<long>(capture.get(cv_cap_prop_pos_frames));      return f;  }  el // 当输入来自一组图像序列时的情况  {      return static_cast<long>(itimg-images.begin());  }}// 该函数获取并处理视频帧void videoprocessor::run(){    // 当前帧    cv::mat frame;    // 输出帧    cv::mat output;    // 打开失败时    if (!isopened())    {        qdebug() << "error!";        return;    }    stop= fal;    while (!isstopped())    {        // 读取下一帧        if (!readnextframe(frame))            break;        // 显示输出帧        if (windownameinput.length()!=0)            cv::imshow(windownameinput,frame);        // 调用处理函数        if (callit)        {          // 处理当前帧          if (process)              process(frame, output);          el if (frameprocessor)              frameprocessor->process(frame,output);          // 增加帧数          fnumber++;        }        el        {          output= frame;        }        // 显示输出帧        if (windownameoutput.length()!=0)            cv::imshow(windownameoutput,output);        // 引入延迟        if (delay>=0 && cv::waitkey(delay)>=0)          stopit();        // 检查是否需要停止运行        if (frametostop>=0 && getframenumber()==frametostop)            stopit();    }}

定义好视频处理类,它将与一个回调函数相关联。使用该类,可以创建一个实例,指定输入的视频文件,绑定回调函数,然后开始对每一帧进行处理,要调用这个视频处理类,只需在main函数中添加:

    // 定义一个视频处理类处理视频帧    // 首先创建实例    videoprocessor processor;    // 打开视频文件    processor.tinput("e:/brokegirls.mkv");    // 声明显示窗口    // 分别为输入和输出视频    processor.displayinput("input video");    pr夜七七ocessor.displayoutput("output video");    // 以原始帧率播放视频    processor.tdelay(1000./processor.getframerate());    // 设置处理回调函数    processor.tframeprocessor(canny);    // 开始帧处理过程    processor.run();    cv::waitkey();

效果:

opencv:打开摄像头获取视频流

#include#includeusing namespace cv;using namespace std;int main(){//【1】从摄像头读入视频    videocapture capture(1);    if (!capture.isopened()){cout<< "open camera fail ..." << endl;        return -1;    }capture.t(cap_prop_frame_width, 640);    capture.t(cap_prop_frame_height, 480);    char filename[200];    int count =0;    //【2】循环显示每一帧    mat frame;  //定义一个mat变量,用于存储每一帧的图像    char key;    while (true){//读入图像        capture>> frame;  //读取当前帧        key = waitkey(20);        if(key ==27)//esc键退出            break;        if(key ==32)//空格键保存图像        {sprintf(filename, "picture_%d.png", ++count);            imwrite(filename, frame);//            namedwindow("[frame]", window_normal);            imshow("[frame]",frame);        }imshow("image", frame);  //显示当前帧    }return 0;集约用地}

总结

到此这篇关于opencv2学习笔记之视频流读取与处理的文章就介绍到这了,更多相关opencv视频流读取与处理内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!

本文发布于:2023-04-04 11:19:13,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/zuowen/71159fc5edd2656c610bface1ea58490.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

本文word下载地址:OpenCV2学习笔记之视频流读取与处理.doc

本文 PDF 下载地址:OpenCV2学习笔记之视频流读取与处理.pdf

标签:函数   视频   图像   回调
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图