为什么opencv videowriter这么慢?

2024-06-19

你好 stackoverflow 社区, 我有一个棘手的问题,我需要你的帮助来了解这里发生了什么。 我的程序从视频采集卡(Blackmagic)捕获帧,到目前为止,它工作得很好,同时我用 opencv (cv::imshow)显示捕获的图像,它也工作得很好(但相当浪费CPU)。 捕获的图像也应该存储在磁盘上,为此我将捕获的帧(cv::Mat)放在堆栈上,最后将它们与 opencv 异步写入:

cv::VideoWriter videoWriter(path, cv::CAP_FFMPEG, fourcc, fps, *size);
videoWriter.set(cv::VIDEOWRITER_PROP_QUALITY, 100);

int id = metaDataWriter.insertNow(path);

while (this->isRunning) {

    while (!this->stackFrames.empty()) {

        cv:Mat m = this->stackFrames.pop();

        videoWriter << m;
    }
    
}

videoWriter.release();

该代码正在另一个线程中运行,将从外部停止。 到目前为止,代码可以正常工作,但有时速度相当慢,这意味着我的堆栈大小增加,我的系统耗尽内存并被操作系统杀死。

目前它正在我的开发系统上运行:

  • Ubuntu 18.04.05
  • OpenCV 4.4.0用Cuda编译
  • 英特尔 i7 10. 代 32GB RAM、GPU Nvidia p620、M.2 SSD

根据编解码器 (fourcc),这会产生较高的 CPU 负载。到目前为止我主要使用“MJPG”、“x264”。有时,甚至 MJPG 也会将 CPU 的一个核心调至 100% 负载,并且我的堆栈会一直升高,直到程序运行完毕。有时,重新启动后,此问题会得到解决,并且负载似乎分布在所有核心上。

关于英特尔文档。对于我的 CPU,它集成了多个编解码器的硬件编码/解码。但我猜 opencv 没有使用它们。 Opencv 甚至使用它自己的 ffmpeg,而不是我的系统。这是我的 opencv 构建命令:

cmake -D CMAKE_BUILD_TYPE=RELEASE \
-D CMAKE_INSTALL_PREFIX=/usr/local \
-D WITH_TBB=ON \
-D WITH_CUDA=ON \
-D BUILD_opencv_cudacodec=OFF \
-D ENABLE_FAST_MATH=1 \
-D CUDA_FAST_MATH=1 \
-D WITH_CUBLAS=1 \
-D WITH_V4L=ON \
-D WITH_QT=OFF \
-D WITH_OPENGL=ON \
-D WITH_GSTREAMER=ON \
-D OPENCV_GENERATE_PKGCONFIG=ON \
-D OPENCV_ENABLE_NONFREE=ON \
-D WITH_FFMPEG=1 \
-D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib/modules \
-D WITH_CUDNN=ON \
-D OPENCV_DNN_CUDA=ON \
-D CUDA_ARCH_BIN=6.1 ..

我刚刚开始使用 linux 和 C++ 进行开发,然后才开始使用 Java/Maven,所以 cmake 的使用仍然是一个正在进行的工作,请放轻松。

基本上我的问题是,如何使视频编码/写入更快,最好使用硬件加速? 或者,如果您认为还有其他可疑之处,请告诉我。

迈克尔·BR


-------- 旧 - 查找底部的答案 --------

感谢@Micka 的很多建议,我在路上找到了正确的东西。

使用 cudacodec::VideoWriter 并不那么容易,编译后我无法使用它,因为这个error https://answers.opencv.org/question/187243/opencv-error-the-functionfeature-is-not-implemented/,即使我可以让它运行,部署 PC 也没有 nvidia GPU。

由于我也将使用配备 AMD CPU 的 PC,因此我无法使用 cv::CAP_INTEL_MFX 作为 cv::VideoWriter 的 api-reference 参数。 但还有 cv::CAP_OPENCV_MJPEG,它适用于 MJPG 编解码器(并非所有视频容器都受支持,我使用 .avi,遗憾的是 .mkv 不适用于此配置)。如果用户不使用 MJPG 作为编解码器,我使用 cv::CAP_ANY,然后 opencv 决定使用什么。

So,

cv::VideoWriter videoWriter(path, cv::CAP_OPENCV_MJPEG, fourcc, fps, *size);

即使在我的旧系统上也运行得很好。

不幸的是我之前从未更改过 api-reference 参数,只是从 ffmpeg 更改为 gstreamer,我在opencv的文档 https://docs.opencv.org/3.4/dd/d9e/classcv_1_1VideoWriter.html#af52d129e2430c0287654e7d24e3bbcdc仅最后一行“cv::CAP_FFMPEG 或 cv::CAP_GSTREAMER”。我没有看到有一个“例如”。前... 谢谢@Micka 让我再次阅读。

