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

How to paint sequential image in efficient way in QQuickPaintedItem

出于某种原因,我需要将 opencv VideoCapture 包装在一个 class 中,它将在 Qt Quick 中使用。

有两个class,一个是Camera,一个是CameraView。 CameraView 继承自 QQuickPaintedItem.

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

通知 CameraView 重新绘制

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

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

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

  2. 在我的笔记本电脑中,当我让 CameraView 全屏绘制图像时,我发现有一个 python 程序变慢了。有没有另一种低成本高效的画图方式?

How can I efficiently update QML item based on QQuickPaintedItem C++ class? I delegated some preprocesssing to dedicated thread instead of a timer on UI thread and it does not update the image in QML UI anymore.

必须从 Qt 中的 UI 线程触发 UI 更新,包括 QML。使 CameraView 暴露 public 插槽 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);
}

ClassOpenCvOnWorkerThread 应该启动它的工作线程并公开 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);
}

更新: 在我自己的 "camera" 线程类似 QML 输出的代码中,我还负责处理 UI 线程停顿时无法处理视频帧,以便信号发送方知道何时不 post 视频帧。但这值得另一个问题。或者可以在没有信号和槽但有条件变量的情况下重新实现整个示例。