首页 > 解决方案 > 如何在 OpenCV 处理期间保持窗口打开?

问题描述

我在 Linux 上遇到了一个奇怪的问题,特别是 Ubuntu 16.04。如果我使用通常的代码来显示这样的网络摄像头流,它可以正常工作:

// WebcamTest.cpp

#include <opencv2/opencv.hpp>

#include <iostream>

int main()
{
  // declare a VideoCapture object and associate to webcam, 1 => use 2nd webcam, the 0th webcam is the one integral to the TX2 development board
  cv::VideoCapture capWebcam(1);

  // check if VideoCapture object was associated to webcam successfully, if not, show error message and bail
  if (capWebcam.isOpened() == false)
  {
    std::cout << "error: capWebcam not accessed successfully\n\n";
    return (0);
  }

  cv::Mat imgOriginal;        // input image
  cv::Mat imgGrayscale;       // grayscale of input image
  cv::Mat imgBlurred;         // intermediate blured image
  cv::Mat imgCanny;           // Canny edge image

  char charCheckForEscKey = 0;

  // while the Esc key has not been pressed and the webcam connection is not lost . . .
  while (charCheckForEscKey != 27 && capWebcam.isOpened())
  {
    bool blnFrameReadSuccessfully = capWebcam.read(imgOriginal);            // get next frame

    // if frame was not read successfully, print error message and jump out of while loop
    if (!blnFrameReadSuccessfully || imgOriginal.empty())
    {
      std::cout << "error: frame not read from webcam\n";
      break;
    }

    // convert to grayscale
    cv::cvtColor(imgOriginal, imgGrayscale, CV_BGR2GRAY);

    // blur image
    cv::GaussianBlur(imgGrayscale, imgBlurred, cv::Size(5, 5), 0);

    // get Canny edges
    cv::Canny(imgBlurred, imgCanny, 75, 150);

    cv::imshow("imgOriginal", imgOriginal);
    cv::imshow("imgCanny", imgCanny);

    charCheckForEscKey = cv::waitKey(1);        // delay (in ms) and get key press, if any
  }  // end while

  return (0);
}

此示例在一个 imshow 窗口中显示网络摄像头流,在第二个窗口中显示 Canny 边缘图像。两个窗口都按预期更新和显示图像,几乎没有任何可察觉的闪烁。

如果您想知道为什么我使用第 1 个摄像头而不是通常的第 0 个摄像头,我在 Jetson TX2 上运行它,第 0 个摄像头是开发板不可或缺的一个,我更喜欢使用额外的外部网络摄像头。出于同样的原因,我必须使用 Ubuntu 16.04,但我怀疑结果与 Ubuntu 18.04 相同(但尚未对此进行测试)。

相反,如果我有一个需要大量处理而不是简单的 Canny 边缘的函数,即:

int main(void)
{
  .
  .
  .
  // declare a VideoCapture object and associate to webcam, 1 => use 2nd webcam, the 0th webcam is the one integral to the TX2 development board
  cv::VideoCapture capWebcam(1);

  // check if VideoCapture object was associated to webcam successfully, if not, show error message and bail
  if (capWebcam.isOpened() == false)
  {
    std::cout << "error: capWebcam not accessed successfully\n\n";
    return (0);
  }

  cv::namedWindow("imgOriginal");

  cv::Mat imgOriginal;
  char charCheckForEscKey = 0;

  // while the Esc key has not been pressed and the webcam connection is not lost . . .
  while (charCheckForEscKey != 27 && capWebcam.isOpened())
  {    
    bool blnFrameReadSuccessfully = capWebcam.read(imgOriginal);            // get next frame

    // if frame was not read successfully, print error message and jump out of while loop
    if (!blnFrameReadSuccessfully || imgOriginal.empty())
    {
      std::cout << "error: frame not read from webcam\n";
      break;
    }

    detectLicensePlate(imgOriginal);

    cv::imshow("imgOriginal", imgOriginal);

    charCheckForEscKey = cv::waitKey(1);        // delay (in ms) and get key press, if any

  }  // end while
  .
  .
  .
  return (0);
}

detectLicensePlate()功能大约需要一秒钟才能运行。

我遇到的问题是,在运行这个程序时,窗口只出现了最少量的时间,通常时间不够长,甚至无法察觉,也永远无法真正看到结果。

奇怪的是,窗口消失了,然后第二天左右发生了detectLicensePlate()做它的事情,然后窗口又出现了很短的时间,然后又消失了,以此类推。几乎就像在cv::imshow("imgOriginal", imgOriginal);,之后cv::destroyAllWindows();被隐式调用一样。

我试图实现的行为是让窗口保持打开状态并在处理下一个结果时继续显示上一个结果。据我回忆,这是 Windows 上的默认行为。

我应该提到,我cv::namedWindow("imgOriginal");在 while 循环之前明确声明了窗口,以试图不让它超出范围,但这似乎没有帮助。

当然我可以让延迟更长,即

charCheckForEscKey = cv::waitKey(1500);

等待 1.5 秒,但随后应用程序变得非常无响应。

基于this post c++ opencv image not display inside boost thread我尝试在while循环之外声明窗口并将detectLicensePlate()andcv::imshow()放在一个单独的线程上,如下所示:

  .
  .
  .
  cv::namedWindow("imgOriginal");

  boost::thread myThread;

  // while the Esc key has not been pressed and the webcam connection is not lost . . .
  while (charCheckForEscKey != 27 && capWebcam.isOpened())
  {

    // if frame was not read successfully, print error message and jump out of while loop
    if (!blnFrameReadSuccessfully || imgOriginal.empty())
    {
      std::cout << "error: frame not read from webcam\n";
      break;
    }

    myThread = boost::thread(&preDetectLicensePlate, imgOriginal);
    myThread.join();
    .
    .
    .
  } // end while


// separate function
void preDetectLicensePlate(cv::Mat &imgOriginal)
{
  detectLicensePlate(imgOriginal);
  cv::imshow("imgOriginal", imgOriginal);
}

我什至尝试detectLicensePlate()使用单独的线程,但没有cv::imshow(),反之亦然,结果仍然相同。无论我如何更改顺序或使用线程,在下一轮处理进行时,我都无法让窗口保持打开状态。

我意识到我可以使用完全不同的窗口环境,例如 Qt 或其他东西,这可能会也可能不会解决问题,但出于各种原因,我真的更愿意避免这种情况。

有没有人有任何其他建议让 OpenCVimshow窗口保持打开状态,直到窗口下次更新或被cv::destroyAllWindows()显式调用?

标签: c++linuxopencvubuntuboost

解决方案


推荐阅读