3

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

有两个类,一个是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 程序变慢了。是另一种成本更低、效率更高的绘画方式吗?

4

1 回答 1

5

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

必须从 Qt 中的 UI 线程(包括 QML)触发 UI 更新。使该 CameraView 公开 public slot 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 应该像updateImage这样实现paint

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

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

于 2017-02-07T06:48:40.723 回答