《OpenCV2 计算机视觉编程手册》视频处理一

2024-04-07 06:38

本文主要是介绍《OpenCV2 计算机视觉编程手册》视频处理一,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文主要结合《OpenCV2 计算机视觉编程手册》第10章的内容,学习OpenCV 处理视频图像的一般方法,包括读入,处理,写出。

1.头文件

#ifndef HEAD_H_
#define HEAD_H_#include <iostream>
#include <iomanip>// 控制输出格式
#include <sstream>// 文件流控制
#include <string>
#include <vector>#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>#endif // HEAD_H_


2. VideoProcessor头文件


#ifndef VPROCESSOR_H_
#define VPROCESSOR_H_#include "head.h"void canny(cv::Mat& img, cv::Mat& out)
{cv::cvtColor(img, out, CV_BGR2GRAY);                      // 灰度转换cv::Canny(out, out, 100, 200);                            // Canny边缘检测cv::threshold(out, out, 128, 255, cv::THRESH_BINARY_INV); // 二值图像反转, 小于128设置为255, 否则为0;即边缘为黑色
}// 抽象类FrameProcessor中纯虚函数process必须在子类(其继承类)中重新定义。
// http://blog.csdn.net/hackbuteer1/article/details/7558868 
// 帧处理器接口
class FrameProcessor 
{public:// 处理方法,定义为纯虚函数, 让其子类实现具体的接口virtual void process(cv:: Mat &input, cv:: Mat &output)= 0;
};class VideoProcessor 
{private:cv::VideoCapture capture;           // OpenCV视频采集对象(object)void (*process)(cv::Mat&, cv::Mat&);// 每帧处理的回调函数, 函数指针调用FrameProcessor *frameProcessor;     // 基类(含纯虚函数的抽象类)FrameProcessor接口指针, 指向子类的实现bool callIt;                        // 启动回调函数与否的bool判断, true:调用, false:不调用std::string windowNameInput;        // 输入显示窗口名字std::string windowNameOutput;       // 输出显示窗口名字int delay;                          // 帧间处理延迟long fnumber;                       // 已处理帧总数long frameToStop;                   // 在该帧停止	  bool stop;                          // 停止处理标志位!std::vector<std::string> images;               // 输入的图像集或者图像向量(vector容器)std::vector<std::string>::const_iterator itImg;// 图像集的迭代器cv::VideoWriter writer;             // OpenCV视频写出对象std::string outputFile;             // 输出视频文件名字int currentIndex;                   // 输出图像集的当前索引int digits;                         // 输出图像文件名字的数字 std::string extension;              // 输出图像集的扩展名// Getting the next frame which could be: video file; camera; vector of imagesbool 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;}else{return false;}}}// Writing the output frame which could be: video file or imagesvoid writeNextFrame(cv::Mat& frame) {if (extension.length()) { // 输出图像文件std::stringstream ss;ss << outputFile << std::setfill('0') << std::setw(digits) << currentIndex++ << extension;cv::imwrite(ss.str(),frame);} else { // 输出视频文件writer.write(frame);}}public:// 构造函数VideoProcessor() : callIt(false), delay(-1), fnumber(0), stop(false), digits(0), frameToStop(-1), process(0), frameProcessor(0) {}// 设置视频文件的名字bool setInput(std::string filename) {fnumber= 0;// In case a resource was already // associated with the VideoCapture instancecapture.release();            // 释放之前打开过的资源images.clear();               // 释放之前打开过的资源return capture.open(filename);// 打开视频文件}// 设置相机IDbool setInput(int id) {fnumber= 0;// In case a resource was already // associated with the VideoCapture instancecapture.release();images.clear();// 打开视频文件return capture.open(id);}// 设置输入的图像集bool setInput(const std::vector<std::string>& imgs) {fnumber= 0;// In case a resource was already // associated with the VideoCapture instancecapture.release();//释放之前打开过的资源// 输入的是图像集images= imgs;itImg= images.begin();return true;}// 设置输出视频文件, 默认参数和输入的一样bool setOutput(const std::string &filename, int codec=0, double framerate=0.0, bool isColor=true) {outputFile= filename;extension.clear();if (framerate==0.0) framerate= getFrameRate(); // 与输入相同char c[4];                     // 使用和输入相同的编码格式if (codec==0) { codec= getCodec(c);}// 打开输出视频return writer.open(outputFile, // 文件名codec,                     // 使用的解码格式 framerate,                 // 帧率getFrameSize(),            // 帧大小isColor);                  // 是否为彩色视频}// 设置输出是图像集, 后缀必须是".jpg", ".bmp" ...bool setOutput(const std::string &filename, // 文件名前缀const std::string &ext,                 // 图像文件后缀 int numberOfDigits=3,                   // 数字位数int startIndex=0)                       // 开始索引000{     if (numberOfDigits<0)                   // 数字位数必须是正数return false;outputFile = filename;                  // 文件名extension  = ext;                       // 公共后缀名digits       = numberOfDigits;          // 文件名中的数字位数 currentIndex = startIndex;              // 开始索引return true;}// 设置每一帧的回调函数void setFrameProcessor(void (*frameProcessingCallback)(cv::Mat&, cv::Mat&)) {// invalidate frame processor class instance 使FrameProcessor实例无效化frameProcessor = 0;process = frameProcessingCallback;callProcess();}// 设置FrameProcessor接口实例void setFrameProcessor(FrameProcessor* frameProcessorPtr) {// invalidate callback function 使回调函数无效化process = 0;frameProcessor= frameProcessorPtr;callProcess();}// 在frame帧停止void stopAtFrameNo(long frame) {frameToStop= frame;}// 处理回调函数void callProcess() {callIt= true;}// 不调用回调函数void dontCallProcess() {callIt= false;}// 显示输入的图像帧void displayInput(std::string wn) {windowNameInput= wn;cv::namedWindow(windowNameInput);}// 显示处理的图像帧void displayOutput(std::string wn) {windowNameOutput= wn;cv::namedWindow(windowNameOutput);}// 不显示处理的图像帧void dontDisplay() {cv::destroyWindow(windowNameInput);cv::destroyWindow(windowNameOutput);windowNameInput.clear();windowNameOutput.clear();}// 设置帧间延迟时间// 0 means wait at each frame// negative means no delayvoid setDelay(int d) {delay= d;}// 处理帧的总数long getNumberOfProcessedFrames() {return fnumber;}// 返回视频帧的大小cv::Size getFrameSize() {if (images.size()==0) {// get size of from the capture deviceint w= static_cast<int>(capture.get(CV_CAP_PROP_FRAME_WIDTH));int h= static_cast<int>(capture.get(CV_CAP_PROP_FRAME_HEIGHT));return cv::Size(w,h);} else { // if input is vector of imagescv::Mat tmp= cv::imread(images[0]);if (!tmp.data) return cv::Size(0,0);else return tmp.size();}}// 返回下一帧的帧数long getFrameNumber() {if (images.size()==0) {// get info of from the capture devicelong f= static_cast<long>(capture.get(CV_CAP_PROP_POS_FRAMES));return f; } else { // if input is vector of imagesreturn static_cast<long>(itImg-images.begin());}}// return the position in msdouble getPositionMS() {// undefined for vector of imagesif (images.size()!=0) return 0.0;double t= capture.get(CV_CAP_PROP_POS_MSEC);return t; }// 返回帧率double getFrameRate() {// undefined for vector of imagesif (images.size()!=0) return 0;double r= capture.get(CV_CAP_PROP_FPS);return r; }// 返回视频中图像的总数long getTotalFrameCount(){// for vector of imagesif (images.size()!=0) return images.size();long t= capture.get(CV_CAP_PROP_FRAME_COUNT);return t; }// 获取输入视频的编解码器int getCodec(char codec[4]) {// 未制定的图像集if (images.size()!=0) return -1;union {// 4-char编码的数据结果int value;char code[4]; } returned;// 获取编码returned.value= static_cast<int>(capture.get(CV_CAP_PROP_FOURCC));// 获得4字符codec[0]= returned.code[0];codec[1]= returned.code[1];codec[2]= returned.code[2];codec[3]= returned.code[3];// 返回对应的整数return returned.value;}// 设置帧位置bool setFrameNumber(long pos) {// for vector of imagesif (images.size()!=0) {// move to position in vectoritImg= images.begin() + pos;// is it a valid position?if (pos < images.size())return true;elsereturn false;} else { // if input is a capture devicereturn capture.set(CV_CAP_PROP_POS_FRAMES, pos);}}// go to this positionbool setPositionMS(double pos) {// not defined in vector of imagesif (images.size()!=0) return false;else return capture.set(CV_CAP_PROP_POS_MSEC, pos);}// go to this position expressed in fraction of total film lengthbool setRelativePosition(double pos) {// for vector of imagesif (images.size()!=0) {// move to position in vectorlong posI= static_cast<long>(pos*images.size()+0.5);itImg= images.begin() + posI;// is it a valid position?if (posI < images.size())return true;elsereturn false;} else { // if input is a capture devicereturn capture.set(CV_CAP_PROP_POS_AVI_RATIO, pos);}}// 停止运行void stopIt() {stop= true;}// 是否已停止运行?bool isStopped() {return stop;}// 判断是否是视频捕获设备或图像集bool isOpened() {return capture.isOpened() || !images.empty();}// 获取并处理图像void run() {cv::Mat frame;  // 当前帧cv::Mat output; // 输出帧// if no capture device has been setif (!isOpened())return;stop= false;while (!isStopped()) {// 读取下一帧if (!readNextFrame(frame))break;// 显示输出帧if (windowNameInput.length()!=0) cv::imshow(windowNameInput,frame);// 调用帧处理回调函数或FrameProcessor实例if (callIt) {  // 处理当前帧if (process)             // 如果是回调函数process(frame, output);else if (frameProcessor) //如果是FrameProcessor实例frameProcessor->process(frame,output);// 增加帧数fnumber++;}else{output= frame;}// 写出输出图像序列if (outputFile.length()!=0)writeNextFrame(output);// 显示输出帧if (windowNameOutput.length()!=0) cv::imshow(windowNameOutput,output);// 引入帧间延迟if (delay>=0 && cv::waitKey(delay)>=0)stopIt();// 检查是否需要停止运行if (frameToStop>=0 && getFrameNumber()==frameToStop)stopIt();}}
};#endif // VPROCESSOR_H_

