How to Efficiently Draw a QImage to a Window.
-
wrote on 21 Feb 2016, 21:04 last edited by
I need to efficiently draw a QImage to a widget several times per second. I had planned to put the draw code in the Widget's paintEvent routine and call update on a timer, as shown here:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { // Set a timer to update the displayed image every 50 ms QTimer *timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(update())); timer->start(50); } void MainWindow::paintEvent(QPaintEvent *event) { }
But on my computer (2015 MacBook Pro) this uses 20-25% CPU, which seems rather high. Is there a more efficient way to do draw a QImage to a widget?
-
Hi and welcome to devnet,
You need to provide more details before talking optimization. What kind of image is that ? What size ? How are you loading it ? Why do you need to redraw so quickly ?
-
wrote on 21 Feb 2016, 21:33 last edited by
Size is 800x600. Kind is QImage, "loaded" with
new QImage(800, 600, QImage::Format_ARGB32);
. I'm drawing shapes/applying effects to them to synthesise video. All of these manipulations individually have little discernible impact on CPU utilisation except for drawing to the widget. -
Ok, then since you are drawing anyway, why not draw directly on the widget ?
On a side note, there's rarely need to allocate a QImage on the heap, why to you need to do it ?
-
wrote on 21 Feb 2016, 21:51 last edited by
I don't understand what you mean by "draw directly" - I thought it was only possible to draw to widgets in paintEvent().
-
Let me reformulate: since you are drawing your QImage on the widget, do you really need to pass by a QImage ? Can't you do the same drawing directly on the widget ?
-
wrote on 21 Feb 2016, 22:05 last edited by
In my case I don't think so. But even if I could I don't see how that would help - the significant computational cost seems to be in getting paintEvent() to run in the first place, not initialising, manipulating or drawing QImages.
-
If you could that would mean you don't have to allocate a QImage each time you call paint event which in itself is already a gain.
You should also rather work on a QPixmap since you're going to draw it, QPixmap is optimized for showing image on screen while QImage is optimized for IO and direct pixel access.
What operations do you need to do exactly ?
-
wrote on 21 Feb 2016, 22:24 last edited by
I think we're getting a little distracted trying to optimise the system instead of the drawing.
Assuming that I could draw directly to a widget and therefore had no need for QImages or QPixmaps, I might be able to express that like this:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); QTimer *timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(update())); timer->start(50); } void MainWindow::paintEvent(QPaintEvent *event) { QPainter painter(this); painter.drawLine(QPointF(10, 10), QPointF(20, 20)); painter.end(); }
This uses 25% CPU, which seems like a lot just to draw a short line segment. How could this simple example be optimised (if at all)?
-
Is your application painting static content ? If so, then don't trigger update that much, there's no real need.
paintEvent will be called when needed so with your last sample, calling update every 50ms is useless and power consuming.
-
wrote on 21 Feb 2016, 22:41 last edited by
Ok, so that may not have been a great example. In reality it will be dynamic content, so I really do need a frequent screen refresh. This is a slightly more representative example:
int x = 0; void MainWindow::paintEvent(QPaintEvent *event) { if (x > 500) x = 0; QPainter painter(this); painter.drawLine(QPointF(10, 10), QPointF(x++, x++)); painter.end(); }
-
Do you need some kind of graph ?
-
wrote on 22 Feb 2016, 00:05 last edited by
No, it's arbitrary shapes.
-
Is there some kind of history for these shapes are do you need to re-draw them all every time ?
-
wrote on 22 Feb 2016, 14:07 last edited by
Need to redraw.
-
The first thing I'd do is optimize the data sent e.g. do you really need to build a line of 500 points if you already know the final coordinates ?
Otherwise, maybe consider using OpenGL
-
wrote on 23 Feb 2016, 23:42 last edited by
So to confirm: there's no way to draw in Qt without invoking the relatively expensive update() first?
-
Yes there is, do the drawing in another thread on a QImage and then trigger the update with that image. You have an example of this in the Mandelbrot example
-
Yes there is, do the drawing in another thread on a QImage and then trigger the update with that image. You have an example of this in the Mandelbrot example
10/19