Webcam im QThread laufen lassen
Verfasst: 17. Februar 2013 13:41
Hallo,
eigentlich ein simples Problem, aber ich bin neu bei Qt und total am verzweifeln, seit ich versuche mit QThread zu arbeiten. Ich möchte einfach nur Frames von der Webcam in einem Thread kontinuierlich abrufen und in einem Fenster anzeigen lassen. Dieses Fenster wird in der Hauptanwendung geöffnet, wenn man auf einen Button drückt. Ich versuche jetzt schon über 40 Stunden versucht es zum laufen zu bekommen, aber es treten immer wieder unterschiedliche Probleme auf. Hinzu kommt, dass im Netz die unterschiedlichsten und oft auch falsche Lösungen zu diesem Thema existieren. Einige schreiben, dass man in den seltenstenfällen QThread subclassen muss/sollte und 10 andere Blogbeispiele machen genau das. Dann gibt es andere die mit Timer Konzepten arbeiten und und und. Bisher habe ich keinen der Ansätze zum laufen gebracht und meinen Code unzählige male umgeschrieben. Jetzt weiß ich einfach nicht weiter. Hier ermstmal mein Code, wie er im Moment aussieht. Ich habe zwei Klassen: VideoThread, soll das Capturen durchführen und WebcamWidget soll die Frames anzeigen. Hier erstmal VideoCapture:
Hier die dazugehörige Definition:
Mir ist schon klar, dass VideoCapture nach dem Start in einer Endlos-Schleife läuft. Mein Problem ist jetzt, dass ich, wenn das WebcamWidget geschlossen wird, der Thread nicht gestoppt werden kann, da er in der Schleife läuft. Egal ob die Schleife durch while, oder signals/slots aufbaue, sie lässt sich nciht unterbrechen. Auch eine Lösung mit QMute, wie in http://thesmithfam.org/blog/2010/02/07/ ... t-threads/ vorgeschlagen hat nicht funktioniert, wobei ich mir unsicher war, ob seine von QThread abgeleitet Klasse war. In WebcamWidget Klasse erzeuge ich einen QThread und stelle die benötigten Verbindungen her:
Hier habe ich lage über die Verbindung:
nachgedacht. Es wird nur das Bild der Webcam angezeigt, wenn Qt::BlockingQueuedConnection oder DirectConnection verwendet wird - so ganz richtig scheint mir das nicht zu sein. closeCapture() wird gesendete, wenn das Fenster geschlossen wird. Hierdurch soll der Thread in dem die Webcam läuft beendet werden. Das funktioniert momentan noch garnicht, da VideoThread nicht auf das Signal reagiert. Setze ich einen Breakpoint in void VideoThread::close(), sehe ich das diese bei Fensterschließen nicht aufgerufen wird, obwohl das emit in webcamwidget ausgeführt wurde.
Ich weiß gerade nicht richtig, wie ich weitermachen soll. Muss ich mein VideoThread jetzt von QThread ableiten, um das umzusetzten, was ich möchte, oder kann ich das auch machen, ohne QThread zu subclassen? Wie kann ich meinen Thread dazu bringen auf Signale von webcamwidget, z.B. close zu reagieren? Auch erscheint mir die Endlosschleife nicht ganz richtig, da die ja vermutlich das Behandeln von Signalen blockiert und jegliche Interaktion mit dem Thread verhindert. Wie kann ich dann aber mit einem Prozess kommunizieren, der kontinuierlich im Hintergrund läuft und nicht, wie in den meisten Beispielen im Netz ein finished() sendet?
Ich bin dankbar für jeden Tipp! Gruß Jan
eigentlich ein simples Problem, aber ich bin neu bei Qt und total am verzweifeln, seit ich versuche mit QThread zu arbeiten. Ich möchte einfach nur Frames von der Webcam in einem Thread kontinuierlich abrufen und in einem Fenster anzeigen lassen. Dieses Fenster wird in der Hauptanwendung geöffnet, wenn man auf einen Button drückt. Ich versuche jetzt schon über 40 Stunden versucht es zum laufen zu bekommen, aber es treten immer wieder unterschiedliche Probleme auf. Hinzu kommt, dass im Netz die unterschiedlichsten und oft auch falsche Lösungen zu diesem Thema existieren. Einige schreiben, dass man in den seltenstenfällen QThread subclassen muss/sollte und 10 andere Blogbeispiele machen genau das. Dann gibt es andere die mit Timer Konzepten arbeiten und und und. Bisher habe ich keinen der Ansätze zum laufen gebracht und meinen Code unzählige male umgeschrieben. Jetzt weiß ich einfach nicht weiter. Hier ermstmal mein Code, wie er im Moment aussieht. Ich habe zwei Klassen: VideoThread, soll das Capturen durchführen und WebcamWidget soll die Frames anzeigen. Hier erstmal VideoCapture:
Code: Alles auswählen
#pragma once
#ifndef VIDEOTHREAD_H
#define VIDEOTHREAD_H
#include <QObject>
#include <QtWidgets/QMainWindow>
#include<opencv2\opencv.hpp>
class VideoThread : public QObject
{
Q_OBJECT
public:
VideoThread();
~VideoThread();
public slots:
void process();
void close();
void getFrame();
signals:
void finished();
void error(QString err);
void updateFrame(cv::Mat img);
void getNextFrame();
private:
cv::VideoCapture m_Cap;
cv::Mat m_Frame;
bool m_EndCapture;
};
#endif // VIDEOTHREAD_H
Code: Alles auswählen
#pragma once
#include "videothread.h"
#include <QTimer>
#include<qthread.h>
#include<QEvent>
VideoThread::VideoThread():m_EndCapture(0)
{
connect(this, SIGNAL(getNextFrame()), this, SLOT(getFrame()));
}
VideoThread::~VideoThread()
{
}
void VideoThread::process(){
m_Cap.open(0);
emit getNextFrame();
}
void VideoThread::close(){
m_EndCapture=true;
}
void VideoThread::getFrame(){
m_Cap>>m_Frame;
emit updateFrame(m_Frame);
emit getNextFrame();
}
Code: Alles auswählen
void webcamwidget::startCam(){
//start video thread
camRunning=true;
m_Thread = new QThread;
videoThread = new VideoThread();
videoThread->moveToThread(m_Thread);
connect(videoThread, SIGNAL(error(QString)), this, SLOT(errorString(QString)));
connect(m_Thread, SIGNAL(started()), videoThread, SLOT(process()));
connect(videoThread, SIGNAL(finished()), m_Thread, SLOT(quit()));
connect(videoThread, SIGNAL(finished()), videoThread, SLOT(deleteLater()));
connect(m_Thread, SIGNAL(finished()), m_Thread, SLOT(deleteLater()));
connect(videoThread, SIGNAL(updateFrame(cv::Mat)), this, SLOT(updateFrameC(cv::Mat)),Qt::BlockingQueuedConnection);
connect(this, SIGNAL(closeCapture()), m_Thread, SLOT(close()));
m_Thread->start();
}
Code: Alles auswählen
connect(videoThread, SIGNAL(updateFrame(cv::Mat)), this, SLOT(updateFrameC(cv::Mat)),Qt::BlockingQueuedConnection);
Ich weiß gerade nicht richtig, wie ich weitermachen soll. Muss ich mein VideoThread jetzt von QThread ableiten, um das umzusetzten, was ich möchte, oder kann ich das auch machen, ohne QThread zu subclassen? Wie kann ich meinen Thread dazu bringen auf Signale von webcamwidget, z.B. close zu reagieren? Auch erscheint mir die Endlosschleife nicht ganz richtig, da die ja vermutlich das Behandeln von Signalen blockiert und jegliche Interaktion mit dem Thread verhindert. Wie kann ich dann aber mit einem Prozess kommunizieren, der kontinuierlich im Hintergrund läuft und nicht, wie in den meisten Beispielen im Netz ein finished() sendet?
Ich bin dankbar für jeden Tipp! Gruß Jan