附:对于我的 cv::imshow 性能问题,我从

cv::namedWindow(WINDOW_NAME, cv::WINDOW_NORMAL);

to

cv::namedWindow(WINDOW_NAME, cv::WINDOW_OPENGL);

显然它使用了 OpenGL,并且做得更好。另外从 cv::Mat 更改为 cv::UMat 可以加快性能,see here https://stackoverflow.com/questions/62243373/too-high-cpu-footprint-of-opencv-text-overlay-on-fhd-video-stream

-------------- 编辑更好的解决方案----------------

由于我在某些系统上使用 OpenCV VideoWriter 时仍然遇到问题,因此我一直在寻找另一种解决方案。现在我用 FFMPEG 编写帧。 对于 FFMPEG,我可以根据我使用的编解码器使用 GPU 或 CPU。 如果 FFMPEG 通过 snapd (Ubuntu 18.04) 安装,则默认启用 cuda:

sudo snap install ffmpeg --devmode

(--devmode 是可选的,但我在特定位置写入文件时遇到问题,这是我修复它的唯一方法)

这是我的代码:

//this string is automatically created in my program, depending on user input and the parameters of the input frames

string ffmpegCommand = "ffmpeg -y -f rawvideo -vcodec rawvideo -framerate 50 -pix_fmt bgr24 -s 1920x1080 -i - -c:v h264_nvenc -crf 14 -maxrate:v 10M -r 50 myVideoFile.mkv";

FILE *pipeout = popen(ffmpegCommand.data(), "w");

int id = metaDataWriter.insertNow(path);

//loop will be stopped from another thread
while (this->isRunning) {
    //this->frames is a stack with cv::Mat elements in the right order
    //it is filled by another thread
    while (!this->frames.empty()) {


        cv::Mat mat = frames.front();
        frames.pop();
        fwrite(mat.data, 1, s, pipeout);

    }  
}

fflush(pipeout);
pclose(pipeout);

因此使用文件(pipeout)将mat.data写入ffmpeg,ffmpeg本身正在进行编码和文件写入。至参数:

-y = 不询问就覆盖输出文件

-f = 格式,在本例中用于输入原始视频

-vcodec = 输入的编解码器也是原始视频,因为使用的 cv::Mat.data 没有压缩/编解码器

-framerate = 我从采集卡/OpenCv 收到的输入帧率

-pix_fmt = 我的原始数据的格式,在本例中为 bgr24,因此每个通道 8 位,因为我使用常规 OpenCV bgr cv::Mat

-s = 每帧的大小,在我的例子中为 1920x1080

-i = 输入,在这种情况下,我们从 stdinput 读取,您可以在这里看到它“-”,因此文件(管道输出)被 ffmpeg 捕获

-c:v = 输出编解码器,所以这是对视频进行编码,这里使用了h264_nvenc,这是一个GPU编解码器

-r = 帧输出速率,在本例中也是 50 myVideoFile.mkv = 这只是 ffmpeg 生成的文件的名称,您可以更改此文件和路径

更高质量的附加参数:-crf 14 -maxrate:v 10M

