使用 OpenCV 创建视频(74)

 返回:OpenCV系列文章目录(持续更新中......)
上一篇:OpenCV 库来捕获和处理视频输入和相似度测量(73)
下一篇 :OpenCV系列文章目录(持续更新中......)

目标

每当您使用视频源时,您最终可能希望将图像处理结果保存为新视频文件的形式。对于简单的视频输出,您可以使用专为此设计的 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 write
 
using 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 name
 const bool askOutputType = argv[3][0] =='Y'; // If false it will use the inputs codec type
 
 VideoCapture inputVideo(source); // Open input
 if (!inputVideo.isOpened())
 {
 cout << "Could not open the input video: " << source << endl;
 return -1;
 }
 
 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
 int ex = static_cast<int>(inputVideo.get(CAP_PROP_FOURCC)); // Get Codec Type- Int form
 
 // Transform from int to char via Bitwise operators
 char 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 output
 if (askOutputType)
 outputVideo.open(NAME, ex=-1, inputVideo.get(CAP_PROP_FPS), S, true);
 else
 outputVideo.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 save
 switch(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; // read
 if (src.empty()) break; // check if at end
 
 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);
 
 //outputVideo.write(res); //save or
 outputVideo << 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.mfbz.cn/a/601019.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【go从入门到精通】go命令使用

