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

Posted

技术标签:

【中文标题】在多线程应用程序中使用 opencv waitKey()【英文标题】:using opencv waitKey() in a multithreading application 【发布时间】:2016-09-26 10:50:15 【问题描述】:

我有一个使用 Qt5.7 和 OpenNI 用 C++ 编写的多线程应用程序。它有一个主线程,它启动第二个线程,该线程从 .oni 录制文件(asus xtion pro live)捕获帧进行一些处理,并通过 Qt 信号槽机制将帧传递给主线程,主线程使用@987654322 显示它@。 我想要做的是实现一个暂停键,例如按下“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;
      
    

这样是不行的,我认为是因为frame是由另一个线程(主线程)显示的,这里的waitKey()只是阻塞了整个进程,但是如果我把它放在主线程中,就在imshow()之后这样:

void Process::FrameImageReady(cv::Mat FrameImage)

  if (modedebug)
    cv::imshow("bgr", FrameImage);
  if (cv::waitKey(1)==112)
    cam->setButtonPause(!(getButtonPause()));
  
 

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

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

【问题讨论】:

imshowwaitKeyhighgui 中的其他功能仅用于调试目的。由于您已经在使用 Qt,我建议通过 Qt 功能显示图像,这些功能将在线程中正常运行 图像显示现在工作正常,我唯一的问题是waitkey()。您是否建议使用具有相同功能的 Qt 函数?你能推荐一个吗? 检查KeyEvent,但这不是我的事...我只是建议将 Qt 用于所有 GUI 的东西,因为 OpenCV 功能不适合用于复杂的任务。跨度> 【参考方案1】:

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

【讨论】:

【参考方案2】:

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

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

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

    vcpkg install opencv[qt]:x64-windows
    

    首先为工作线程创建类,我使用这个线程不断地从相机缓冲区中检索图像帧,并在每次图像准备好时通知主线程:

    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;
    ;
    

    然后创建控制器类来处理来自工作线程的信号,我用它来显示框架。注意它在主线程中运行:

    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;
    ;
    

    现在在主函数中,我们可以启动线程,并使用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;
    
    

【讨论】:

以上是关于在多线程应用程序中使用 opencv waitKey()的主要内容,如果未能解决你的问题,请参考以下文章

无法使用opencv打开视频

使用Android IP Camera(python)在openCv中直播

使用 OpenCV 在多类分类中获取 SVM 分类分数

Python快速学习opencv

在多线程应用程序中使用屏障的真实示例是啥?

如何在多线程应用程序中使用 aiopg 池?