3. 主函数


#include "head.h"
#include "videoprocessor.h"int main()
{//----Zero Test----cv::VideoCapture capture("../bike.avi"); // 打开视频/摄像头0if (!capture.isOpened())return 1;double rate= capture.get(CV_CAP_PROP_FPS);// 获取帧率bool stop(false);cv::Mat frame;                            // 当前帧cv::namedWindow("Extracted Frame");int delay= 1000/rate;                     // 延迟的毫秒//int delay = 1000;// 处理视频所有帧while (!stop) {// read next frame if anyif (!capture.read(frame))break;cv::imshow("Extracted Frame",frame);if (cv::waitKey(delay)>=0)            // 延迟等待直到cv::waitKey(delay)<0stop= true;}capture.release();                       // 因为capture自动调用析构函数,所以capture.release不是必须的!cv::waitKey();//----First Test----VideoProcessor processor;                           // 创建VideoProcessor类实例 processorprocessor.setInput("../bike.avi");                  // 打开视频文件bike.aviprocessor.displayInput("Input Video");              // 声明输入视频显示窗口processor.displayOutput("Output Video");            // 声明输出视频显示窗口processor.setDelay(1000./processor.getFrameRate()); // 设置播放视频为原始输入视频帧率processor.setFrameProcessor(canny);                 // 设置帧处理器的回调函数--cannyprocessor.run();                                    // 开始处理视频文件cv::waitKey();                                      // 等待按键响应//----Second test----processor.setInput("../bike.avi");                            // 重新设置打开视频cv::Size size= processor.getFrameSize();                      // 获取视频文件的基本信息std::cout << size.width << " " << size.height << std::endl;   // 视频图像的宽度(列)和高度(行)std::cout << processor.getFrameRate() << std::endl;           // 视频的帧率std::cout << processor.getTotalFrameCount() << std::endl;     // 视频总的帧数std::cout << processor.getFrameNumber() << std::endl;         // 视频帧的编号std::cout << processor.getPositionMS() << std::endl;          // 视频帧的位置(ms)processor.dontCallProcess();                                   // 不处理打开视频文件// 输出.jpg视频图像到output文件夹, 图像名字为bikeOut000.jpg~bikeOut118.jpgprocessor.setOutput("../output/bikeOut",".jpg");               processor.run(); cv::waitKey();// 输出bike.avi视频到output文件夹,编解码器为:XVID, 基于MPEG-4视频标准的开源解码库char codec[4];                                                 // 编解码器标识processor.setOutput("../output/bike.avi",processor.getCodec(codec),processor.getFrameRate());std::cout << "Codec: " << codec[0] << codec[1] << codec[2] << codec[3] << std::endl;processor.run();cv::waitKey();//----Three test----processor.setInput("../bike.avi");processor.displayInput("Input Video");              // 声明输入视频显示窗口processor.displayOutput("Output Video");            // 声明输出视频显示窗口processor.setFrameNumber(80);                       // 设置帧的位置processor.stopAtFrameNo(120);                       // 停止的帧位置processor.setDelay(1000./processor.getFrameRate());processor.run();cv::waitKey();return 0;
}

