出于某种原因,我需要在一个将在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(...)绘制此图像。
我在编码过程中遇到了一些问题:
我尝试用QThread替换时间事件,以定期从相机获取图像。当我在QThread中调用CameraView :: Update()时,CameraView不会重新绘制。有什么问题?
在我的笔记本电脑中,当我使CameraView全屏绘制图像时,我发现一个python程序变慢了。是另一种以更低的成本和效率来描绘图像的方法吗?
答案 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应该像这样实现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);
}
UPDATE:在我自己的代码中,从“相机”线程输出类似的QML我还会在无法处理视频帧时处理UI线程停顿,这样信号发送者就知道什么时候不能发布视频帧。但这值得另一个问题。或者这整个例子可以重新实现,没有信号和槽,但条件变量。