Für einige Zeit arbeite ich jetzt mit QT an einer Anwendung, in der ich Rahmen von einer Kamera schnappen muss. Die Kamera wird in einem anderen Faden ausgeführt als der Rest der Anwendung. Ich folgte den Empfehlungen von: http://mayaposch.wordpress.com/2011/11/ ... xplanation /
und https://www.qt.io/blog/2010/06/17/youre-doing-it-wrong < /p>
Nicht zu subklassen QThread. Stattdessen habe ich ein Worker -Objekt Ccameracapture erstellt und es in ein QThread verschoben. Das Rahmeneinzug der Kamera wird von einem Qtimer gesteuert, der mit einem Grab -Rahmen -Steckplatz verbunden ist. Nachdem die Ccameracapture in den QThread verschoben hat, kann die Erfassungsfestigkeit mit dem Timer gestartet werden. Meine Frage ist: Muss ich Start () der QThread -Klasse anrufen? Mein Ansatz funktioniert, ohne es anzurufen. Die Schleife wird vom Timer durchgeführt und der Arbeiter arbeitet tatsächlich in einem anderen Thread, ohne den Start anzurufen. Ich frage mich also, ob es einen Sinn gibt, Start () anzurufen (), wenn ein Timer verwendet wird. Für die Klarheit habe ich meine Arbeiterklasse unten in der Hauptanwendung erstellt von: < /p>
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)));
/**
< /code>
Bis zu diesem Punkt wurde also kein m_cameracapturethread-> start () gerufen, um die Verarbeitungsschleife zu starten. Aber wenn ich Cameracapture-> startgrabbing () nenne, wird es gut funktionieren. Der Timer Grabframe () wird vom Timer ausgelöst und die Frames werden an die Hauptanwendung gesendet. Allerdings alle Codebeispiele, die ich bisher als Start () genannt habe, auch wenn sie Timer verwendeten: z. The-Right-Way-Teil-1/(Verwendung 2-1 am Ende der Seite)
Dies ist meine 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
#include
#include
#include
#include
#include
//Required OpenCV libs
#include
/**
@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
< /code>
Dies ist die CPP -Datei: < /p>
/**
@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() >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();
}
Für einige Zeit arbeite ich jetzt mit QT an einer Anwendung, in der ich Rahmen von einer Kamera schnappen muss. Die Kamera wird in einem anderen Faden ausgeführt als der Rest der Anwendung. Ich folgte den Empfehlungen von: http://mayaposch.wordpress.com/2011/11/01/how-toe-really-try-use-qthreads-the-full-explanation / und https://www.qt.io/blog/2010/06/17/youre-doing-it-wrong < /p> Nicht zu subklassen QThread. Stattdessen habe ich ein Worker -Objekt Ccameracapture erstellt und es in ein QThread verschoben. Das Rahmeneinzug der Kamera wird von einem Qtimer gesteuert, der mit einem Grab -Rahmen -Steckplatz verbunden ist. Nachdem die Ccameracapture in den QThread verschoben hat, kann die Erfassungsfestigkeit mit dem Timer gestartet werden. Meine Frage ist: Muss ich Start () der QThread -Klasse anrufen? Mein Ansatz funktioniert, ohne es anzurufen. Die Schleife wird vom Timer durchgeführt und der Arbeiter arbeitet tatsächlich in einem anderen Thread, ohne den Start anzurufen. Ich frage mich also, ob es einen Sinn gibt, Start () anzurufen (), wenn ein Timer verwendet wird. Für die Klarheit habe ich meine Arbeiterklasse unten in der Hauptanwendung erstellt von: < /p> [code]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))); /** < /code> Bis zu diesem Punkt wurde also kein m_cameracapturethread-> start () gerufen, um die Verarbeitungsschleife zu starten. Aber wenn ich Cameracapture-> startgrabbing () nenne, wird es gut funktionieren. Der Timer Grabframe () wird vom Timer ausgelöst und die Frames werden an die Hauptanwendung gesendet. Allerdings alle Codebeispiele, die ich bisher als Start () genannt habe, auch wenn sie Timer verwendeten: z. The-Right-Way-Teil-1/(Verwendung 2-1 am Ende der Seite) Dies ist meine ccameracapture.h: /**
@file CCameraCapture.h @brief this file contains the definition of the 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 < /code> Dies ist die CPP -Datei: < /p> /** @file CCameraCapture.cpp @brief this file contains the function definitions of CCameraCapture. **/
void CCameraCapture::grabFrame(){ qDebug() >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(); } [/code]
Ist es eine gute Vorgehensweise, den Konstruktor dazu zu bringen, eine Ausnahme auszulösen?
Zum Beispiel habe ich eine Klasse „Person“ und ich habe „Alter“ als einziges Attribut. Jetzt
stelle ich die...
Ich habe eine vom Entwickler abgeleitete Klasse , die von der Mitarbeiter-Basisklasse erbt.
In meiner abgeleiteten Klasse habe ich eine Override-Eigenschaft das ein Hintergrundfeld verwendet, das von...
Ich habe nach einem Vorschlag gesucht, dass wir mit Justify-Content: Flex-Start/Start beginnen sollen, anstatt auf lange Sicht Justify-Content: Stretch zu verwenden. Wenn wir die Rechtfertigung in...
Ich habe nach einem Vorschlag gesucht, dass wir mit Justify-Content: Flex-Start/Start beginnen sollen, anstatt auf lange Sicht Justify-Content: Stretch zu verwenden. Wenn wir die Rechtfertigung in...