Canny边缘检测



视频写出结果(包含文件和视频)



制定开始帧和结束帧位置








这篇关于《OpenCV2 计算机视觉编程手册》视频处理一的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/881889

相关文章

流媒体平台/视频监控/安防视频汇聚EasyCVR播放暂停后视频画面黑屏是什么原因?

视频智能分析/视频监控/安防监控综合管理系统EasyCVR视频汇聚融合平台,是TSINGSEE青犀视频垂直深耕音视频流媒体技术、AI智能技术领域的杰出成果。该平台以其强大的视频处理、汇聚与融合能力,在构建全栈视频监控系统中展现出了独特的优势。视频监控管理系统EasyCVR平台内置了强大的视频解码、转码、压缩等技术,能够处理多种视频流格式,并以多种格式(RTMP、RTSP、HTTP-FLV、WebS

无人叉车3d激光slam多房间建图定位异常处理方案-墙体画线地图切分方案

墙体画线地图切分方案 针对问题:墙体两侧特征混淆误匹配,导致建图和定位偏差,表现为过门跳变、外月台走歪等 ·解决思路:预期的根治方案IGICP需要较长时间完成上线,先使用切分地图的工程化方案,即墙体两侧切分为不同地图,在某一侧只使用该侧地图进行定位 方案思路 切分原理:切分地图基于关键帧位置,而非点云。 理论基础:光照是直线的,一帧点云必定只能照射到墙的一侧,无法同时照到两侧实践考虑:关

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

【生成模型系列(初级)】嵌入(Embedding)方程——自然语言处理的数学灵魂【通俗理解】

【通俗理解】嵌入(Embedding)方程——自然语言处理的数学灵魂 关键词提炼 #嵌入方程 #自然语言处理 #词向量 #机器学习 #神经网络 #向量空间模型 #Siri #Google翻译 #AlexNet 第一节:嵌入方程的类比与核心概念【尽可能通俗】 嵌入方程可以被看作是自然语言处理中的“翻译机”,它将文本中的单词或短语转换成计算机能够理解的数学形式,即向量。 正如翻译机将一种语言

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能

【编程底层思考】垃圾收集机制,GC算法,垃圾收集器类型概述

Java的垃圾收集(Garbage Collection,GC)机制是Java语言的一大特色,它负责自动管理内存的回收,释放不再使用的对象所占用的内存。以下是对Java垃圾收集机制的详细介绍: 一、垃圾收集机制概述: 对象存活判断:垃圾收集器定期检查堆内存中的对象,判断哪些对象是“垃圾”,即不再被任何引用链直接或间接引用的对象。内存回收:将判断为垃圾的对象占用的内存进行回收,以便重新使用。

Go Playground 在线编程环境

For all examples in this and the next chapter, we will use Go Playground. Go Playground represents a web service that can run programs written in Go. It can be opened in a web browser using the follow

深入理解RxJava:响应式编程的现代方式

在当今的软件开发世界中,异步编程和事件驱动的架构变得越来越重要。RxJava,作为响应式编程(Reactive Programming)的一个流行库,为Java和Android开发者提供了一种强大的方式来处理异步任务和事件流。本文将深入探讨RxJava的核心概念、优势以及如何在实际项目中应用它。 文章目录 💯 什么是RxJava?💯 响应式编程的优势💯 RxJava的核心概念