作者简介: 高科,先后在 IBM PlatformComputing从事网格计算,淘米网,网易从事游戏服务器开发,拥有丰富的C++,go等语言开发经验,mysql,mongo,redis等数据库,设计模式和网络库开发经验,对战棋类,回合制,moba类页游,手游有丰富的架构设计和开发经验。 (谢谢…

矩阵相关运算1

矩阵运算是线性代数中的一个核心部分&#xff0c;它包含了许多不同类型的操作&#xff0c;可以应用于各种科学和工程问题中。 矩阵加法和减法 矩阵加法和减法需要两个矩阵具有相同的维度。操作是逐元素进行的&#xff1a; CAB or CA−B其中 A,B 和 C 是矩阵&#xff0c;且 C…

第12章 软件测试基础(第三部分)测试类型、测试工具

七、测试类型&#xff08;按工程阶段划分&#xff09; 单集系确收 &#xff08;一&#xff09;单元测试 1、单元测试/模块测试 单元就是软件中最小单位&#xff08;或模块&#xff09;。可以是一个函数、一个过程、一个类。主要依据是模块的详细设计文档。价值在于尽早发现…

2024年全域电商矩阵109节线上课

《24年全域电商矩阵109节线上课》是一门全面介绍电子商务领域的课程。从电子商务的基本概念到全球电子商务趋势&#xff0c;再到电子商务的营销策略和实际操作技巧&#xff0c;本课程涵盖了丰富多样的主题。学员将通过109节在线课程系统全面了解电子商务&#xff0c;并获得在这…

如何安全可控地进行内外网跨网络传输文件?

跨网络传输文件通常指的是在不同的网络环境之间移动数据&#xff0c;这在现代企业运营中非常常见。随着网络技术的高速发展&#xff0c;为了有效地保护内部的核心数据资产&#xff0c;企业一般会采用内外网隔离的策略。在进行内外网跨网络传输文件时&#xff0c;需要考虑多种因…

全国各地区劳动力流动、外出务工劳动力数、总劳动力数(2006-2021年)

01、数据简介 劳动力流动是指劳动力在不同地区、行业、职业、岗位之间的流动。它是劳动力市场运行的重要特征&#xff0c;也是实现劳动力资源优化配置的必要条件。劳动力流动可以促进劳动力资源的优化配置&#xff0c;提高劳动生产率和经济效益。据名称&#xff1a;全国各地区…

初始C++(一)

目录 前言&#xff1a; 命名空间&#xff1a; 总结&#xff1a; 前言&#xff1a; C语言学好了&#xff0c;现在当然要进阶了&#xff0c;那么就是从C开始。 C兼容C&#xff0c;支持其中90%的语法。可能有很多同学听说过C#&#xff0c;C#和C没有关系&#xff0c;是微软研究出…

SD-WAN对云服务的优化

在云服务日益普及的当下&#xff0c;SD-WAN技术正成为众多企业优化网络连接的首选方案。其通过优化云集成和连接&#xff0c;以及增强应用程序性能&#xff0c;为企业带来了前所未有的业务效益。这种革新性的云连接方式极大地促进了企业对全球劳动力和潜在客户的触达能力。 软件…

Java中Maven的依赖管理

依赖介绍 是指当前项目运行所需要的jar包&#xff0c;一个项目中可以引入多个依赖 配置 在pom.xml中编写<dependencies>标签 在<dependencies>中使用<dependency>引入标签 定义坐标的groupId、rtifactId、version 点击刷新按钮、引入新坐标 例如引入下…

git bash各分支修改内容不同但合并后不显示冲突问题

在跟着廖雪峰老师的git学习时&#xff0c;按部就班的执行明后&#xff0c;发现 而不是出现原文的结果 解决方法&#xff1a; 切换位feature分支&#xff0c;再合并 git switch feature1 git merge master 此时我们发现&#xff1a; 后面再跟着原文敲就可以了

【spark RDD】spark 之 Kryo高性能序列化框架

文章目录 一. RDD序列化的原因二. Kryo序列化框架三. spark 配置 kryo 序列化1. 设定kryo序列化2. 注册序列化类&#xff08;非必须&#xff0c;但是强烈建议做&#xff09;3. 配置 spark.kryoserializer.buffer 一. RDD序列化的原因 Spark初始化工作是在Driver端进行的&#…

机器人系统ros2-开发实践07-将机器人的状态广播到 tf2(Python)

上个教程将静态坐标系广播到 tf2&#xff0c;基于这个基础原理这个教程将演示机器人的点位状态发布到tf2 1. 写入广播节点 我们首先创建源文件。转到learning_tf2_py我们在上一教程中创建的包。在src/learning_tf2_py/learning_tf2_py目录中输入以下命令来下载示例广播示例代码…

【机器学习与实现】线性回归示例——波士顿房价分析

目录 一、创建Pandas对象并查看数据的基本情况二、使用皮尔逊相关系数分析特征之间的相关性三、可视化不同特征与因变量MEDV&#xff08;房价中值&#xff09;间的相关性四、划分训练集和测试集并进行回归分析 一、创建Pandas对象并查看数据的基本情况 boston.csv数据集下载&a…

Grotesque系列靶机Grotesque1

第一步信息收集&#xff1a; 靶机ip&#xff1a;192.168.108.131 攻击机IP&#xff1a;192.168.108.128 nmap扫描靶机的可用端口&#xff1a; 发现http服务的端口存在66端口和80端口 扫描一下靶机端口的http服务&#xff1a; 可以看到&#xff0c;默认的80端口是不存在的&am…

25_Scala集合Tuple

文章目录 tuple1.元组定义2.Tuple元素访问3.如果元素的len2&#xff0c;称之为键值对对象&#xff0c;也称之为对偶元组4.补充上节Map5.Map集合遍历6.集合之间相互转化 tuple 概念&#xff1a;scala语言采用特殊的方式将无关的数据作为一个整体&#xff0c;组合在一起’ 1.元…

【Git】Git学习-13:Gitee和GitLab的使用

学习视频链接&#xff1a;【GeekHour】一小时Git教程_哔哩哔哩_bilibili​编辑https://www.bilibili.com/video/BV1HM411377j/?vd_source95dda35ac10d1ae6785cc7006f365780 流程 1. 创建仓库/已有仓库 2. 克隆到本地/在远程仓库关联 git clone 仓库地址 git remote add 仓库别…

小语言模型的潜力

想象一下这样一个世界&#xff1a;智能助手不在云端&#xff0c;而是在你的手机上&#xff0c;无缝了解你的需求并以闪电般的速度做出响应。这不是科幻小说&#xff0c;而是科幻小说。这是小语​​言模型 (SLM) 的希望&#xff0c;这是一个快速发展的领域&#xff0c;有可能改变…

聪明与诚实:社会信任的桥梁

在现代社会中&#xff0c;我们经常听到这样的评价&#xff1a;“某人真聪明。”然而&#xff0c;当我们深入思考时&#xff0c;会发现“聪明”这个词背后所承载的含义并不单一。聪明和狡诈往往被混淆&#xff0c;而诚实的价值却时常被忽视。在一个高度诚信的社会里&#xff0c;…

CentOS 自建gitlab仓库:安装相关工具

所需环境 Node 安装项目依赖、项目打包运行Nginx 前端项目部署&#xff08;正向代理、反向代理、负载均衡等&#xff09;Git 自动化部署时 拉取代码使用GitLab 代码仓库GitLab-Runner GitLab的CI/CD执行器 一、安装Node 检测是否已安装 常用node -v 命令检测。 如果已安装&a…

【挑战30天首通《谷粒商城》】-【第一天】03、简介-分布式基础概念

文章目录 课程介绍 ( 本章了解即可&#xff0c;可以略过)1、微服务简而言之: 2、集群&分布式&节点2.1、定义2.2、示例 3、远程调用4、负载均衡常见的负裁均衡算法: 5、服务注册/发现&注册中心6、配置中心7、服务熔断&服务降级7.1、服务熔断7.2、服务降级 8、AP…
最新文章