繁体   English   中英

在多线程应用程序中使用opencv waitKey()

[英]using opencv waitKey() in a multithreading application

我有一个用Qt5.7和OpenNI用C ++编写的多线程应用程序。 它具有一个主线程,该主线程启动了第二个线程,该线程从.oni录制文件(华硕xtion pro live)捕获帧进行一些处理,并通过Qt信号槽机制将帧传递给主线程,并使用imshow() 我想做的是实现一个暂停键,因此按下例如“ p”表示处理暂停。 我在想这样的事情:

void Camera::run(){
  while(!cameraStop && this->device.isValid())
    {
      try {
        if (!buttonPause) {
            getFrame();
            process();
            emit sigFrameImageReady(frame);
            if (cv::waitKey(1)==112){
              setButtonPause(!(getButtonPause()));
            }
          }

      }
      catch(std::exception &ex) {
        std::cerr << "getFrame()" << ex.what() << std::endl;
      }
    }
}

这样就行不通了,我认为这是因为该框架是由另一个线程(主线程)显示的,这里的waitKey()只是阻塞了整个过程,但是如果我将它放在主线程中,就在imshow()之后imshow()以这种方式:

void Process::FrameImageReady(cv::Mat FrameImage)
{
  if (modedebug)
    cv::imshow("bgr", FrameImage);
  if (cv::waitKey(1)==112){
    cam->setButtonPause(!(getButtonPause()));
  }
} 

waitkey似乎被忽略了(图像显示效果很好)..有什么想法吗?

编辑 GUI部分仅用于调试目的。

您应该在显示线程中实现线程安全的FIFO缓冲区或循环缓冲区。 来自摄像头线程的信号会将图像推入此缓冲区,而显示线程将其取出并在单独的循环中显示。 只有这样,您才能将相机事件循环与显示线程分开。

也许这是一个较晚的答案,但如果有人遇到类似情况并希望使用相同的技术,我想介绍一下我在最近的项目中所做的事情。

基本上,我的项目是一个命令行程序,并使用QT进行多线程和线程间通信,同时我们还需要一些最小的UI来显示图像并处理用户按键事件,因此OpenCV Highgui模块对我来说已经足够了。 这是我为使他们一起工作所做的:

  1. (重要)您必须构建具有QT支持的OpenCV才能使以下代码正常工作,即在构建OpenCV时在cmake-gui中检查WITH_QT选项。 或者,如果您使用vcpkg,请使用:

     vcpkg install opencv[qt]:x64-windows 
  2. 首先创建用于工作线程的类,然后使用此线程不断从相机缓冲区中检索图像帧,并在每次图像准备就绪时通知主线程:

     class MyThread : public QThread { Q_OBJECT public: MyThread() : mAbort(false) { } ~MyThread() { mMutex.lock(); mAbort = true; // make the thread out of the loop mMutex.unlock(); wait(); // wait until the run() function returns cout << "thread terminated" << endl; } protected: void run() override { while(!mAbort) { cv::Mat frame; if (myCamera->grab(frame) && !frame.empty()) { emit imageReady(frame); } else { cout << "failed to grab" << endl; } } } signals: void imageReady(const cv::Mat& frame); private: bool mAbort; QMutex mMutex; }; 
  3. 然后创建控制器类来处理来自工作线程的信号,我用它来显示框架。 注意它正在主线程中运行:

     class MyController : public QObject { Q_OBJECT public: MyController(MyThread* pThread) : mThread(pThread) { // this is needed as the argument is passed through queued connection qRegisterMetaType<cv::Mat>("CvMat"); connect(mThread, &MyThread::imageReady, this, &MyController::onImageReady); connect(mThread, &MyThread::finished, mThread, &QObject::deleteLater); mThread->start(); } public slots: void onImageReady(const cv::Mat& frame) { cv::imshow("camera live view", frame); } private: MyThread* mThread; }; 
  4. 现在在main函数中,我们可以启动线程,并使用cv::waitKey()处理键事件,注意它还将在内部启动QT主事件循环。

     Q_DECLARE_METATYPE(cv::Mat) ... int main(int argc, char* argv[]) { ... // start working thread MyThread thread = new MyThread(); MyController controller(thread); // handle key events while (true) { int key = cv::waitKey(); cout << "key = " << key << endl; // press "ESC" to exit if (key == 27) { break; } } // clean up ... delete thread; delete myCamera; return 0; } 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM