FHD 视频流上 OpenCV 文本覆盖的 CPU 占用太高
Posted
技术标签:
【中文标题】FHD 视频流上 OpenCV 文本覆盖的 CPU 占用太高【英文标题】:Too High CPU Footprint of OpenCV Text Overlay on FHD Video Stream 【发布时间】:2020-06-07 09:26:16 【问题描述】:我想显示 FHD 实时流 (25 fps) 并覆盖一些(变化的)文本。为此,我基本上使用下面的代码。
基本上是这样
-
加载框架
(
cv::putText
此处略过)
如果它是delay
的倍数,则显示框架
但与例如代码相比,代码超级慢。 mpv
并消耗大量 CPU 时间 (cv::useOptimized() == true
)。
到目前为止,delay
是我不方便的小提琴参数,以某种方式使其可行。
delay == 1
导致 180 % CPU 使用率(全帧率)
delay == 5
导致 80 % 的 CPU 使用率
但是delay == 5
或 5 fps 确实很慢,实际上仍然过多的 cpu 负载。
我怎样才能使这段代码更快或更好或以其他方式解决任务(我不绑定到 opencv)?
P.s. 没有cv::imshow
,无论delay
如何,CPU 使用率都低于 30%。
#include <opencv2/opencv.hpp>
#include <X11/Xlib.h>
// process ever delayth frame
#define delay 5
Display* disp = XOpenDisplay(NULL);
Screen* scrn = DefaultScreenOfDisplay(disp);
int screen_height = scrn->height;
int screen_width = scrn->width;
int main(int argc, char** argv)
cv::VideoCapture cap("rtsp://url");
cv::Mat frame;
if (cap.isOpened())
cap.read(frame);
cv::namedWindow( "PREVIEW", cv::WINDOW_NORMAL );
cv::resizeWindow( "PREVIEW", screen_width, screen_height );
int framecounter = 0;
while (true)
if (cap.isOpened())
cap.read(frame);
framecounter += 1;
// Display only delay'th frame
if (framecounter % delay == 0)
/*
* cv::putText
*/
framecounter = 0;
cv::imshow("PREVIEW", frame);
cv::waitKey(1);
【问题讨论】:
您是在编译代码时启用优化(也称为“发布版本”)还是在测试未优化的版本? Here 是cv::getBuildInformation()
对opencv
本身的完整输出。对于这段代码,除了-O3
,我没有指定任何内容。
在没有激活 putText 的情况下使用多少 cpu?你用的是什么机器?将 cv::waitKey 增加到 5、10 还是 20 会更好吗?
@Micka 这是一个 i3-8100T,所以它有一个 Intel UHD 630,调整 FHD 图像的大小应该不是问题。我现在用 OpenGL 支持编译它(Debian 版本没有),cv::WINDOW_OPENGL
甚至比cv::WINDOW_AUTOSIZE
更快(55% CPU 与 65%)但不能与cv::WINDOW_KEEPRATIO
一起工作,所以它压缩了图像。将 16:9 的视频安装到 16:10 的屏幕是可以接受的 atm,但我有另一个 4:3 比例的流看起来很尴尬。
@Micka cv::WINDOW_AUTOSIZE
disables resizing completely(“大小受显示的图像限制”)而cv::WINDOW_OPENGL
将完整的渲染(调整大小)卸载到 GPU。我不知道调整大小对 CPU 来说是一项艰巨的任务(就像 cv::WINDOW_NORMAL
所做的那样)。我在下面相应地调整了我的答案。
【参考方案1】:
我现在发现了valgrind
(存储库)和gprof2dot
(pip3 install --user gprof2dot
):
valgrind --tool=callgrind /path/to/my/binary # Produced file callgrind.out.157532
gprof2dot --format=callgrind --output=out.dot callgrind.out.157532
dot -Tpdf out.dot -o graph.pdf
这产生了一个精彩的图表,表明在cvResize
上超过 60 % 蒸发。
事实上,当我注释掉 cv::resizeWindow
时,cpu 使用率会从 180 % 降低到 ~ 60 %。
由于屏幕的分辨率为 1920 x 1200,流的分辨率为 1920 x 1080,它基本上只消耗 CPU 周期。
到目前为止,这仍然很脆弱。一旦我将其切换到全屏模式并返回,cpu 负载就会恢复到 180%。
为了解决这个问题,事实证明我可以使用 cv::WINDOW_AUTOSIZE
完全禁用调整大小 ...
cv::namedWindow( "PREVIEW", cv::WINDOW_AUTOSIZE );
... 或 -- 如Micka 建议的 -- 在使用 OpenGL 支持编译的 OpenCV 版本上(-DWITH_OPENGL=ON
,我的 Debian 存储库版本不支持),使用 ...
cv::namedWindow( "PREVIEW", cv::WINDOW_OPENGL );
... 将渲染卸载到 GPU,结果证明与调整大小一起更快(55% CPU,而我为 65%)。
只需does not seem 与cv::WINDOW_KEEPRATIO
一起工作。*
此外,事实证明cv:UMat
可以用作cv:Mat
的直接替代品,这进一步提高了性能(如ps -e -o pcpu,args
所见):
附录
[*] 所以我们必须手动缩放它并注意纵横比。
float screen_aspratio = (float) screen_width / screen_height;
float image_aspratio = (float) image_width / image_height;
if ( image_aspratio >= screen_aspratio ) // width limited, center window vertically
cv::resizeWindow("PREVIEW", screen_width, screen_width / image_aspratio );
cv::moveWindow( "PREVIEW", 0, (screen_height - image_height) / 2 );
else // height limited, center window horizontally
cv::resizeWindow("PREVIEW", screen_height * image_aspratio, screen_height );
cv::moveWindow( "PREVIEW", (screen_width - image_width) / 2, 0 );
【讨论】:
【参考方案2】:弹出的一件事是您正在创建一个新窗口并在每次要显示某些内容时调整它的大小。
移动这些行
cv::namedWindow( "PREVIEW", cv::WINDOW_NORMAL );
cv::resizeWindow( "PREVIEW", screen_width, screen_height );
在您的while(true)
之前,看看它可以解决这个问题
【讨论】:
哦,当然!谢谢!我更新了上面的代码。它给了我 1% 或 2%,但并没有真正改变结果。 您是否在不显示任何内容的情况下检查了您获得的 CPU 使用率(删除cv::imshow()
? 只是为了看看您开始使用什么,以确保开销来自 opencv 而不是来自流媒体部分
@YunusTemurlenk 我们正试图找出原因。我们不知道,如果您有什么建议,请帮忙。
如果没有cv::imshow()
,delay == 5
和 delay == 1
的 CPU 利用率(进程的 CPU 利用率(CPU、线程的利用率,以 % 为单位 - 由 htop 列出)。所以,剩下的就是opencv
。
可能跑题了:有趣的是,在完整的 fps 流中,我有 11 个线程(4 核 i3 gen. 8),其中 4 个线程再次在 4% 左右,4 个在 0% 和 3 个繁重的工作。是不是应该的样子?以上是关于FHD 视频流上 OpenCV 文本覆盖的 CPU 占用太高的主要内容,如果未能解决你的问题,请参考以下文章