How to paint sequential image in efficient way in QQuickPaintedItem - qt

For some reason, I needs to wrap opencv VideoCapture in a class which will be used in Qt Quick.
There are two classes, one is Camera, other is CameraView. CameraView inheritd from QQuickPaintedItem.
Camera class will get image periodically. It achieved by QObject::startTimer(int interval). (e.g. If fps of the webcam is 30, the timer interval is 1000 / 30 - 8, 8 is deviation of time). Once Camera has get image, it notifies CameraView to repaint by calling CameraView::Update().
And in CameraView::paint(QPainter *), CameraView will get an copy of image from Camera class and paints this image by call QPainter::drawImage(...).
I got some problems in process of coding:
I try to replace time event with QThread to get image from camera periodically. When I call CameraView::Update() in QThread, CameraView doesn't repaint. What is the problem?
In my laptop, when I make the CameraView painting the image in fullscreen, I found one python program slow down. Is another way to paint image with lower cost and efficient?

How can I efficiently update QML item based on QQuickPaintedItem C++
class? I delegated some preprocesssing to dedicated thread instead of
a timer on UI thread and it does not update the image in QML UI anymore.
It is a mandatory to trigger UI update from UI thread in Qt including QML. Make that CameraView to expose public slot updateImage.
class CameraView : public QQuickPaintedItem
{
Q_OBJECT
Q_DISABLE_COPY(CameraView)
public:
CameraView(QQuickItem* parent = nullptr);
public slots:
void updateImage(const QImage&);
protected:
QImage m_image;
};
CameraView should implement updateImage and paint like that:
void CameraView::updateImage(const QImage& image)
{
m_imageThumb = image; // does shallow copy of image data
update(); // triggers actual update
}
void CameraView::paint(QPainter* painter)
{
painter->drawImage(this->boundingRect(), m_image);
}
ClassOpenCvOnWorkerThread should start its worker thread and expose signalUiUpdate:
OpenCvOnWorkerThread::OpenCvOnWorkerThread()
{
this->moveToThread(&m_workerThread);
// the below will allow communication between threads
connect(this, SIGNAL(signalUiUpdate(QImage)), m_cameraView, SLOT(updateImage(QImage)));
m_workerThread.start();
}
void OpenCvOnWorkerThread::cvRead()
{
QImage image;
// OpenCV details available in your code
// cv::read
// make QImage from frame
// deliver QImage to another thread
emit signalUiUpdate(image);
}
UPDATE: In my own code for similar QML output from "camera" thread I also take care of handling the UI thread stall when it is unable to process video frames so the signal sender knows when not to post video frames. But that worth another question. Or this whole example can be reimplemented without signal and slot but with condition variable.

Related

How to run animation with blocked UI thread in Qt Widgets app?

In QML you can use Animator type to "animate on the scene graph's rendering thread even when the UI thread is blocked."
How can I achieve the same thing for Qt Widgets?
Basically, I want something like:
1) start loading screen / splash-screen
2) start GUI-blocking operation
3) stop loading screen / splash-screen
It is not possible to move the ui-blocking operation to a separate thread (Widgets are being created). I cannot modify this part.
I tried QQuickWidget and QQuickView containing the splash-screen scene with an Animator inside but it didn't work - they got blocked as well.
EDIT: In the separate thread I read the file containing the UI description. Then I recursively create hundreds of Widgets (including QQuickWidgets, QLabels for images, Web views etc.).
Point of the question was to see if there is a "workaround" for that (e.g. displaying the aforementioned QML scene in some separate window with an own event loop). Unfortunately at this point not much more can be done about the overall design of the above.
Probably the widgets you're creating do too much work. You have to specify exactly how many widgets you're creating, and how. Show some example code. In general, the GUI thread is for cooperative multitasking - if you have something that "blocks", break it down into tiny chunks. For example, suppose that you're processing some XML or json file to build the UI. You could have that task do it one widget at a time, and be invoked each time the event loop is about to block (i.e. use a zero-duration "timer" and invert control).
You should also do the maximum possible amount of work outside of the gui thread. I.e. the UI description should be read and converted to an efficient representation that encapsulates the work to be done in the main thread. This conversion has to be done asynchronously.
The simplest way to accomplish that is to encapsulate each widget's creation in a lambda that refers to some context object. Such a lambda would have the signature [...](BatchContext &ctx). The vector of those lambdas would be kept by the CreationContext object as well:
class BatchContext : public QObject {
Q_OBJECT
public:
using Op = std::function<void(CreationContext &)>;
using QObject::QObject;
// useful for Op to keep track of where things go
void push(QWidget *w) { m_stack.push_back(w); }
QWidget *pop() { return m_stack.isEmpty() ? nullptr : m_stack.takeLast(); }
QWidget *top() const { return m_stack.isEmpty() ? nullptr : m_stack.last(); }
int stackSize() const { return m_stack.size(); }
bool stackEmpty() const { return m_stack.isEmpty(); }
Q_SLOT void startExec() {
if (m_execIndex < ops.size())
m_execTimer.start(0, this);
}
template <typename F>
void addOp(F &&op) { m_ops.push_back(std::forward<F>(op)); }
...
private:
QVector<Op> m_ops;
QVector<QWidget *> m_stack;
QBasicTimer m_execTimer;
int m_execIndex = 0;
void timerEvent(QTimerEvent *ev) override {
if (ev->timerId() == m_execTimer.timerId())
if (!exec())
m_execTimer.stop();
}
/// Does a unit of work, returns true if more work is available
bool exec() {
if (m_execIndex < m_ops.size())
m_ops.at(m_execIndex++)(*this);
return m_execIndex < ops.size();
}
};
After the context is created asynchronously, it can be passed to the main thread where you can then invoke startExec() and the widgets will be created one-at-a-time. The stack is but an example of how you might implement one aspect of widget creation process - the tracking of what widget is the "current parent".

