Using a label to display large images in QT GUI



  • Hi guys,

    My application does live processing of images using OpenCV and shows the result on an output display / monitor. I'm using a 'label' for this, first converting my OpenCV matrix to a QImage and then I use that QImage to create a pixmap for the label. It works ok for small labels but if the label is covering the entire size of say a 1920 x 1080 display, setting the pixmap slows everything down by a factor of 6 which is inhumane (it goes from processing time of ~10 mS to ~60 mS).

    Can anyone else confirm that this is the case?

    Is there a faster way of doing this using another type of widget perhaps? OpenGL?

    This is what I'm doing at the moment (videoFrameOut is my OpenCV matrix):

    image = QImage((uchar*)(videoFrameOut.data),videoFrameOut.cols,videoFrameOut.rows, QImage::Format_RGBA8888);
    
    ui -> oLabel -> setAlignment(Qt::AlignCenter);
    ui -> oLabel -> setPixmap(QPixmap::fromImage(image.scaled(QSize(ui->oLabel->width(),ui->oLabel->height()), Qt::KeepAspectRatio, Qt::FastTransformation)));
    

  • Lifetime Qt Champion

    Hi,

    Something is not completely clear, are you always resizing to a smaller version of the image for displaying ?


  • Moderators

    The first line is nice because it just creates Qt interface over the foreign data without any copies. Unfortunately the rest of it is not as nice.
    I'd say the performance is killed by the amount of copies and resizing you're doing: image.scaled does scaling and creates new buffer, QPixmap::fromImage does another copy, setPixmap is another (potential) copy and then setting that pixmap on a label causes it to re-layout itself and do all sorts of bookkeeping.

    Without going into hardware acceleration (OpenGL or Vulkan) the low hanging fruit is avoiding all those copies.
    Instead of a label inherit a plain QWidget, override paintEvent and draw the image directly with QPainter::drawImage. It will do the scaling and draw on the fly without all those expensive copies.



  • @sgaist I have a few small-sized labels of ~130x130 pixels which display a scaled down image (usually 1280x720 or 1920x1080). The bigger label which covers an entire display is what is causing the performance drop. Not knowing whats going on under the hood I would have imagined that downsizing to the smaller labels would be the bottleneck but its the other way round.

    @Chris-Kawa That makes sense, I'll try that.

    There doesn't seem to be any way to set the pixmap from raw data similar to what I'm doing with the QImage, at least not with a uchar array outside of a file, is that right?



  • An update on this. It works perfectly and its a very low-cost solution. My processing time remains almost the same (~10mS) using this method since the painter does the scaling for you when it draws.

    Thanks for your help guys.