使用 OpenCV 创建视频(74)

 返回:OpenCV系列文章目录(持续更新中......)
上一篇:OpenCV 库来捕获和处理视频输入和相似度测量(73)
下一篇:OpenCV使用 Kinect 和其他兼容 OpenNI 的深度传感器(75)

目标

每当您使用视频源时,您最终可能希望将图像处理结果保存为新视频文件的形式。对于简单的视频输出,您可以使用专为此设计的 OpenCV 内置 cv::VideoWriter 类。

  • 如何使用 OpenCV 创建视频文件
  • 您可以使用 OpenCV 创建什么类型的视频文件
  • 如何从视频中提取给定的颜色通道

作为一个简单的演示,我将只将输入视频文件的一个 BGR 颜色通道提取到新视频中。您可以从应用程序的控制台行参数中控制应用程序的流:

  • 第一个参数指向要处理的视频文件
  • 第二个参数可能是字符之一:R G B。这将指定要提取的通道。
  • 最后一个参数是字符 Y(是)或 N(否)。如果为否,则用于输入视频文件的编解码器将与用于输出的编解码器相同。否则,将弹出一个窗口,允许您选择要使用的编解码器。

例如,有效的命令行如下所示:

video-write.exe video/Megamind.avi R Y

源代码

您也可以在 OpenCV 源库的文件夹samples/cpp/tutorial_code/videoio/video-write/中找到源代码和这些视频文件,或从此处下载。

#include <iostream> // for standard I/O
#include <string> // for strings#include <opencv2/core.hpp> // Basic OpenCV structures (cv::Mat)
#include <opencv2/videoio.hpp> // Video writeusing namespace std;
using namespace cv;static void help()
{cout<< "------------------------------------------------------------------------------" << endl<< "This program shows how to write video files." << endl<< "You can extract the R or G or B color channel of the input video." << endl<< "Usage:" << endl<< "./video-write <input_video_name> [ R | G | B] [Y | N]" << endl<< "------------------------------------------------------------------------------" << endl<< endl;
}int main(int argc, char *argv[])
{help();if (argc != 4){cout << "Not enough parameters" << endl;return -1;}const string source = argv[1]; // the source file nameconst bool askOutputType = argv[3][0] =='Y'; // If false it will use the inputs codec typeVideoCapture inputVideo(source); // Open inputif (!inputVideo.isOpened()){cout << "Could not open the input video: " << source << endl;return -1;}string::size_type pAt = source.find_last_of('.'); // Find extension pointconst string NAME = source.substr(0, pAt) + argv[2][0] + ".avi"; // Form the new name with containerint ex = static_cast<int>(inputVideo.get(CAP_PROP_FOURCC)); // Get Codec Type- Int form// Transform from int to char via Bitwise operatorschar EXT[] = {(char)(ex & 0XFF) , (char)((ex & 0XFF00) >> 8),(char)((ex & 0XFF0000) >> 16),(char)((ex & 0XFF000000) >> 24), 0};Size S = Size((int) inputVideo.get(CAP_PROP_FRAME_WIDTH), // Acquire input size(int) inputVideo.get(CAP_PROP_FRAME_HEIGHT));VideoWriter outputVideo; // Open the outputif (askOutputType)outputVideo.open(NAME, ex=-1, inputVideo.get(CAP_PROP_FPS), S, true);elseoutputVideo.open(NAME, ex, inputVideo.get(CAP_PROP_FPS), S, true);if (!outputVideo.isOpened()){cout << "Could not open the output video for write: " << source << endl;return -1;}cout << "Input frame resolution: Width=" << S.width << " Height=" << S.height<< " of nr#: " << inputVideo.get(CAP_PROP_FRAME_COUNT) << endl;cout << "Input codec type: " << EXT << endl;int channel = 2; // Select the channel to saveswitch(argv[2][0]){case 'R' : channel = 2; break;case 'G' : channel = 1; break;case 'B' : channel = 0; break;}Mat src, res;vector<Mat> spl;for(;;) //Show the image captured in the window and repeat{inputVideo >> src; // readif (src.empty()) break; // check if at endsplit(src, spl); // process - extract only the correct channelfor (int i =0; i < 3; ++i)if (i != channel)spl[i] = Mat::zeros(S, spl[0].type());merge(spl, res);//outputVideo.write(res); //save oroutputVideo << res;}cout << "Finished writing" << endl;return 0;
}

视频的结构

