0

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

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

但是,我不会从中得到任何图像输出。

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

提前非常感谢。

4

1 回答 1

-1

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

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

3-我的建议是(如果我完全理解您的工作)创建一个循环工作并始终获取新图像的线程,然后创建一个队列工作者并创建另一个线程(工作者)来处理您的场景(此处为 updateImage 方法)。

于 2021-04-22T07:37:17.527 回答