簡體   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