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(&lt);

        // 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() 显着减慢捕获过程 - 解决方法?的主要内容,如果未能解决你的问题,请参考以下文章

当我 ORDER BY 计算列时,查询会显着减慢 - 可以加快速度吗?

CSS3 PIE:圆角减慢 IE9,即使它本机支持它们

查询减慢网站速度,必须使它们执行得更快

为啥 cvWaitKey(0) 不起作用?

cvwaitkey理解

如何在 Spring Boot 中简化 LDAP 身份验证以减少数据加载过程时间?