cvWaitKey() 显着减慢捕获过程 - 解决方法?
Posted
技术标签:
【中文标题】cvWaitKey() 显着减慢捕获过程 - 解决方法?【英文标题】:cvWaitKey() slowing capture process significantly - workaround? 【发布时间】:2013-09-09 15:00:52 【问题描述】:我正在将 PS3 Eye Camera Video 捕获为我调整大小和显示的图像,并将它们保存到磁盘。我在帧率方面遇到了麻烦,所以我测量了每个单独进程的时间。事实证明,唯一真正减慢捕获速度的过程是 cvWaitKey(1),它为每个捕获循环增加了大约 20 毫秒。
有没有办法以某种方式避免 cvWaitKey() ?
测量的时间将是大约 20 毫秒(没有等待键和显示)和 60 毫秒(显示需要等待键)。调整大小不会增加这么多时间。
感谢您的帮助。
// image capturing loop
while(_running)
//activate cvWaitKey - this drops framerate significantly!
cvWaitKey(1);
//get frame from capture and put into buffer
CLEyeCameraGetFrame(_cam, pCapBuffer);
//get system timestamps
GetSystemTime(&st);
GetLocalTime(<);
// Resize image to fit screen size
cvResize(pCapImage,resizedpCapImage,CV_INTER_NN);
//display image
cvShowImage(_windowName, resizedpCapImage);
//clear string
sstm.str(std::string());
//complete filname
sstm << _folder << prefix << _participant << std::setfill('0') << std::setw(10) << i << "-" << st.wHour << st.wMinute << st.wSecond << st.wMilliseconds << suffix;
image_name = sstm.str();
c = image_name.c_str();
//log if enabled
if (_logging)
//try to save image
try
cvSaveImage(c, pCapImage); //bmp = speed!
catch (runtime_error& ex)
fprintf(stderr, "Exception converting image to bmp format: %s\n", ex.what());
【问题讨论】:
【参考方案1】:首先,不建议立即抓取一个帧并将其写入磁盘,因为这是一个系统调用,因此所花费的时间是不可预测的。对于短视频,您可以将整组未压缩的帧存储在内存中。如果这不起作用,您将需要两个线程:一个用于抓取帧并将其写入缓冲区,另一个用于将它们保存到磁盘。
其次,如果你在运行windows,你可以使用_getch
(和_kbhit
)来替换cvWaitKey
,如果它更快的话。
if(_kbhit()) ch = _getch();
但是,我对指责 cvWaitKey
持保留意见。如果您使用GetSystemTime
来分析您的代码,那么您的结果很可能是错误的,因为它不是很准确。
我建议您使用 QueryPerformanceCounter 重新分析您的代码(如果您使用的是 Windows)。
【讨论】:
嗨,Jacob,我的视频不是视频,而是捕获的帧,大约 5-10 分钟长,所以我怀疑缓冲是一种选择。多线程这并没有提高速度,因为外包保存过程实际上并没有太大帮助,因为我获得了大约 3-5 毫秒的速度增益。如果我不显示并且只保存我会获得大约 40 毫秒的速度增益。至于测量 - 我看到在一段时间内保存的图像,也以客观的方式查看视频,所以差异对我来说是可以测量的。你将如何用 cvWaitKey 交换 _getch ? 对不起,对于@jakob 的反对意见,但它要么放弃 waitkey 和 showImage,要么将两者都保留在这里。 waitkey 所做的不仅仅是等待按键,它包含窗口的消息泵,并触发实际的 blitting(这可能解释了为什么它需要时间)。还 getch 阻塞了主线程,这非常糟糕。 @berak:没问题;_getch()
单独是个坏主意。它需要像往常一样与_kbhit()
结合。
嘿,真的。但除了完全不可移植外,它还等待控制台窗口中的事件,而不是显示图像的事件。
嘿,让我们在这里解决,我们都尽力提供帮助;)【参考方案2】:
我还没有找到 cvWaitKey(1) 的解决方法,但我想出了另一种使用窗口处理程序调整图像大小的方法,这让我可以在大约 20 毫秒内渲染图像
cvResize(pCapImage,resizedpCapImage,CV_INTER_NN);
因此,这种插值可能会减慢过程并代表瓶颈。
我是这样处理的:
而不是使用
cvNamedWindow(_windowName, CV_WINDOW_AUTOSIZE);
我现在用
cvNamedWindow(_windowName, CV_WINDOW_NORMAL);
由于我仍然必须完成以无边框全屏显示窗口,因此我添加了以下功能:
//display Window in Fullscreen depending on where the client camerawindow is at and what resolution this monitor has.
void Class::setFullscreen()
cvSetWindowProperty(_windowName, CV_WND_PROP_FULLSCREEN, CV_WINDOW_FULLSCREEN);
HWND win_handle = FindWindow(0, (LPCTSTR)_windowName);
if (!win_handle)
printf("Failed FindWindow\n");
// Get monitor resolution
HMONITOR monitor = MonitorFromWindow(win_handle, MONITOR_DEFAULTTONEAREST);
MONITORINFO info;
info.cbSize = sizeof(MONITORINFO);
GetMonitorInfo(monitor, &info);
int monitor_width = info.rcMonitor.right - info.rcMonitor.left;
int monitor_height = info.rcMonitor.bottom - info.rcMonitor.top;
// Resize
unsigned int flags = (SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER);
flags &= ~SWP_NOSIZE;
// Set position
unsigned int x = 0;
unsigned int y = 0;
SetWindowPos(win_handle, HWND_NOTOPMOST, x, y, monitor_width, monitor_height, flags);
// Borderless
SetWindowLong(win_handle, GWL_STYLE, 0);
ShowWindow(win_handle, SW_SHOW);
这样做我在每次迭代大约 20 毫秒到 30 毫秒之间完成了相当高的帧速率,这相当于大约 30-50hz(或 fps)。这是对速度的改进,但它不是精确帧速率的精确解决方案。我还尝试将精度提高到 40hz,但像 cvWaitKey(20) 一样为 cvWaitKey() 提供更高的参数只会降低帧率,但不会增加任何帧率稳定性。
【讨论】:
以上是关于cvWaitKey() 显着减慢捕获过程 - 解决方法?的主要内容,如果未能解决你的问题,请参考以下文章