QTimer timeout signal not being emitted

I have a subclass of QObject called Updater that I want to use to manage some widgets in my app. I want it to run updateDisp() every 16 ms, so I created a QTimer in the constructor and connected the timeout signal to the updateDisp() slot. However, updateDisp() never runs, and I can't for the life of me figure out why.
in updater.h:
class Updater : public QObject {
Q_OBJECT
ToUpdate* toUpdate;
QTimer* timer;
...
public slots:
void updateDisp();
};
in updater.cpp:
Updater::Updater(ToUpdate* t, QObject *parent)
: QObject(parent) {
toUpdate = t;
timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(updateDisp()));
timer->setInterval(16);
timer->start();}
I instantiate an Updater object in MainWindow.cpp. Also, I have the GUI thread separate from main() (using winapi CreateThread()); I've seen some other posts about problems with QTimers and QThreads but obviously this is a bit different.
There's some similar issues.
I'd a similar problem in the past: https://github.com/codelol/QtTimer/commit/cef130b7ad27c9ab18e03c15710ace942381c82a#commitcomment-10696869
Basically it seems that Qt5 timer doesn't work as expected while in background, it's sync with the animation timer... which doesn't run often while in background.
This guy solved a similar issue setting the timer type to Qt::PreciseTimer
https://github.com/codelol/QtTimer/commit/cef130b7ad27c9ab18e03c15710ace942381c82a#commitcomment-10696869
timer->setTimerType(Qt::PreciseTimer);
The description of the timer types: http://doc.qt.io/qt-5/qt.html#TimerType-enum
Qt::PreciseTimer 0 Precise timers try to keep millisecond accuracy
Not sure if they're the exactly same problem, but you can give a try on that.

QT GUI freezes when capturing video from webcam using OpenCV

