PDA

View Full Version : Pausing a Thread running an infinite loop (Qt+OpenCV)



franco.amato
28th October 2019, 16:41
Good morning community,
I am developing an OpenCV and Qt based app where I detect the genre of the person looking to a camera, and I fire a script if the detected gender is "Male" and another script if "Female".
To detect face and gender I use a caffe model and the OpenCV inference engine. To prevent the GUI from freezing, i decided to use a separate thread for camera frames processing but my poor experience in multithreading is giving me some problems. Reading some articles seems that the correct way to use QThreads is using moveToThread function.

This is the basic structure of my program:


GDWidget.h



..code..
private:
Ui::GDWidget *ui;
cv::VideoCapture m_capture;

cv::Mat m_currentFrame;

// for capture thread
QMutex *m_dataLock;
GDDetector *m_worker;
QThread *m_thread;

QString m_maleUrl = "https://app.onsign.tv/play/u0mAM5ju0R9cP4R5wr6L?repeat=1";
QString m_femaleUrl = "https://app.onsign.tv/play/Q0CoHhopjpr8l1IaxC7v?repeat=1";
};


GDWidget.cpp


void GDWidget::openCamera()
{
int camIdx = 0;
m_worker = new GDDetector(this, camID, m_dataLock);
m_thread = new QThread;
m_worker->moveToThread(m_thread);
connect(m_worker, &GDDetector::frameCaptured, this, &GDWidget::updateFrame);

connect(m_thread, SIGNAL(started()), m_worker, SLOT(processFrame()));
connect(m_worker, SIGNAL(finished()), m_thread, SLOT(quit()));
connect(m_worker, SIGNAL(finished()), m_worker, SLOT(deleteLater()));
connect(m_thread, SIGNAL(finished()), m_thread, SLOT(deleteLater()));
thread->start();
m_worker->start();
}

In my processFrame() i have an infinite loop (that stops when I set to true a variable). My problem is that I would get the thread paused ( for 10 seconds ) when I detect the person gender.


void GDDetector::processFrame()
{
m_running = true;
m_capture.open(m_cameraIdx);
cv::Mat tmp_frame;

..code ..

while(m_running)
{
m_capture >> tmp_frame;
if (!tmp_frame.empty())
{
detectFace(tmp_frame);

m_dataLock->lock();
cvtColor(tmp_frame, m_sourceFrame, cv::COLOR_BGR2RGB);
m_dataLock->unlock();

emit frameCaptured(&m_sourceFrame);
}

///// I WOULD PAUSE THIS LOOP WHEN I GET A SPECIFIC RESULT FROM THE detectFace ROUTINE ///
}

emit processFinished();

m_capture.release();
m_running = false;
}

I would have a help in pausing the infinite loop when i detect the gender. Also I would know how to move my code to QtConcurrent module but I don't know how.
Any help will be appreciated

Regards

^NyAw^
28th October 2019, 17:38
Hi,

If you only want to wait for 10 seconds you can call "msleep" method from a QThread. So, add this code on line 23:


QThread::currentThread()->msleep(10000);

d_stranz
28th October 2019, 19:28
If you only want to wait for 10 seconds you can call "msleep" method from a QThread. So, add this code on line 23:

It is generally a bad idea (and a sign of a design that needs some more thinking) to add pauses of this sort to any program. Not only does it lock the thread during the sleep call, the choice of the delay period is usually arbitrary and dependent on particular hardware.

If the OP's issue is that he does not want to perform any more face detection while the current face is being processed, then the solution should not be to pause the loop, but probably not to use an infinite loop at all. Instead, it would be better to start and stop the frame capture using some kind of handshaking mechanism between capturing and processing, or use a QTimer to trigger capture every "n" seconds, or some similar method.

It might be helpful to draw something like a UML timing diagram (https://www.uml-diagrams.org/timing-diagrams.html) with the various steps in the process.

^NyAw^
29th October 2019, 08:43
It is generally a bad idea (and a sign of a design that needs some more thinking) to add pauses of this sort to any program. Not only does it lock the thread during the sleep call, the choice of the delay period is usually arbitrary and dependent on particular hardware.

If the OP's issue is that he does not want to perform any more face detection while the current face is being processed, then the solution should not be to pause the loop, but probably not to use an infinite loop at all. Instead, it would be better to start and stop the frame capture using some kind of handshaking mechanism between capturing and processing, or use a QTimer to trigger capture every "n" seconds, or some similar method.

It might be helpful to draw something like a UML timing diagram (https://www.uml-diagrams.org/timing-diagrams.html) with the various steps in the process.

Totally agree. But he asked to wait for 10 seconds.
I used to use other mechanisms like QWaitCondition to let the thread go sleep and wake up when some condition is triggered and synchronize multiple threads.

d_stranz
29th October 2019, 23:10
Totally agree. But he asked to wait for 10 seconds.

Yes, true, you did answer the question. QWaitCondition might be a good solution for this, or some kind of state machine.