这对我来说非常有用,并且使用我的 GPU 硬件加速或与负责 CPU 的另一个编解码器一起使用。 我希望这也能帮助其他开发人员。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么opencv videowriter这么慢? 的相关文章

  • 嵌套绑定表达式

    这是一个后续问题我之前的问题 https stackoverflow com questions 2735294 templates function pointers and c0x include
  • 如何防止函数中的隐式转换?

    我正在编写一个实用程序类 其中包含 IsEquals 和 IsGreaterThanEquals 等接受 double 类型参数的方法 当我将浮点值发送到方法时 它们会隐式转换为双精度值并进行比较 我不希望这种事发生 当我发送 float
  • Linq Any 始终返回 true

    我已经使用 Linq to Entities 多年 但这是我第一次遇到这个问题 我有Tips and Items表 每个提示可以有很多项目 我的数据库中只有 3 个项目 编辑项目时 我想确保GivenId对于具有相同提示的项目 字段是唯一的
  • 改装和授权标头

    目前 我正在向我的请求添加授权标头 如下所示 文件 SomeFile cs public interface ITestApi Get api test id Task
  • 预期在模拟中调用一次,但使用 Moq 时调用次数为 0 次

    我收到错误 在mock上调用一次 但是0次 下面是我的代码结构 public class GenerateAddress IGenerateAddress public GenerateAddress IAddress createAdd
  • 如何更改控制台中的光标位置?

    我想用Console ReadLine 在上一行中并使其显示如下 HeresomeText gt input Not like HeresomeText gt input 可以做吗 使用 Write 方法而不是 WriteLine 方法 C
  • 文件已创建但无法写入

    我的计划 检查Settings txt 文件 如果该文件不存在 则创建文本并自动写入其中 如果 Settings txt 文件已存在 请忽略 不要创建或写入现有文件 我的问题 当文件不存在时 Settings txt 文件会创建 但它是空的
  • C++ 访问嵌套类的私有成员

    标题可能有点误导 我有以下问题 我有一棵由叶子和内部节点组成的树 用户应该能够在叶子中存储任何信息and该树有一些方法可以获取一组用户定义的值 并且需要在恒定时间内 未摊销 访问相应的叶子 我提出了以下想法 但它不起作用 因为不幸的是我无法
  • 对指针列表进行排序

    我再次发现自己在 C 中的一些非常简单的任务上失败了 有时我希望我能从 Java 中的 OO 中学到所有知识 因为我的问题通常是从像 Java 一样思考开始的 无论如何 我有一个std list
  • 使用 MemoryCache 而不是普通的旧 Dictionary 的令人信服的理由是什么

    我刚刚遇到内存缓存 http msdn microsoft com en us library system runtime caching memorycache aspx这是 NET 4 中的新增功能 我知道如果你想的话它会很有用 限制
  • 在 Visual Studio 2017 mac 上安装扩展 [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我正在尝试在 Visual Studio for Mac 上安装 Visual Studio Marketplace 扩展 但是 Vi
  • 使用 C# 在 XML 文档中查找特定值的好方法是什么?

    我正在调用 Oracle 公开的 WebService 它接受 ItemID 的输入并向我返回相应的 Item Number 我想获取从响应中包含的 XML 返回的项目编号 XML 看起来像这样
  • 在多个线程中添加和删除时 List 中的 null 值

    我知道 C System Collections Generic List 对象不是线程安全的 但我想知道为什么这段代码会生成空值 Task Run gt for var i 0 i lt 10 i var str Test i list
  • WiX 安装程序在 vs 2012 上不起作用

    我想为我的应用程序创建一个安装程序 我已经下载了 WiX 3 6 并将其安装在 vs 2012 上 创建简单的winform应用程序 将 WiX 安装项目添加到我的解决方案中 右键单击参考并将我的 winform 应用程序添加到安装程序的参
  • boost::bind 会导致开销吗?

    我目前正在从事网络软件方面的工作 它有一个主要类 server这显然代表一个服务器实例 A server实例可以发送请求 并通过回调通知用户响应 代码如下 class server public typedef boost function
  • 获取上下文菜单的控制

    我有一个如下所示的上下文菜单 A 1 2 3 选择 1 2 或 3 后 我需要访问调用上下文菜单的对象 意思是如果这是 textbox1 的上下文菜单 那么我需要访问该对象 我该怎么做 忘了说了 这是一个WPF应用程序 所以我使用 Syst
  • 成员函数的Decltype

    class A int f int x int j return 2 decltype f p 给我错误 error decltype cannot resolve address of overloaded function 我不明白为什
  • 如何在mvc视图中的表中显示数据库数据

    在我的 MVC 应用程序中 我从数据库检索数据 我想在表格中显示退役数据 控制器代码 public ActionResult MyAccount var user User Identity Name string sThumbnails
  • 如何在迭代时从地图中删除?

    迭代时如何从地图中删除 喜欢 std map
  • Interlocked.CompareExchange 可以抛出 NullReferenceException 吗?

    From https msdn microsoft com en us library bb297966 v vs 110 aspx https msdn microsoft com en us library bb297966 v vs

随机推荐

  • MySQL 排序顺序 - 排序规则?

    我在对 MySQL 中的 char 字段进行排序时遇到困难 问题是重音字符与非重音字符混淆 例如 Abc bd Acc 我认为这可能与整理有关 所以我将表格的排序规则更改为utf8 ut8 bin 看完之后这个帖子 https stacko
  • 我可以用关闭的文件对象做什么?

    当您打开文件时 它存储在一个打开的文件对象中 该对象使您可以访问该文件的各种方法 例如读取或写入 gt gt gt f open file0 gt gt gt f
  • Emacs htmlize 在批处理模式下?

    我喜欢在 emacs 中使用 htmlize file 将 clojure 源文件转换为 html 我想从 linux 命令行使用它 或者从 clojure 本身以编程方式使用它 I tried emacs eval htmlize fil
  • VS Code 在交互式变基期间不会等待我 [重复]

    这个问题在这里已经有答案了 如果我使用交互式变基git rebase i使用为 Git 配置的默认编辑器 一切都运行良好 如果我在我的全局中添加以下内容 gitconfig core editor C Program Files x86 M
  • 在 Haskell 中创建 100 万个线程需要多长时间?

    据我了解 Haskell 有绿色线程 但它们的重量有多轻 是否可以创建100万个线程 或者 100 000 个线程需要多长时间 from here http www reddit com r programming comments a4n
  • 在 Marshmallow 中获取蓝牙本地 mac 地址

    在 Marshmallow 之前 我的应用程序将通过以下方式获取其设备 MAC 地址BluetoothAdapter getDefaultAdapter getAddress 现在 随着 Marshmallow Android 的回归02
  • 更快的算法来计算有多少数字可以被范围内的特定整数整除

    int a b c d 0 cin gt gt a gt gt b gt gt c for int i a i lt b i if i c 0 d cout lt
  • Flutter - 选择 TextFormField 时键盘不显示

    我目前遇到一个问题 当我选择任何一个时 键盘不会出现TextFormFielda 内的小部件Form小部件 这是表单的代码 位于我的内部CreateAccountForm有状态的小部件 import package flutter mate
  • 必须打开存储才能执行此操作 - System.IO.Packaging.Package

    我正在使用 System IO Packaing Package 类来压缩文件 我的应用程序的多个实例可以同时运行 并读取和保存文件 当处理小文件时 一切似乎都很好 但是当涉及大文件时 如果应用程序的两个实例同时保存 我会收到一个异常 消息
  • 为什么在尝试编译此代码时会收到错误“错误:未知类型名称'虚拟'”?

    Code struct IRenderingEngine virtual void Initialize int width int height 0 virtual void Render const 0 virtual void Upd
  • 在 Visual Studio 中继承构建后事件?

    我在 Visual Studio 中有一个解决方案 其中有一个共享属性表 其中包含构建后事件命令 bar 需要为每个项目执行 Foo props gt 通用属性 gt 构建事件 gt 构建后事件 gt 命令行 栏 然后 我如何指定其他特定于
  • jquery ajax调用一个接一个循环而不停止页面渲染

    我有一个超过 100 行的表 每行包含 pdf 文件及其说明以及最后一列状态 状态显示 pdf 文件是否可读 一旦表格加载到浏览器中 我就会从表格的每一行获取每个文件名 并使用 ajax 调用对其进行处理 如果文件可读 我将该行的状态字段更
  • 带有 Play 框架的 cassandra

    我正在尝试开发一个由两部分组成的应用程序 Web 服务和 Android 应用程序 我计划使用 java play 框架和 cassandra noSQL 数据库来实现我的 Web 服务 我已经找了两天了 我还是不知道该怎么做 我需要集成一
  • 如何使用 Spring Boot 和 Flyway 设置 Quartz 调度程序的数据库架构?

    我有一个 Spring Boot 应用程序 它使用 Quartz 调度程序和 PostGreSQL 数据库作为存储 我正在将它从使用它自己的数据库运行迁移到publicschema 来针对每个应用程序使用一个 schema 的共享数据库运行
  • 如何在 MySQL 中测试 Select for Update

    我正在表演SELECT FOR UPDATE或 InnoDB 表的行级锁定 我的目的是只有一个请求可以读取同一行 因此 如果两个用户同时请求相同的数据 其中只有一个人获取数据 即第一个触发查询的人 但是我如何测试锁定是否已放置 因为我正在通
  • RSpec 2 中使用 OR 相等

    下面这个例子的正确写法是什么 玩家的分数应等于 5 或 8 it should equal 5 or 8 do player score should 5 or 8 end Thanks Tim 5 or 8将始终产生结果 5 并且不会执行
  • 输入连接-如何删除选定的文本?

    我为 Android 制作了一个自定义键盘 当我按下键盘的退格按钮时 我使用 getCurrentInputConnection deleteSurroundingText 1 0 从输入字段中删除一个字母 但是 当我选择一些文本然后按退格
  • SetWindowsHookEx 函数返回 NULL

    我正在研究 DLL 注入 但收到错误如下 挂接进程失败 87 参数不正确 目标进程和dll都是64位的 注入代码为 BOOL HookInjection TCHAR target TCHAR dll name https msdn micr
  • C修改printf()输出到文件

    有没有办法修改printf为了将字符串输出到文件而不是控制台 我尝试在互联网上查找一些内容 发现了类似的电话dup dup2 and fflush这可能与此有关 EDIT 也许我不清楚 问题是这是C考试问题 问题如下 解释一个通常将字符串输
  • 为什么opencv videowriter这么慢?

    你好 stackoverflow 社区 我有一个棘手的问题 我需要你的帮助来了解这里发生了什么 我的程序从视频采集卡 Blackmagic 捕获帧 到目前为止 它工作得很好 同时我用 opencv cv imshow 显示捕获的图像 它也工