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

时间:2010-01-12 16:15:11

标签: c++ multithreading image-processing opencv

我有一个循环从250fps的高速framegrabbger中获取图像。

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

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

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

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

我尝试使用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

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

4 个答案:

答案 0 :(得分:10)

确定。令人尴尬的是,我的问题也是它自己的答案。

使用我的问题中描述的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;
}

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

答案 1 :(得分:4)

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

答案 2 :(得分:0)

对不起,我现在无法给你一个更好的答案,但似乎你的问题不是你的程序结构,而是你应该用来实现多线程的工具。为此我建议Qt。我已经使用Qt了一段时间,但我刚刚进入多线程。

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

再次抱歉,我不能更详细,但就像我说的那样,我也只是进入了这个。我基本上试图做同样的事情,但不是那么快:)。祝你好运!

答案 3 :(得分:0)

我不确定为什么会这样,但我在每个cvShowImage之后添加了一个cvWaitKey并且图片显示正确。

cvShowImage(myImage);
cvWaitKey(1);