使用 OpenCV 创建视频(74)

news2024/11/26 18:36:53
 返回: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.coloradmin.cn/o/1650871.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HDLC协议

目录 1.概念 2.配置 3.HDLC帧结构 4.HDLC帧类型 1.概念 HDLC(High-level Data Link Control&#xff09;高级数据链路控制位于链路层协议&#xff0c;传输单位是帧&#xff0c;它是一组用于在网络结点间传送数据的协议。其特点是各项数据和控制信息都以比特为单位&#xff…

C/C++程序设计实验报告综合作业 | 小小计算器

本文整理自博主本科大一《C/C程序设计》专业课的课内实验报告&#xff0c;适合C语言初学者们学习、练习。 编译器&#xff1a;gcc 10.3.0 ---- 注&#xff1a; 1.虽然课程名为C程序设计&#xff0c;但实际上当时校内该课的内容大部分其实都是C语言&#xff0c;C的元素最多可能只…

2024年第九届数维杯数学建模B题思路分享

文章目录 1 赛题思路2 比赛日期和时间3 竞赛信息4 建模常见问题类型4.1 分类问题4.2 优化问题4.3 预测问题4.4 评价问题 5 建模资料 1 赛题思路 (赛题出来以后第一时间在CSDN分享) https://blog.csdn.net/dc_sinor?typeblog 2 比赛日期和时间 报名截止时间&#xff1a;2024…

六级段落匹配

一个段落最多匹配2个句子 一个段落对应&#xff1a;0-2 适当放题 找到三个对应点就可以选 每看三个句子划关键词之后再自己回忆一遍关键词&#xff0c;看了36 37 38 就复述一遍关键词看了39 40 41就又从36开始复述关键词&#xff08;334&#xff09;看到最后一句话就又从头…

测试平台开发:Django开发实战之注册界面实现(下)

1、 评论和用户建立关联 1&#xff09;修改model: 软关联还是硬关联默认值是什么关联方被删除怎么办如何根据评论找到用户如何根据用户找到评论 然后执行命令&#xff1a; pdm run M pdm run init 这样在表里面就会多一个user_id的字段 2&#xff09;修改视图&#xf…

电脑提示mfc140u.dll文件丢失了?怎么快速修复mfc140u.dll文件

当你的电脑提示你的mfc140u.dll文件丢失了&#xff0c;那么就要小心了&#xff0c;可能你的某些程序出问题了&#xff01;这时候需要我们去进行相关的修复&#xff0c;只有修复了这个mfc140u.dll文件&#xff0c;才能正常的使用某些程序。下面一起来了解一下mfc140u.dll文件吧。…

Deeplab的复现(pytorch实现)

DeepLab复现的pytorch实现 本文复现的主要是deeplabv3。使用的数据集和之前发的文章FCN一样&#xff0c;没有了解的可以移步到之前发的文章中去查看一下。 1.该模型的主要结构 对于代码部分&#xff0c;主要只写了模型部分的&#xff0c;其他部分内容基本和FCN的一致&#xf…

笔试强训Day18 字符串 排序 动态规划

[编程题]压缩字符串(一) 题目链接&#xff1a;压缩字符串(一)__牛客网 (nowcoder.com) 思路&#xff1a; 跟着思路写就完了。 AC code&#xff1a; #include <iostream> #include<string> using namespace std; string a; string ans; int main() {cin >>…

【Java基础】Maven继承

1. 前言 Maven 在设计时&#xff0c;借鉴了 Java 面向对象中的继承思想&#xff0c;提出了 POM 继承思想。 2. Maven继承 当一个项目包含多个模块时&#xff0c;可以在该项目中再创建一个父模块&#xff0c;并在其 POM 中声明依赖&#xff0c;其他模块的 POM 可通过继承父模…

DMAR: [INTR-REMAP] Present field in the IRTE entry is clear 的解决办法

问题描述 在使用FPGA开发PCIe的MSI-X中断相关功能时&#xff0c;一次测试过程中dmesg打印出如下错误&#xff0c;使用cat /proc/interrupts查看FPGA的PCIe驱动程序未收到MSIX中断。使用的系统为基于Intel x86_64的linux&#xff08;RHEL8.9&#xff09;&#xff0c;基于Xilinx …

回归分析的理解

1.是什么&#xff1a; 2.回归问题的求解&#xff1a; 首先是根据之前的数据确定变量和因变量的关系根据关系去预测目标数据根据结果做出判断 2.1如何找到关系&#xff1f; y’是根据模型生成的预测结果&#xff1a; y’axb&#xff0c;而我们的目的是y’和y(正确的结果)之间…

微信小程序相对于H5和原生APP有哪些优势?开发小程序的步骤是什么?

微信小程序是什么&#xff1f; 小程序是小型、轻量级的原生移动应用&#xff0c;你可以使用它们来订餐、预约出租车或支付账单。它们建立在微信平台上&#xff0c;可以通过微信的“小程序”目录进行访问。 与普通应用不同&#xff0c;小程序不需要安装。你可以直接打开并使用…

Ansible --- playbook 脚本+inventory 主机清单

一 inventory 主机清单 Inventory支持对主机进行分组&#xff0c;每个组内可以定义多个主机&#xff0c;每个主机都可以定义在任何一个或 多个主机组内。 如果是名称类似的主机&#xff0c;可以使用列表的方式标识各个主机。vim /etc/ansible/hosts[webservers]192.168.10.1…

js 图片渐变

1. 点击图片&#xff0c;使其渐变为另一张图片 通过定义keyframes来创建一个淡入淡出的动画效果。当图片被点击时&#xff0c;先添加淡出动画使图片透明度从0渐变到1&#xff0c;然后在1秒后切换图片源并添加淡入动画使新图片透明度从0渐变到1&#xff0c;实现图片渐变效果。 …

Hive Views 视图

Hive Views 视图 在Hive中&#xff0c;视图&#xff08;Views&#xff09;是虚拟表&#xff0c;它只包含查询定义&#xff0c;而不包含实际的数据。视图可以简化复杂查询&#xff0c;隐藏数据结构&#xff0c;提供安全性&#xff0c;以及促进数据访问和重用。 创建视图的语法如…

推荐网站(5)Pika文字生成视频,ai视频创作

今天推荐一个网站&#xff0c;Pika文字生成视频&#xff0c;通过问题描述&#xff0c;帮我们生成对应的视频&#xff0c;非常的实用。 比如输入&#xff1a;一只小狗在河边洗澡 当然我们还可以在生成的视频上编辑 点击编辑后出来一些属性&#xff0c;可以修改区域&#xff0c…

MyBatis入门例子

1、建立与数据库对应的POJO类 2、建立mybatis的配置文件 修改后如下&#xff1a; 3、创建POJO对象和Mysql数据的表之间的映射配置 4、建一个测试方法 实现从数据库中取数一条数据&#xff0c;封装成User对象返回 注意点&#xff1a; 这点&#xff0c;大家应该不陌生了&#x…

2024最新行业领域名词解释大全

2024最新行业领域名词解释大全 &#x1f680; 大家好&#xff01;我是你们的老朋友猫头虎&#x1f42f;。今天要为大家带来2024年最新的行业领域名词解释大全&#xff01;在这个信息爆炸的时代&#xff0c;准确了解不同领域的行业动态、工作机会和职业前景至关重要。下面我会分…

Java -- (part22)

一.缓冲流 字节缓冲流 BufferedOutputStream 1.构造 BufferedOutputStream(OutputStream out) 2.用法 和FileOutputStream一样 BufferedInputStream 1.构造 BufferedInputStream(InputStream in) 2.用法 和FileInputStream一样 字符缓冲流 BufferedWriter 1.构造…

Pytorch 实现情感分析

情感分析 情感分析是 NLP 一种应用场景&#xff0c;模型判断输入语句是积极的还是消极的&#xff0c;实际应用适用于评论、客服等多场景。情感分析通过 transformer 架构中的 encoder 层再加上情感分类层进行实现。 安装依赖 需要安装 Poytorch NLP 相关依赖 pip install t…