使用Qt显示图像流

时间:2016-07-26 09:04:21

标签: c++ qt opengl

目前的解决方案如下:

//paintlabel.h
class PaintLabel : public QWidget
{
    Q_OBJECT

public:
    explicit PaintLabel(QWidget *parent = 0);

public slots:
    void setImage(char *img_ptr, QSize img_size, int pitch);

protected:
    void paintEvent(QPaintEvent *event) override;

private:
    QImage image;

}

//paintlabel.cpp

PaintLabel::PaintLabel(QWidget *parent) : QWidget(parent)
{
    setAttribute(Qt::WA_NoSystemBackground, true);
}

void PaintLabel::setImageLive(char *img_ptr, QSize img_size, int pitch)
{
    image = QImage((uchar *)img_ptr, img_size.width(), img_size.height(), pitch, QImage::Format_RGB32).scaled(this->size());
    update();  
}

void PaintLabel::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);
    QPainter painter;
    painter.begin(this);
    if (!image.isNull()) {
        const QPoint p = QPoint(0,0);
        painter.drawImage(p, image);
    }
    painter.end();
}

我希望每秒20-40帧。问题是,性能随着大小而变得非常糟糕。在全高清的范围内,这幅画需要1-2毫秒。但是,如果我将它调整为4k,它会变得非常迟钝(16毫秒绘画)。有没有办法实现相同的功能,但资源消耗更少?

理论上,如果我将父类更改为QOpenGLWidget,则QPainter将使用硬件加速运行。但是这样做,它运行得更慢。

1 个答案:

答案 0 :(得分:3)

首先,代码中的一个限制因素似乎是scaled()函数。试着把它取出来,你应该看到一些加速。

其他问题只是QImage性能的限制。有关更多信息,请参阅此问题。 How can QPainter performance be improved?

  

QPainter将使用软件光栅化器绘制QImage实例。

请参阅http://doc.qt.io/qt-5/topics-graphics.html以获取更多信息。

你不能去QPixmap,因为你的整个缓冲区也会改变每一帧。

您可以尝试使用QOpenGLPaintDevice使QPainter使用硬件加速。您尝试的另一种方法是QOpenGLWidget

  

QOpenGLWidget - 也可以在QOpenGLWidget上打开画家。这是为了方便起见,因为从技术上讲,这与使用QOpenGLPaintDevice没什么不同。

参考上面的相同qt链接。

所以是的,这在技术上应该更快,但是因为你正在调整Widget的大小从而调整OpenGL Viewport的大小,所以每次都会重新生成底层缓冲区。因此减速更多。请注意,QOpenGLWidget本身可以处理glViewport()等一些函数。当您尝试优化性能时,这没有用。

以下是一些建议

  1. 我认为主要问题是QImage的处理。我建议您设置自己的OpenGL场景,只需使用一个四边形来渲染纹理,然后尝试每帧写入纹理。缩放将在GPU上处理,因此肯定会更快。

  2. 或者,您可以使用glDrawPixels()将图像从主机内存(RAM)渲染到帧缓冲区。虽然这不会为您处理缩放。有关详细信息,请参阅https://www.opengl.org/sdk/docs/man2/xhtml/glDrawPixels.xml

  3. 我目前正在使用QGLWidget和自定义OpenGL纹理并绘制调用以实现快速更新(> 60 FPS)。我观察到它比QImage / Qpixmap方法快8到10倍。请注意,我的纹理大小永远不会超过700x700。此外,我的Image始终存储在GPU内存中,并通过映射的CUDA内核进行更新。

    你绝对应该看到加速,但我不能保证它会满足你的FPS要求。