首先,您应该对视频文件的外观有所了解。每个视频文件本身都是一个容器。容器的类型以文件扩展名表示(例如 avimov 或 mkv)。这包含多个元素,例如:视频源、音频源或其他轨道(例如字幕)。这些源的存储方式由用于每个源的编解码器决定。对于音轨,常用的编解码器是mp3aac。对于视频文件,列表在某种程度上更长,包括 XVID、DIVXH264 或 LAGSLagarith 无损编解码器)等名称。您可以在系统上使用的编解码器的完整列表仅取决于您安装了什么编解码器。

如您所见,视频可能会变得非常复杂。但是,OpenCV 主要是一个计算机视觉库,而不是视频流、编解码器和写入库。因此,开发人员试图使这部分尽可能简单。因此,用于视频容器的 OpenCV 仅支持 avi 扩展,即其第一个版本。这样做的直接限制是您不能保存大于 2 GB 的视频文件。此外,您只能在容器内创建和扩展单个视频轨道。此处不支持音频或其他轨道编辑。尽管如此,您系统上存在的任何视频编解码器都可能有效。如果您遇到其中一些限制,您将需要研究更专业的视频编写库,例如 FFmpeg 或编解码器,如 HuffYUVCorePNG 和 LCL。或者,使用 OpenCV 创建视频轨道并使用音轨扩展它,或者使用 VirtualDub 或 AviSynth 等视频处理程序将其转换为其他格式。

VideoWriter 类

此处编写的内容基于以下假设:您已经阅读了使用 OpenCV 的视频输入和相似度测量教程,并且您知道如何阅读视频文件。要创建视频文件,您只需要创建 cv::VideoWriter 类的实例。您可以通过构造函数中的参数指定其属性,也可以稍后通过 cv::VideoWriter::open 函数指定其属性。无论哪种方式,参数都是相同的:1. 在其扩展中包含容器类型的输出的名称。目前仅支持 avi。我们从输入文件构造它,将要使用的通道名称添加到其中,然后使用容器扩展完成它。

