在多线程应用程序中使用 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 部分仅用于调试目的。
【问题讨论】:
imshow
、waitKey
和highgui
中的其他功能仅用于调试目的。由于您已经在使用 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()的主要内容,如果未能解决你的问题,请参考以下文章