Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Memory leak (OpenCV + QML)



  • Hi! I’m trying to display OpenCV Mat in QML image.

    I grab frames from camera with OpenCV, the frames are displayed successfully in QML, but memory usage increases with time. How can I fix it? Here is the my code:

    main.cpp

    #include <QGuiApplication>
    #include "videoprovider.h"
    
    int main(int argc, char *argv[])
    {
        QGuiApplication app(argc, argv);
    
        VideoProvider videoProvider;
    
        return app.exec();
    }
    

    VideoProvider.h

    #ifndef VIDEOPROVIDER_H
    #define VIDEOPROVIDER_H
    
    #include <QObject>
    #include <QFuture>
    #include <QImage>
    #include <QQmlApplicationEngine>
    #include <QQuickImageProvider>
    #include <opencv2/opencv.hpp>
    
    class VideoProvider : public QObject, public QQuickImageProvider
    {
        Q_OBJECT
    public:
        explicit VideoProvider();
        QPixmap requestPixmap(const QString &id, QSize *size, const QSize& requestedSize);
    
    signals:
        void frameChanged();
    
    public slots:
        void framePainted();
    
    private:
        QQmlApplicationEngine engine;
        bool readyfor;
        cv::Mat mat;
        QImage outputImage;
        void process();
    };
    
    #endif // VIDEOPROVIDER_H
    

    VideoProvider.cpp

    #include <QQmlContext>
    #include <QtConcurrent/QtConcurrent>
    #include <QDebug>
    #include <QThread>
    #include "videoprovider.h"
    #include <QQuickImageProvider>
    
    VideoProvider::VideoProvider() : QQuickImageProvider (QQuickImageProvider :: Pixmap)
    {
        engine.rootContext()->setContextProperty("videoProvider", this);
    
        engine.addImageProvider(QLatin1String ("videoCapture"), this);
    
        engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    
        readyfor = true;
    
        QtConcurrent::run(this, VideoProvider::process);
    }
    
    void VideoProvider::framePainted()
    {
        readyfor = true;
    }
    
    void VideoProvider::process()
    {
        cv::VideoCapture capture(0);
    
        while(true){
    
            QThread::currentThread()->msleep(80);
    
            if(!readyfor) continue;
    
            mat.release();
    
            capture >> mat;
    
            if(mat.empty())
            {
                qDebug()<<"disconnect";
            }
            else
            {
                readyfor = false;
    
                cv::cvtColor(mat, mat, cv::COLOR_BGR2RGB);
    
                outputImage = QImage((uchar*)mat.data, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
    
                emit frameChanged();
            }
        }
    
        capture.release();
    }
    
    QPixmap VideoProvider::requestPixmap(const QString &id, QSize *size, const QSize& requestedSize)
    {
        return QPixmap::fromImage(outputImage);
    }
    

    main.qml

    import QtQuick 2.6
    import QtQuick.Window 2.2
    
    Window
    {
        visible: true
        width: 640
        height: 480
        title: qsTr("Hello World")
        id: root
    
        Image {
            id: videoLayer
            anchors.fill: parent
            cache: false
    
            onSourceChanged:{
                videoProvider.framePainted();
            }
        }
     
        Connections
        {
            target: videoProvider
            property int frameCounter: 0
    
            onFrameChanged:
            {
                videoLayer.source = "image://videoCapture/hoge" + frameCounter;
                frameCounter ^= 1;
            }
        }
    }
    

    I found that it happened when I send signal (emit frameChanged();) to QML.



  • @DYYF have you tried any other examples for OpenCV + QML? i.e. here or here?
    I'm not sure why, but I don't like your videoprocessor object launching the QML engine. All the examples I've used to so far run the QML engine from main.cpp


Log in to reply