在Qt/C++中使用QFutures和OpenCV



我有一个简单的Qt/C++程序,它使用cv::VideoCapture对象从我的一个LAN设备中收集网络摄像头图像。该应用程序使用Qt Quick构建,具有ImageQML项,通过自定义QQuickImageProvider实现:,每500毫秒为其提供一张图片

WebcamImageProvider::WebcamImageProvider()
: QQuickImageProvider(ImageType::Image)
{
connect(&_timer, &QTimer::timeout, this, &WebcamImageProvider::updateImage);
// refresh our picture every .5 seconds
_timer.start(500);
}
// overridden function from base class
QImage WebcamImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
{
Q_UNUSED(id)
Q_UNUSED(size)
Q_UNUSED(requestedSize)
return _img;
}

我的主要功能如下:

// Qt Quick
#include <QQuickItem>
#include <QQuickWindow>
// QML + GUI
#include <QQmlContext>
#include <QGuiApplication>
#include <QQmlApplicationEngine>
// webcam stuff
#include "webcamimageprovider.h"
/*
* Here we go
*/
int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
const QUrl url(QStringLiteral("qrc:/main.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
// we're adding our self-made image provider instance here
WebcamImageProvider wip;
engine.addImageProvider("webcam", &wip);
engine.rootContext()->setContextProperty("webcamImageProvider", &wip);
engine.load(url);
return app.exec();

我的main.qml文件的代码在这里应该不重要。

在我的图像提供者类中,我提供了updateImage插槽,如下所示:

void WebcamImageProvider::updateImage()
{
/*
* Webcam image grapping via https://raspberrypi.stackexchange.com/a/85510/132942
*/
if (!_cap.open(_videoUrl)) {
qDebug() << "Error opening stream.";
}
if (!_cap.read(_mat)) {
qDebug() << "No video capture or webcam error.";
}
// via https://stackoverflow.com/a/12312326/4217759
_img = QImage(
static_cast<uchar*>(_mat.data),
_mat.cols,
_mat.rows,
static_cast<int>(_mat.step),
QImage::Format_BGR888
);
emit imageChanged(_img);
}

我的问题是,当我的设备无法通过网络访问时,应用程序将完全冻结,因为它卡在_cap.open()功能中。因此,我正试图将此功能外包给未来,以便异步加载图像。由于我对线程和期货几乎一无所知,我随机试用了QFutures:

void WebcamImageProvider::updateImage()
{
/*
* Webcam image grapping via https://raspberrypi.stackexchange.com/a/85510/132942
*/
QFuture<void> future = QtConcurrent::run([&](){ _cap.open(_videoUrl); });
if (!future.isRunning()) {
qDebug() << "Error opening stream.";
}
if (future.isFinished()) {
if (!_cap.read(_mat)) {
qDebug() << "No video capture or webcam error.";
}
// via https://stackoverflow.com/a/12312326/4217759
_img = QImage(
static_cast<uchar*>(_mat.data),
_mat.cols,
_mat.rows,
static_cast<int>(_mat.step),
QImage::Format_BGR888
);
emit imageChanged(_img);
}
}

然而,我不会从中得到任何图像输出。

有人能帮助我如何正确地构建代码,这样我就可以在这里异步加载我的图像吗?

提前非常感谢。

1-您应该知道一些事情,为_img创建setter并在其中发出更改!因为有一天你可能需要在另一个函数中设置Image,如果你不这样做,你应该复制emit-fooChanged((。

2-当你检查这些并且is不负责在你的方法中工作时,你应该抛出一个异常,然后处理它们,如果你想使用qDebug((。

3-我的建议是(如果我完全理解你的工作(创建一个在循环中工作并总是获得新图像的线程,然后创建一个队列工作者,并创建另一个线程(工作者(来处理你的场景(这里是updateImage方法(。

最新更新