一段时间以来,我现在正在与一个应用程序的Qt合作,我必须从相机抓取帧。相机将运行在与应用程序其余部分不同的线程中。我跟着的建议:不使用QThread :: start()而使用QThread是否有意义?
http://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/
和
http://blog.qt.digia.com/blog/2010/06/17/youre-doing-it-wrong/
不继承的QThread。相反,我创建了一个工作对象CCameraCapture并将其移至QThread。摄像头的抓图由连接到抓图框槽的QTimer控制。将CCameraCapture移到QThread后,可以通过启动定时器来启动捕获。我的问题是:我必须调用QThread类的start()吗?我的方法不需要调用它。该循环由计时器执行,并且该工作人员实际上正在另一个线程中工作而不调用开始。所以我想知道是否有任何意义调用start()如果使用了一个计时器?为清楚起见,我把低于在主应用程序通过创建了Worker类:
m_CameraCaptureThread= new QThread();
m_CameraCapture = new CCameraCapture(30);
m_CameraCapture->moveToThread(m_CameraCaptureThread);
//Connect error signal
QObject::connect(m_CameraCapture, SIGNAL(error(QString,QString)), this, SLOT(reportError(QString,QString)));
//Connect started() of QThread to the starting function of the worker class
connect(m_CameraCaptureThread, SIGNAL(started()), m_CameraCapture, SLOT(startGrabbing()));
//Connect the finished signal of the worker class to the thread for quitting the loop
connect(m_CameraCapture, SIGNAL(finished()), m_CameraCaptureThread, SLOT(quit()));
//This connections guarantees that the *m_CVideoCapture is automatically deleted if the event loop of the thread is terminated. Therefore, m_CVideoCapture does not need to be released manually if the capturing process is stopped.
QObject::connect(m_CameraCaptureThread, SIGNAL(finished()), m_CameraCaptureThread, SLOT(deleteLater()));
QObject::connect(m_CameraCapture, SIGNAL(finished()), m_CameraCapture, SLOT(deleteLater()));
//Connect sendFrame to update frame for displaying the current frame
QObject::connect(m_CameraCapture, SIGNAL(sendFrame(QImage)), this, SLOT(receiveFrame(QImage)));
/**
所以这点没有m_CameraCaptureThread->开始()被调用开始处理循环。但是如果我调用CameraCapture-> startGrabbing(),它将很好地工作。 grabFrame()插槽由定时器触发,并将帧发送到主应用程序。然而,所有的代码示例,我看到到目前为止调用start(),即使他们使用的定时器:如: http://blog.debao.me/2013/08/how-to-use-qthread-in-the-right-way-part-1/(使用2-1页的末尾)
这是我CCameraCapture.h:
/**
@file CCameraCapture.h
@brief this file contains the definition of the class CCameraCapture.
**/
#ifndef CCameraCapture_H
#define CCameraCapture_H
//Required Qt libs
#include <QObject>
#include <QImage>
#include <QTimer>
#include <QString>
#include <QMutex>
#include <QDebug>
//Required OpenCV libs
#include <opencv2\opencv.hpp>
/**
@class CCameraCapture
@brief This class defines a video capture object which should be moved to thread.
class CCameraCapture : public QObject{
Q_OBJECT
public:
/**
@brief Constructor of CCameraCapture.
@param frameRate Desired frame rate (if possible)
*/
CCameraCapture(double frameRate=30);
/**
@brief Destructor of CCameraCapture.
*/
~CCameraCapture();
/**
@brief This function terminates the thread.
*/
void exitThread();
bool startGrabbing();
void stopGrabbing();
/**
@brief Check if camera is running
@return Returns true if camera is running
*/
bool isGrabbing();
private:
//The openCV capturing object to access the camera
cv::VideoCapture m_Cap;
// Device index
int m_IdxDevice;
// Timer for triggring grab frame
QTimer m_Timer;
//The most recent frame
QImage m_Frame;
//Mutex to lock variables
QMutex m_Mutex;
private slots:
/**
@brief This slot grabs a frame from the camera. It is triggered by the timer m_Timer.
*/
void grabFrame();
signals:
/**
@brief This signal needs to be connected to the slot in the main application which should receive the images.
@param img The most recent frame.
*/
void sendFrame(QImage currentFrame);
/**
@brief This signal is emitted if an error occurs
@param errMsg QString contains the error message to be displayed.
@param errTitle QString contains the title of the diplayed error message.
This signal should be connected to a slot in the main application. It allows to send error reports back to the main application which can be displayed on screen
*/
void error(QString errMsg,QString errTitle);
void finished();
};
#endif //CCameraCapture_H
这是cpp文件:
/**
@file CCameraCapture.cpp
@brief this file contains the function definitions of CCameraCapture.
**/
#include "CCameraCapture.h"
CCameraCapture::CCameraCapture(double frameRate):m_Mutex(),m_IdxDevice(0)
{
//Connect timer to grabFrame
connect(&m_Timer, SIGNAL(timeout()), this, SLOT(grabFrame()), Qt::DirectConnection);
//Set framerate
m_Timer.setInterval(1000/frameRate);
}
CCameraCapture::~CCameraCapture(void)
{
}
void CCameraCapture::grabFrame(){
qDebug() << "Worker thread ID" << this->thread();
//Lock this function
QMutexLocker ml(&m_Mutex);
//Local image storage
cv::Mat cvFrameBGR,cvFrameRGB;
//Get new frame from camera
m_Cap>>cvFrameBGR;
//Convert frame to RGB
cv::cvtColor(cvFrameBGR, cvFrameRGB, CV_BGR2RGB);
//Convert cv::Mat to QImage
QImage m_Frame=QImage((uchar*)(cvFrameRGB.data),cvFrameRGB.cols,cvFrameRGB.rows,QImage::Format_RGB888);
//Send frame to receivers
emit sendFrame(m_Frame);
}
bool CCameraCapture::startGrabbing(){
//Lock this function
QMutexLocker ml(&m_Mutex);
//Check if camera is open
if(!m_Cap.isOpened()){
//Connect to camera
if(!m_Cap.open(m_IdxDevice)){
emit error(QString("Could not connect to Camera."),QString("Error: No camera detected"));
return 0;
}
else{
//Start grabbing
m_Timer.start();
return 1;
}
}
else{
//Start grabbing
m_Timer.start();
return 1;
}
}
void CCameraCapture::stopGrabbing(){
//Lock this function
QMutexLocker ml(&m_Mutex);
//Stop grabbing
m_Timer.stop();
}
bool CCameraCapture::isGrabbing(){
//Lock this function
QMutexLocker ml(&m_Mutex);
//Return true if timer is running and triggering grabFrame
return m_Timer.isActive();
}
void CCameraCapture::exitThread(){
//Lock this function
QMutexLocker ml(&m_Mutex);
//Stop grabbing
stopGrabbing();
//Release camera
m_Cap.release();
//Emit finished signal which should be connected to quit() of QThread and deleteLater() of this class;
emit finished();
}
感谢您的答案 - 我检查了CCameraCapture :: grabFrame(),如果它真的是一个不同的线程,因为我担心只有start()会实际启动一个不同的线程。它返回不同的线程ID。因此,我会假设我不必调用start(),因为我不需要事件循环。所以我想知道是否我错过了一些重要的事情,如果我不打电话开始除了有一个空的事件循环,或者如果我应该改变设计。 – 00Jan00
我建议你无论如何称呼它。即使您的代码现在可以工作,您也可以决定使用该线程做其他事情,然后想知道为什么它不能正常工作,忘记启动它。你会发现不同线程上的对象之间的消息需要在每个线程上有一个事件循环。 – TheDarkKnight
好点。直接连接使我的代码正常工作(请参阅下面的答案)。 – 00Jan00