我有一个使用Qt5.7和OpenNI用C ++编写的多线程应用程序。它有一个主线程,启动第二个线程,从.oni记录文件(asus xtion pro live)捕获帧进行一些处理,并通过Qt信号槽机制将帧传递给主线程,使用{{ 1}}。 我想要做的是实现一个暂停键,所以按下例如'p'处理暂停。我在考虑这样的事情:
imshow()
通过这种方式它不起作用,我认为那是因为框架是由另一个线程(主要的)显示的,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()
waitkey似乎被忽略了(图像显示工作正常)..任何想法?
修改的 GUI部分仅用于调试目的。
答案 0 :(得分:1)
您应该在显示线程中实现线程安全FIFO缓冲区或循环缓冲区。来自相机线程的信号将图像推送到此缓冲区,显示线程将把它们取出并在单独的循环中显示它们。只有这样才能将相机事件循环与显示线程分开。
答案 1 :(得分:0)
也许这是一个较晚的答案,但是我想介绍一下我在最近的项目中所做的事情,以防万一有人处于类似情况并希望使用相同的技术。
我的项目基本上是一个命令行程序,并使用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;
};
现在在main函数中,我们可以启动线程并使用cv::waitKey()
处理键事件,请注意,它还将在内部启动QT main事件循环。
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;
}