在第二个线程中显示图像,OpenCV?

Posted

技术标签:

【中文标题】在第二个线程中显示图像,OpenCV?【英文标题】:Display image in second thread, OpenCV? 【发布时间】:2010-01-12 16:15:11 【问题描述】:

我有一个循环以 250fps 的速度从高速帧抓取器中获取图像。

/** Loop processes 250 video frames per second **/
while(1)
  AcquireFrame();
  DoProcessing();
  TakeAction();

同时,我希望用户能够监控正在发生的事情。用户只需要以大约 30 fps(或更低)的速度查看图像。如何设置第二个线程,每隔一段时间显示当前帧?

Thread()
  cvShowImage();
  Wait(30); /** Wait for 30 ms **/

我在 Windows 上使用 MinGW、gcc 和 OpenCV 1.1 的四核 Intel 机器。主要标准是显示线程必须尽可能少地离开我的主处理循环。每一毫秒都很重要。

我尝试使用CreateThread() 创建一个新线程,其中cvShowImage()cvWaitKey() 但apparently those functions are not threadsafe。

我正在考虑使用 OpenMP,但有些人 report problems with OpenMP and OpenCV。我也在考虑尝试使用 DirectX directDraw,因为它显然非常快。但它looks complicated 显然有problems using Windows DLL's with MinGw。

这些途径中的哪一个是最好的起点?

【问题讨论】:

仅使用 if 条件和高达 250 的“计数”变量来显示每 8 次捕获 (250/30) 是否足够? 啊,是的。但是如果你这样做了,那么当你显示第 8 个捕获时,整个程序就会停止。使用 cvShowImage 显示图像大约需要 10 毫秒。到那时你已经错过了几帧。 您是否从相机获得 250 fps?如果你是,你能告诉我你是怎么做到的吗?这是非常快的。 @bakalolo 是的。答案是花哨的硬件。我使用带有专用 PCIe 图像采集卡的 10 抽头双 CameraLink 相机。 (对不起,这晚了7年。现在才看到。) 【参考方案1】:

好的。很尴尬的是,我的问题也是它自己的答案。

使用我的问题中描述的CreateThread()CvShowImage()CvWaitKey() 确实有效——这与网络上的一些帖子相反。

无论如何,我实现了这样的东西:

/** Global Variables **/
bool DispThreadHasFinished;
bool MainThreadHasFinished;
iplImage* myImg;

/** Main Loop that loops at >100fps **/
main() 
  DispThreadHasFinished = FALSE;
  MainThreadHasFinished = FALSE;
  CreateThread(..,..,Thread,..);

  while( IsTheUserDone() ) 
    myImg=AcquireFrame();
    DoProcessing();
    TakeAction();
  
  MainThreadHasFinished = TRUE;

  while ( !DisplayThreadHasFinished ) 
     CvWaitKey(100);
  

  return;


/** Thread that displays image at ~30fps **/
Thread() 
  while ( !MainThreadHasFinished ) 
    cvShowImage(myImg);
    cvWaitKey(30);
  
DispThreadHasFinished=TRUE;
return;

当我最初发布此问题时,我的代码因不相关的原因而失败。我希望这会有所帮助!

【讨论】:

【参考方案2】:

由于帧抓取不需要使用 UI,我会设置一个辅助线程来处理帧抓取,并让处理 UI 的原始线程显示示例帧。如果您试图显示当前被抓取的帧,则必须锁定数据(这通常相当慢)。为避免这种情况,我会在当前被抓取的帧“后面”显示一帧(或可能是两帧),因此在抓取和显示数据之间没有争用。您仍然必须确保递增当前帧号是线程安全的,但这非常简单——在捕获线程中使用 InterlockedIncrement。

【讨论】:

我同意这个解决方案——这里的复杂性似乎源于处理是在主线程上完成的事实。如果处理是在后台线程上完成的,保存对最后一张图像的引用,则 ui 线程(或 ui 上的工作线程)可以以您选择的任何速率抓取最后一张图像。【参考方案3】:

很抱歉,我现在不能给你一个更好的答案,但你的问题似乎不是关于你的程序的结构,而是关于你应该用来实现多线程的工具。为此,我推荐Qt。我使用 Qt 已经有一段时间了,但我现在才开始使用多线程。

在我看来,您最好的选择可能是QReadWriteLock。这允许您从图像中读取,但当写入线程出现时,读取线程将放弃其锁定。在这种情况下,您可以保留上次显示的图像的副本,并在图像被锁定以供写入时显示它。

再次抱歉,我不能说得更详细,但是,就像我说的,我也刚刚开始讨论这个问题。我基本上是在尝试做和你一样的事情,但没有那么快:)。祝你好运!

【讨论】:

【参考方案4】:

我不知道为什么会这样,但是我在每个 cvShowImage 之后都添加了一个 cvWaitKey 并且图片可以正常显示。

cvShowImage(myImage);
cvWaitKey(1);

【讨论】:

以上是关于在第二个线程中显示图像,OpenCV?的主要内容,如果未能解决你的问题,请参考以下文章

Java 多线程共享对象 - 需要设计模式

APNG 在第二个页面刷新后不同步

数组中的数据未显示在第二个 UIPickerView 中

Delphi Form显示在第二个显示器中的方法

无法在第二个视图控制器中更新我的 UIImage

菜单栏未显示在第二个窗口上