OpenCV2学习笔记(九):视频流读取与处理

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

一. 读取视频序列

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

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(false);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(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,其定义如下:

{public:virtual void process(cv:: Mat &input, cv:: Mat &output)= 0;};#endif // FRAMEPROCESSOR_H

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

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;::vector<std::string> images;// 图像向量的迭加器std::vector<std::string>::const_iterator itImg;readNextFrame(cv::Mat &frame){if (images.size()==0)return capture.read(frame);else {if (itImg != images.end()){frame= cv::imread(*itImg);itImg++;return frame.data != 0;}}}public:// 默认设置 digits(0), frameToStop(-1),VideoProcessor() : callIt(false), delay(-1),fnumber(0), stop(false),process(0), frameProcessor(0) {}// 创建输入窗口void displayInput(std::string wt);// 创建输出窗口void displayOutput(std::string wn);// 不再显示处理后的帧void dontDisplay();// 以下三个函数设置输入的图像向量bool setInput(std::string filename);// 若输入为摄像头,设置IDbool setInput(int id);::vector<std::string>& imgs);setDelay(int d);// 返回图像的帧率double getFrameRate();// 需要调用回调函数void callProcess();// 不需要调用回调函数void dontCallProcess();// 设置FrameProcessor实例void setFrameProcessor(FrameProcessor* frameProcessorPtr);// 设置回调函数void setFrameProcessor(void (*frameProcessingCallback)(cv::Mat&, cv::Mat&));// 停止运行void stopIt();// 判断是否已经停止bool isStopped();// 是否开始了捕获设备?bool isOpened();// 返回下一帧的帧数long getFrameNumber();// 该函数获取并处理视频帧void run();};#endif // VIDEOPROCESSOR_H呼唤你前往另一个地方,过上另一种生活。

OpenCV2学习笔记(九):视频流读取与处理

相关文章:

你感兴趣的文章:

标签云: