当使用OpenCV从网络摄像头捕获视频时,QT GUI冻结
我正在使用Opencv进行一些实时视频处理 作为前端,我使用QT框架 在我的GUI上,我有一个输入图像窗口(映射到一个标签)和一个输出图像窗口(映射到另一个标签)以及3个按钮。一个用于启动输入视频捕获,第二个用于处理视频(代码尚未编写),第三个用于退出 我目前能够流式传输我的视频并在前端显示它。但这会锁定我的GUI,我无法退出 我尝试使用qtimer(使用本文和QT论坛的建议),但我的GUI仍然保持锁定状态 如果有人能为我指出正确的方向,我将不胜感激 代码如下:当使用OpenCV从网络摄像头捕获视频时,QT GUI冻结,qt,user-interface,opencv,webcam,Qt,User Interface,Opencv,Webcam,我正在使用Opencv进行一些实时视频处理 作为前端,我使用QT框架 在我的GUI上,我有一个输入图像窗口(映射到一个标签)和一个输出图像窗口(映射到另一个标签)以及3个按钮。一个用于启动输入视频捕获,第二个用于处理视频(代码尚未编写),第三个用于退出 我目前能够流式传输我的视频并在前端显示它。但这会锁定我的GUI,我无法退出 我尝试使用qtimer(使用本文和QT论坛的建议),但我的GUI仍然保持锁定状态 如果有人能为我指出正确的方向,我将不胜感激 代码如下: mainwindow.h #i
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp> // for cvtColor
#include <iostream>
#include <QTimer>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_buttonCaptureVideo_clicked();
void on_buttonExit_clicked();
public slots:
virtual void doNextFrame() {repaint();}
private:
Ui::MainWindow *ui;
CvCapture *capture; // OpenCV Video Capture Variable
IplImage *frame; // Variable to capture a frame of the input video
cv::Mat source_image; // Variable pointing to the same input frame
cv::Mat dest_image; // Variable to output a frame of the processed video
QTimer *imageTimer;
};
#endif // MAINWINDOW_H
当您单击按钮时
while(capture) { ... }
循环将永远运行,因为capture
将永远不会设置为NULL。
这意味着代码流永远不会离开您的循环,因此主线程无法处理其他任何事情,例如重新绘制
QTimer将发出其timeout()信号,但它们将作为事件放置在Qt的事件队列中。只要您的on\u buttonCaptureVideo\u clicked()
方法正在运行,这些事件就不会被处理
以下是我的建议,如何让它发挥作用:
此代码:
// Set to 25 frames per second
const int imagePeriod = 1000/25; // ms
imageTimer = new QTimer(this);
imageTimer->setInterval(imagePeriod);
connect(imageTimer, SIGNAL(timeout()), this, SLOT(doNextFrame()));
// Use the default camera
capture = cvCreateCameraCapture(-1);
属于MainWindow的构造函数,因为您只想设置一次。当用户第二次、第三次等单击按钮时,无需再次执行此操作
while
循环中的代码应该进入doNextFrame()
插槽(不带while构造)
那么你的按钮只能
imageTimer->start();
然后,例如,做
imageTimer->stop();
当再次单击时
示例代码:
void MainWindow::on_buttonCaptureVideo_clicked()
{
if( imageTimer->isActive() )
{
imageTimer->stop();
}
else
{
imageTimer->start();
}
}
如果你那样做会发生什么 单击该按钮时,GUI线程将调用\u buttonCaptureVideo\u clicked()单击的插槽上的
,计时器将启动,方法将立即返回。
现在GUI线程是免费的,可以处理重绘等操作。
从那时起,计时器将每隔40毫秒发送timeout()信号。每当GUI线程空闲时,它将处理此信号并调用您的doNextFrame
插槽。
此插槽将捕获下一帧并在完成后返回。完成后,GUI线程将能够再次处理其他事件(例如重新绘制)。
一旦再次单击该按钮,计时器将停止,并且不会发送新的timeout()事件。如果点击了按钮之后仍然看到两个帧,这意味着计时器事件发送的速度比处理的速度快。 序言:我在C++中不强,所以我不能提供特定的代码,但是我在PYQT
中有经验。
对于Qt的新手来说,这是一个常见的陷阱。您单击的
按钮上的似乎正在进入GUI主线程中的一个循环来完成工作。在QT中,您希望避免在主线程中执行任何繁忙的操作。Qt eventloop需要能够在GUI事件进入时不断地处理和刷新它们。您所做的是阻塞事件循环
在这里你可以做两件不同的事情。第一种是更基本的方法,但允许您看到更直接的结果。您可以“泵送”eventloop。根据循环迭代时的速度,可以调用qApp->processEvents()代码>。这将允许Qt处理挂起的GUI事件,并使您的应用程序看起来更具响应性。它基本上是在while循环和主循环之间共享时间。也许你想在每N帧调用这个。取决于您希望确保GUI刷新的频率
另一个更可取的选择是将捕获循环放在QThread中。当一个新帧可用时,您可以发射一个带有帧数据的信号。信号将被放入Qt事件循环中,与其他所有内容一起处理,并且不会占用GUI。一般来说,这是您希望在处理任何繁重的处理或长时间运行的回调函数时采用的方法
编辑
我刚刚意识到,除了在主线程中执行循环之外,还可以启动一个QTimer。如果您想使用QTimer,并且图像处理不太繁重(每个周期不需要很长时间),则应将所有内容移动到doNextFrame
中,并完全删除while
循环。如果您的doNextFrame
是一个繁重的进程,那么您应该使用QThread和signals。多长时间capture
计算为true?while循环运行多长时间?@jdi:只要用户希望流式传输输入视频,capture的计算结果应该为true。我现在已经让GUI使用QTimer进行响应,但是我注意到,如果我让流媒体太长时间处于活动状态,我会收到消息“Camera Drop frame!”,因此我猜测最终我将需要移动到QThreads。谢谢你的回复。@Sid,你能把代码贴出来吗?谢谢你的回复。我能够让GUI根据您的建议做出响应。
void MainWindow::on_buttonCaptureVideo_clicked()
{
if( imageTimer->isActive() )
{
imageTimer->stop();
}
else
{
imageTimer->start();
}
}