I am using Opencv for some real-time video processing.
As a front-end I am using QT framework.
On my GUI, I have an input image window (mapped to a Label) and an output image window (mapped to another Label) and 3 push buttons. One to Start input video capture, the second to process the video (code not written yet), and third to Exit.
I am currently able to stream my video and display it on the Front-end. But this locks my GUI and am unable to Exit.
I tried using QTimers (using suggestions from this and the QT forum), but my GUI still remains locked.
Would appreciate if someone can point my in the right direction.
Below is the code:
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
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
cvReleaseImage(&frame);
cvReleaseCapture(&capture);
}
void MainWindow::on_buttonCaptureVideo_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);
while(capture)
{
// Capture a frame
frame = cvQueryFrame(capture);
// Point to the same frame
source_image = frame;
// Resize Image
cv::resize(source_image, source_image, cv::Size(128,128) , 0, 0);
// Change to RGB format
cv::cvtColor(source_image,source_image,CV_BGR2RGB);
// Convert to QImage
QImage qimg = QImage((const unsigned char*) source_image.data, source_image.cols, source_image.rows, QImage::Format_RGB888); // convert to QImage
// Display on Input Label
ui->labelInputVideo->setPixmap(QPixmap::fromImage(qimg));
// Resize the label to fit the image
ui->labelInputVideo->resize(ui->labelInputVideo->pixmap()->size());
}
}
void MainWindow::on_buttonExit_clicked()
{
connect(ui->buttonExit, SIGNAL(clicked()), qApp, SLOT(closeAllWindows()));
}
When you click your button, the
while(capture) { ... }
loop will run forever, as capture will never be set to NULL.
This means the code flow never leaves your loop and thus the main thread cannot process anything else, like e.g. repainting.
The QTimer will emit its timeout() signals, but they will be placed as Events in Qt's Event Queue. As long as your on_buttonCaptureVideo_clicked() method is running, those Events will not be processed.
Here are my suggestions how to make it work:
This code:
// 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);
belongs into the constructor of MainWindow as you want to set that up one time only. There is no need to do it again when the user clicks the button the second, third, etc time.
The code which is within your while loop should go into the doNextFrame() slot (without the while construct).
Then your button will only do
imageTimer->start();
and then e.g. do
imageTimer->stop();
when it is clicked again.
Example code:
void MainWindow::on_buttonCaptureVideo_clicked()
{
if( imageTimer->isActive() )
{
imageTimer->stop();
}
else
{
imageTimer->start();
}
}
What will happen if you do that?
When you click the button, your on_buttonCaptureVideo_clicked() clicked slot will be called from the GUI thread, the timer will be started, and the method will return almost instantly.
Now the GUI thread is free and able to handle repaints etc.
From that point on, the timer will be sending timeout() signals every 40ms. Whenever the GUI thread is free, it will handle this signal and call your doNextFrame slot.
This slot will capture the next frame and return when it is done. When it is done, the GUI thread will be able to process other Events (e.g. repaint) again.
As soon as you click the button again, the timer will stop, and no new timeout() events will be sent. If you still see a couple of frames after the button has been clicked, this could mean that the timer events were sent faster than they could be processed.
Preface: I am not strong in C++ so I cannot offer specific code, but I am experienced in PyQt
This is a common pitfall for newcomers to Qt. What it seems your on_buttonCaptureVideo_clicked is doing is entering into a loop in your main GUI thread to do work. In QT, you want to avoid doing anything busy in your main thread. The Qt eventloop needs to be able to constantly process and flush your GUI events as they come in. What you are doing is blocking the event loop.
There are two different things you can do here. The first is the more basic approach but allows you to see more immediate results. You can "pump" the eventloop. Depending on how fast your while loop iterates, you can call qApp->processEvents();. This will allow Qt to process the pending GUI events and make your app appear more responsive. Its basically sharing time between your while loop and the main loop. Maybe you want to call this on every nth frame. Depends how often you want to make sure the GUI refreshes.
The other option, which is more preferable, is to place your capture loop into a QThread. When a new frame is available you can emit a signal with the frame data. The signal will get placed into the Qt event loop to be processed with everything else and will not hold up your GUI. Generally this is the approach you want to take with any heavy crunching or long running callables.
Edit
I just realized that you start a QTimer in addition to doing a loop in the main thread. If you want to use a QTimer, and your image processing is not too heavy (it doesn't take long per cycle) then you should move everything into the doNextFrame and completely remove the while loop. If your doNextFrame is a heavy process, then you should be using a QThread and signals.

Passing signals through hierarchies

I am having some difficulty fully grasping how signals and slots are used in Qt. I am sure it is really basic but I'm just no getting it today.
I have a set of widgets a bit like this:
MainWindow
-->StackedWidget
-->ChildForms
Now the idea is that there are some actions on the Child widgets that will cause the stacked widget to display a different page.
So if I understand it properly I thought the way to connect signals and slots is to use the connect() at the scope that knows about the objects but what I have managed to get working doesn't do it this way. At the moment in my child form I use parentWidget() to access the slot of the StackedWidget but I am not very happy with really because it is giving the child information about the parent which it shouldn't have:
void TaskSelectionForm::setButtonMappings()
{
// Set up a mapping between the buttons and the pages
QSignalMapper *mapper = new QSignalMapper(this);
connect(mapper, SIGNAL(mapped(int)), parentWidget(), SLOT(setCurrentIndex(int)));
mapper->setMapping(ui->utilitiesButton, 2); // Value of the index
connect(ui->utilitiesButton, SIGNAL(clicked()), mapper, SLOT(map()));
}
But I am not really sure how I should do this and connect it up. Do I need to have signals at each level and emit through the tree?
A Bit of Signal-Slot Theory
The signal-slot connections are oblivious to parent-child relationships between QObjects, and any such relationship doesn't matter. You're free to connect objects to their children, to their siblings, to their parents, or even to QObjects that are in a separate hierarchy, or to lone QObjects that have neither parents nor children. It doesn't matter.
A signal-slot connection connects a signal on a particular instance of QObject to slot on another instance of QObject. To use the connect method, you need the pointers to the instance of sender QObject and the instance of receiver QObject. You then use the static QObject::connect(sender, SIGNAL(...), receiver, SLOT(...)). Those connections have nothing to do with any hierarchy there is between the sender and receiver.
You can also connect a signal to a signal, to forward it -- for example from a private UI element to a signal that's part of the API of the class. You cannot connect a slot to a slot, because it'd incur a bit of runtime overhead for a rarely-used case. The overhead would be an extra bool member in QObjectPrivate, plus a failed if (bool) test. If you want to forward slots to slots, there are at least two ways to do it:
Emit a signal in the source slot and connect that signal to the destination slot.
Obtain a list of all signals connected to the source slot, iterate on it and connect them to to the target slot. There's no easy way to maintain such connections when further signals are connected or disconnected from the source slot. Unfortunately, QObject only has a connectNotify(const char*) protected function, but not a signal -- so you can't hook up to it unless you would modify src/corelib/kernel/qobject[.cpp,_p.h,.h] to emit such a signal. If you truly need it, just modify the Qt source, you have access it for a reason, after all. Hacking the vtable without modifying Qt is possible, but discouraged for obvious reasons.
The Answer
Below is a self contained example that shows how to do what you want. Turns out I have answers to quite a few questions from my various experiments I've done in Qt in the past. I'm a packrat when it comes to test code. It's all SSCCE to boot :)
// https://github.com/KubaO/stackoverflown/tree/master/questions/signal-slot-hierarchy-10783656
#include <QtGui>
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
#include <QtWidgets>
#endif
class Window : public QWidget
{
QSignalMapper m_mapper;
QStackedLayout m_stack{this};
QWidget m_page1, m_page2;
QHBoxLayout m_layout1{&m_page1}, m_layout2{&m_page2};
QLabel m_label1{"Page 1"}, m_label2{"Page 2"};
QPushButton m_button1{"Show Page 2"}, m_button2{"Show Page 1"};
public:
Window(QWidget * parent = {}) : QWidget(parent) {
// the mapper tells the stack which page to switch to
connect(&m_mapper, SIGNAL(mapped(int)), &m_stack, SLOT(setCurrentIndex(int)));
// Page 1
m_layout1.addWidget(&m_label1);
m_layout1.addWidget(&m_button1);
// tell the mapper to map signals coming from this button to integer 1 (index of page 2)
m_mapper.setMapping(&m_button1, 1);
// when the button is clicked, the mapper will do its mapping and emit the mapped() signal
connect(&m_button1, SIGNAL(clicked()), &m_mapper, SLOT(map()));
m_stack.addWidget(&m_page1);
// Page 2
m_layout2.addWidget(&m_label2);
m_layout2.addWidget(&m_button2);
// tell the mapper to map signals coming from this button to integer 0 (index of page 1)
m_mapper.setMapping(&m_button2, 0);
connect(&m_button2, SIGNAL(clicked()), &m_mapper, SLOT(map()));
m_stack.addWidget(&m_page2);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Window w;
w.show();
return a.exec();
}
Connect(stackedwidget->currentactivewidget,SIGNAL(OnAction()),this,SLOT(PrivateSlot()));
PrivateSlot() is a slot declared privately. So in this function, you can add your code to change the page of stackedwidget corresponding to the action produced by currentactivewidget.
Again if you really want to pass the signal up the heirarchy, emit a publicsignal() at the end of private slot function.
Connect(this,SIGNAL(publicsignal()),Parentwidgetofstackedwidget(here mainwindow),SLOT(mainwindow_slot()));

Qt Modeless Dialog Destruction

From what I understand to make dialog Modeless you have to allocate it on the heap. By Doing something like this:
MyDialog* dlg = new MyDialog(this);
dlg->show();
dlg->raise();
Since exec() ignores Modal Property. However now there is a memory leak since nothing deallocates memory pointed to by dlg pointer until the application is closed. I found one solution here http://tinf2.vub.ac.be/~dvermeir/manuals/KDE20Development-html/ch08lev1sec3.html#ch08list09 at the end of the page and was wondering whether there was a less cumbersome way having Modeless dialog.
You can use the attribute Qt::WA_DeleteOnClose to destroy the window when it is closed/hidden, and QWeakPointer (or QPointer) with a static variable to track the existence of the window inside the slot/function which opens it:
void MyWindow::openDialog() {
static QWeakPointer<MyDialog> dlg_;
if (!dlg_)
dlg_ = new MyDialog(this);
MyDialog *dlg = dlg_.data();
dlg->setAttribute(Qt::WA_DeleteOnClose);
dlg->show();
dlg->raise();
dlg->activateWindow();
}
I'd schedule it for deletion at the time it's work is finished by using deleteLater:
void MyDialog::MyDialog(QWidget *parent) {
// ...
connect(this, SIGNAL(finished(int)), SLOT(deleteLater)));
}
This approach will preclude you from examining it after the finished signal has been emitted (unless you can guarantee that any accesses happen before everything gets back to the event loop when the deletion is actually performed).
Personally, I would choose between either using
dlg->setAttribute(Qt::WA_DeleteOnClose);
or making the dialog a -dynamically allocated- member i.e. creating it only once:
// constructor
: dialog_(0)
// member function
{
if (! dialog_)
dialog_ = new MyDialog(this);
dialog_->show();
dialog_->raise();
}
This way the dialog is deleted when the parent dies, and only needs to be constructed once.

Resources