如何在QQuickPaintedItem中以有效的方式绘制顺序图像

时间:2017-02-07 02:14:15

标签: qt qgraphicsscene qquickitem

出于某种原因,我需要在一个将在Qt Quick中使用的类中包含opencv VideoCapture。

有两个类,一个是Camera,另一个是CameraView。 CameraView继承自QQuickPaintedItem。

相机类会定期获取图像。它通过QObject :: startTimer(int interval)实现。 (例如,如果网络摄像头的fps为30,则定时器间隔为1000 / 30-8,8是时间偏差)。一旦Camera获得图像,它会通过调用CameraView :: Update()来通知CameraView重新绘制。

在CameraView :: paint(QPainter *)中,CameraView将从Camera类获取图像副本,并通过调用QPainter :: drawImage(...)绘制此图像。

我在编码过程中遇到了一些问题:

  1. 我尝试用QThread替换时间事件,以定期从相机获取图像。当我在QThread中调用CameraView :: Update()时,CameraView不会重新绘制。有什么问题?

  2. 在我的笔记本电脑中,当我使CameraView全屏绘制图像时,我发现一个python程序变慢了。是另一种以更低的成本和效率来描绘图像的方法吗?

1 个答案:

答案 0 :(得分:3)

  

如何基于QQuickPaintedItem C ++高效更新QML项目   类?我将一些预处理委托给专用线程而不是   UI线程上的计时器,它不再更新QML UI中的图像。

必须从Qt中的UI线程触发UI更新,包括QML。使CameraView公开公共广告位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应该像这样实现updateImagepaint

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);
}

OpenCvOnWorkerThread应该启动其工作线程并公开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:在我自己的代码中,从“相机”线程输出类似的QML我还会在无法处理视频帧时处理UI线程停顿,这样信号发送者就知道什么时候不能发布视频帧。但这值得另一个问题。或者这整个例子可以重新实现,没有信号和槽,但条件变量。