user2950911
user2950911

Reputation: 933

Efficient way of displaying a continuous stream of QImages

I am currently using a QLabel to do this, but this seems to be rather slow:

void Widget::sl_updateLiveStreamLabel(spImageHolder_t _imageHolderShPtr) //slot
{
    QImage * imgPtr = _imageHolderShPtr->getImagePtr();
    m_liveStreamLabel.setPixmap( QPixmap::fromImage(*imgPtr).scaled(this->size(), Qt::KeepAspectRatio, Qt::FastTransformation) );
    m_liveStreamLabel.adjustSize();
}

Here I am generating a new QPixmap object for each new image that arrives. Since QPixmap operations are restricted to the GUI Thread, this also makes the GUI feel poorly responsive.
I've seen there are already some discussions on this, most of them advising to use QGraphicsView or QGLWidget, but I have not been able to find a quick example how to properly use those, which would be what I am looking for.
I'd appreciate any help.

Upvotes: 5

Views: 2671

Answers (3)

Pavel Strakhov
Pavel Strakhov

Reputation: 40512

QPixmap::fromImage is not the only problem. Using QPixmap::scaled or QImage::scaled also should be avoided. However you can't display QImage directly in QLabel or QGraphicsView. Here is my class that display QImage directly and scales it to the size of the widget:

Header:

class ImageDisplay : public QWidget {
  Q_OBJECT
public:
  ImageDisplay(QWidget* parent = 0);
  void setImage(QImage* image);

private:
  QImage* m_image;

protected:
  void paintEvent(QPaintEvent* event);

};

Source:

ImageDisplay::ImageDisplay(QWidget *parent) : QWidget(parent) {
  m_image = 0;
  setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
}

void ImageDisplay::setImage(QImage *image) {
  m_image = image;
  repaint();
}

void ImageDisplay::paintEvent(QPaintEvent*) {
  if (!m_image) { return; }
  QPainter painter(this);
  painter.drawImage(rect(), *m_image, m_image->rect());
}

I tested it on 3000x3000 image scaled down to 600x600 size. It gives 40 FPS, while QLabel and QGraphicsView (even with fast image transformation enabled) gives 15 FPS.

Upvotes: 5

TheDarkKnight
TheDarkKnight

Reputation: 27621

Setting up a QGraphicsView and QGraphicsScene is quite straight-forward: -

int main( int argc, char **argv )
{
    QApplication app(argc, argv);

    // Create the scene and set its dimensions
    QGraphicsScene scene;
    scene.setSceneRect( 0.0, 0.0, 400.0, 400.0 );

    // create an item that will hold an image
    QGraphicsPixmapItem *item = new QGraphicsPixmapItem(0);

    // load an image and set it to the pixmapItem
    QPixmap pixmap("pathToImage.png") // example filename pathToImage.png
    item->setPixmap(pixmap);

    // add the item to the scene
    scene.addItem(item);

    item->setPos(200,200); // set the item's position in the scene

    // create a view to look into the scene
    QGraphicsView view( &scene );
    view.setRenderHints( QPainter::Antialiasing );
    view.show();

    return app.exec();
}

Upvotes: 1

Marek R
Marek R

Reputation: 38062

I recommend not use QLabel but write own class. Every call of setPixmap causes layout system to recalculate sizes of items and this can propagate to topmost parent (QMainWindow) and this is quite big overhead.

Conversion and scaling also is a bit costly.

Finally best approach is to use profiler to detect where is the biggest problem.

Upvotes: 0

Related Questions