const string source = argv[1]; // the source file name
string::size_type pAt = source.find_last_of('.'); // Find extension point
const string NAME = source.substr(0, pAt) + argv[2][0] + ".avi"; // Form the new name with container
  1. 用于视频轨道的编解码器。现在,所有视频编解码器都有一个唯一的短名称,最多四个字符。因此,XVID、DIVX 或 H264 名称。这称为四字符代码。您也可以使用其 get 函数从输入视频中询问此问题。由于 get 函数是通用函数,因此它始终返回双精度值。双精度值存储在 64 位上。四个字符是四个字节,即 32 位。这四个字符以双精度的下 32 位编码。丢弃上面 32 位的一种简单方法是将此值转换为 int
    VideoCapture inputVideo(source); // Open input
    int ex = static_cast<int>(inputVideo.get(CAP_PROP_FOURCC)); // Get Codec Type- Int form

    OpenCV 在内部使用此整数类型,并期望将其作为其第二个参数。现在,要从整数形式转换为字符串,我们可以使用两种方法:按位运算符和并集方法。第一个从 int 中提取字符看起来像(一个“and”操作,一些移动并在末尾添加一个 0 以关闭字符串):
    char EXT[] = {ex & 0XFF , (ex & 0XFF00) >> 8,(ex & 0XFF0000) >> 16,(ex & 0XFF000000) >> 24, 0};
    您可以对联合执行以下操作:
    union { int v; char c[5];} uEx ;
    uEx.v = ex; // From Int to char via union
    uEx.c[4]='\0';
    这样做的优点是转换是在分配后自动完成的,而对于按位运算符,您需要在更改编解码器类型时执行操作。如果您事先知道编解码器的四个字符代码,则可以使用 CV_FOURCC 宏来构建整数:
    CV_FOURCC('P','I','M,'1') // this is an MPEG1 codec from the characters to integer
    如果通过此参数减去 1,则在运行时会弹出一个窗口,其中包含系统上安装的所有编解码器,并要求您选择要使用的编解码器:

  1. 输出视频的每秒帧数。同样,在这里,我使用 get 函数保持每秒输入视频帧数。
  2. 输出视频的帧大小。在这里,我也使用 get 函数保持每秒输入视频帧大小。
  3. 最后一个参数是可选的。默认情况下为 true,并表示输出将是彩色的(因此对于写入,您将发送三个通道图像)。要创建灰度视频,请在此处传递 false 参数。

以下是我在示例中如何使用它:

VideoWriter outputVideo;
Size S = Size((int) inputVideo.get(CAP_PROP_FRAME_WIDTH), //Acquire input size(int) inputVideo.get(CAP_PROP_FRAME_HEIGHT));
outputVideo.open(NAME , ex, inputVideo.get(CAP_PROP_FPS),S, true);

之后,使用 cv::VideoWriter::isOpened()函数来确定打开的操作是否成功。当 VideoWriter 对象被销毁时,视频文件将自动关闭。成功打开对象后,可以使用类的 cv::VideoWriter::write 函数按顺序发送视频帧。或者,您可以使用其重载运算符<<:

outputVideo.write(res); //or
outputVideo << res;

从 BGR 图像中提取颜色通道意味着将其他通道的 BGR 值设置为零。您可以使用图像扫描操作或使用拆分和合并操作来执行此操作。首先将通道拆分为不同的图像,将其他通道设置为相同大小和类型的零图像,最后将它们合并回来:

split(src, spl); // process - extract only the correct channel
for( int i =0; i < 3; ++i)if (i != channel)spl[i] = Mat::zeros(S, spl[0].type());
merge(spl, res);

把所有这些放在一起,你会得到上面的源代码,其运行时结果将显示围绕这个想法的东西:

您可以在 YouTube 上观察此操作时实例。

参考文献:

1、《Creating a video with OpenCV》------Bernát Gábor

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/324350.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Zabbix6.0容器化部署(Docker-Composed)

Zabbix 为每个 Zabbix 组件提供 Docker image 作为可移植和自给自足的容器&#xff0c;以加快部署和更新过程。 Zabbix 组件在 Ubuntu、Alpine Linux 和 CentOS 基础 image 上提供:Zabbix 组件支持 MySQL 和 PostgreSQL 数据库、Apache2 和 Nginx Web 服务器。 1. Zabbix 组件…

ASP.NET网上车辆档案管理系统

摘 要 本文采用基于Web的Asp.net技术&#xff0c;并与sql server 2000数据库相结合&#xff0c;研发了一套车辆档案管理系统。该系统扩展性好&#xff0c;易于维护。简化了车辆档案设计流程&#xff0c;去除了冗余信息。汽车销售企业可以通过本系统完成整个销售及售后所有档案…

C语言指针的初级练习

前言 从0开始记录我的学习历程&#xff0c;我会尽我所能&#xff0c;写出最最大白话的文章&#xff0c;希望能够帮到你&#xff0c;谢谢。 提示&#xff1a;文章作者为初学者&#xff0c;有问题请评论指正&#xff0c;感谢。 哥们嗷 不知道你和我是否一样在学习C语言指针的时…

【ZZULI数据结构实验】压缩与解码的钥匙:赫夫曼编码应用

&#x1f4c3;博客主页&#xff1a; 小镇敲码人 &#x1f49a;代码仓库&#xff0c;欢迎访问 &#x1f680; 欢迎关注&#xff1a;&#x1f44d;点赞 &#x1f442;&#x1f3fd;留言 &#x1f60d;收藏 &#x1f30f; 任尔江湖满血骨&#xff0c;我自踏雪寻梅香。 万千浮云遮碧…

使用 Docker 部署 TaleBook 私人书籍管理系统

1&#xff09;项目介绍 GitHub&#xff1a;https://github.com/talebook/talebook Talebook 是一个简洁但强大的私人书籍管理系统。它基于 Calibre 项目构建&#xff0c;具备书籍管理、在线阅读与推送、用户管理、SSO 登录、从百度/豆瓣拉取书籍信息等功能。 友情提醒&#x…

工业交换机外壳材质大比拼,看看哪种外壳适合你

在工业领域里&#xff0c;交换机就像我们的网络心脏&#xff0c;时刻跳动着确保信息畅通无阻。而它的外壳&#xff0c;就是保护这颗“心脏”的铠甲。今天&#xff0c;咱们就来聊聊这些铠甲——工业交换机外壳的材质和防护等级&#xff0c;看看它们如何守护我们的网络世界。 首…

网络编程基础回顾

计算机网络&#xff08;5&#xff09;&#xff1a;运输层 OSI 模型与 TCP/IP 协议 OSI七层协议模型 (open system interconnection) 应用层&#xff1a;为应用数据提供服务表示层&#xff1a;数据格式转化&#xff0c;数据加密会话层&#xff1a;建立、维护和管理会话传输层&…

算法设计与分析 动态规划/回溯

1.最大子段和 int a[N]; int maxn(int n) {int tempa[0];int ans0;ansmax(temp,ans);for(int i1;i<n;i){if(temp>0){tempa[i];}else tempa[i];ansmax(temp,ans);}return ans; } int main() {int n,ans0;cin>>n;for(int i0;i<n;i) cin>>a[i];ansmaxn(n);co…

【吃透Java手写】4-Tomcat-简易版

【吃透Java手写】Tomcat-简易版-源码解析 1 准备工作1.1 引入依赖1.2 创建一个Tomcat的启动类 2 线程池技术回顾2.1 线程池的使用流程2.2 线程池的参数2.2.1 任务队列&#xff08;workQueue&#xff09;2.2.2 线程工厂&#xff08;threadFactory&#xff09;2.2.3 拒绝策略&…

财务管理|基于SprinBoot+vue的财务管理系统(源码+数据库+文档)

财务管理系统 目录 基于SprinBootvue的财务管理系统 一、前言 二、系统设计 三、系统功能设计 系统功能实现 1管理员功能模块 2员工功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1…

视频批量剪辑指南:一键合并视频并添加背景音乐,高效便捷

在数字化时代&#xff0c;视频剪辑已经成为了一项常见且重要的技能。无论是制作家庭影片、工作展示还是社交媒体内容&#xff0c;掌握高效的视频剪辑技巧都能极大地提升我们的工作效率和创作质量。本文将为您介绍云炫AI智剪中高效的视频批量剪辑方法&#xff0c;让您能够一键合…

在线教程|图灵奖得主Yann LeCun盛赞!小红书开源InstantID,一张原图即可定制多种风格写真

不久前&#xff0c;一群来自小红书的 95 后工程师联合北大团队发布了开源项目「InstantID」&#xff0c;只需上传一张照片&#xff0c;这款 AI 写真神器就能轻松定制多种风格的 AI 写真&#xff0c;告别繁琐修图。 InstantID 一经发布就引起了广泛关注&#xff0c;GitHub 收藏量…

Java实现的网上书店系统(附带完整源码)

作者声明:文章仅供学习交流与参考!严禁用于任何商业与非法用途!否则由此产生的一切后果均与作者 实现技术:JSP技术;javaBean;servlet;MySql数据库。 系统功能结构图 该系统为MVC结构,它的运行环境分客户端、应用服务器端和数据库服务器端三部分 书店系统需求分析: 通过…

通用人工智能AGI,究竟是一个哲学问题还是技术问题?

引言 在探索人工智能的未来方向中&#xff0c;人工通用智能&#xff08;AGI&#xff09;的概念逐渐成为科技领域和哲学探讨的焦点。AGI旨在创建可以执行任何智能任务的机器&#xff0c;甚至在某些方面超越人类的能力。然而&#xff0c;关于AGI的研究不仅仅是技术问题&#xff…

天龙怀旧游戏python脚本

设置图&#xff1a; 游戏窗口最大化。 海贼洞这里定位你要回点的定位。 运行bat就行&#xff0c;脚本出错了还是会重新运行脚本&#xff0c;运行自动启动&#xff0c;end暂停脚本&#xff0c;home重新启动脚本 1. 我常用的是内挂回点脚本&#xff0c; 下面都是前台脚本&…

数据结构与算法学习笔记六-二叉树的顺序存储表示法和实现(C语言)

目录 前言 1.数组和结构体相关的一些知识 1.数组 2.结构体数组 3.递归遍历数组 2.二叉树的顺序存储表示法和实现 1.定义 2.初始化 3.先序遍历二叉树 4.中序遍历二叉树 5.后序遍历二叉树 6.完整代码 前言 二叉树的非递归的表示和实现。 1.数组和结构体相关的一些知…

【React】React-redux多组件间的状态传递

效果&#xff08;部分完整代码在最底部&#xff09;&#xff1a; 编写 Person 组件 上面的 Count 组件&#xff0c;已经在前面几篇写过了&#xff0c;也可以直接翻到最底部看 首先我们需要在 containers 文件夹下编写 Person 组件的容器组件 首先我们需要编写 index.jsx 文件…

基于VOLOPV2的自动驾驶环境感知系统

基于VOLOPV2的自动驾驶环境感知系统是一个复杂的系统&#xff0c;它主要负责实时检测并识别周围环境中的各种物体和信息&#xff0c;为自动驾驶车辆提供必要的感知数据。以下是对该系统的一个简要介绍&#xff1a; 环境感知是自动驾驶系统中的一个关键部分&#xff0c;它依赖于…

AI代理和AgentOps生态系统的剖析

1、AI代理的构成&#xff1a;AI代理能够根据用户的一般性指令自行做出决策和采取行动。 主要包含四个部分&#xff1a; &#xff08;1&#xff09;大模型&#xff08;LLM&#xff09; &#xff08;2&#xff09;工具&#xff1a;如网络搜索、代码执行等 &#xff08;3&#x…

C++学习第二十九课:C++ 输入输出流详解:从基础到高级应用

在 C 中&#xff0c;流&#xff08;stream&#xff09;是一种用于实现输入输出操作的抽象概念。流可以看作是字节的流动&#xff0c;这些字节可以从一个地方流向另一个地方&#xff0c;例如从键盘输入到程序中&#xff0c;或者从程序输出到屏幕。C 提供了一套完整的流库来处理各…