Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. [solved] To call function in C++ from QML
Forum Updated to NodeBB v4.3 + New Features

[solved] To call function in C++ from QML

Scheduled Pinned Locked Moved QML and Qt Quick
17 Posts 5 Posters 7.9k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • sierdzioS Offline
    sierdzioS Offline
    sierdzio
    Moderators
    wrote on last edited by
    #8

    Set "visible" to false.

    (Z(:^

    1 Reply Last reply
    0
    • B Offline
      B Offline
      bts-007
      wrote on last edited by
      #9

      Yes you are right. Now only the second screen is visible. Here comes the new problem. when I go back and forth between main and second qml screen continuosly , there is a degradation in performance. video capturing is becoming slow and it is showing 2-5 frames per second.

      1 Reply Last reply
      0
      • S Offline
        S Offline
        stereomatching
        wrote on last edited by
        #10

        May you show us your codes?Maybe your resources handle have some problem(forget to delete something etc)?

        May I ask you why do you set the openCV camera as global parameter?
        If you need the same camera parameter could be used
        between different entity of the same class, you culd declare it as
        static data member, this way could reduce the chance of name conflict.

        My implementation with openCV2 and Qt5

        @
        #ifndef OPENCVCAMERA_HPP
        #define OPENCVCAMERA_HPP

        #include <QQuickPaintedItem>
        #include <QString>

        //#include <opencv2/core/core.hpp>
        #include <opencv2/highgui/highgui.hpp>

        class QPainter;
        class QTimer;

        class openCVCamera : public QQuickPaintedItem
        {
        Q_OBJECT
        Q_PROPERTY(int imageHeight READ imageHeight WRITE setImageHeight NOTIFY imageHeightChanged)
        Q_PROPERTY(int imageWidth READ imageWidth WRITE setImageWidth NOTIFY imageWidthChanged)
        Q_PROPERTY(bool play READ play WRITE setPlay NOTIFY playChanged)
        public:
        explicit openCVCamera(QQuickItem *parent = 0);
        openCVCamera(openCVCamera const&)=delete;
        openCVCamera& operator=(openCVCamera const&)=delete;

        int imageHeight() const;
        int imageWidth() const;
        
        Q_INVOKABLE void open(int width, int height);
        
        void paint(QPainter *painter);
        bool play() const;
        
        Q_INVOKABLE void release();
        
        void setImageHeight(int value);
        void setImageWidth(int value);
        void setPlay(bool value);
        

        signals:
        void imageHeightChanged();
        void imageWidthChanged();

        void playChanged();
        

        public slots:
        void open(size_t index);

        private slots:
        void captureFrame();

        private:
        cv::VideoCapture camera_;
        cv::Mat cameraFrame_;

        cv::Mat displayedFrame_;
        
        int imageHeight_;
        int imageWidth_;
        
        QString log_;
        
        bool play_;
        
        cv::Mat result_;
        
        QTimer *timer_;
        

        };

        #endif // OPENCVCAMERA_HPP

        @

        @
        #include <QDebug>

        #include <QPainter>
        #include <QTimer>

        #include <opencv2/core/core.hpp>

        #include "openCVToQt.hpp"

        #include "openCVCamera.hpp"

        openCVCamera::openCVCamera(QQuickItem *parent) :
        QQuickPaintedItem(parent), imageHeight_(320), imageWidth_(480), play_(false), timer_(new QTimer(this))
        {
        setRenderTarget(QQuickPaintedItem::FramebufferObject);
        setPerformanceHint(QQuickPaintedItem::FastFBOResizing);
        connect(timer_, &QTimer::timeout, this, &openCVCamera::captureFrame);

        open(imageWidth_, imageHeight_);
        

        }

        int openCVCamera::imageHeight() const
        {
        return imageHeight_;
        }

        int openCVCamera::imageWidth() const
        {
        return imageWidth_;
        }

        void openCVCamera::open(int width, int height)
        {
        if(!camera_.isOpened()){
        camera_.open(0);
        camera_.set(CV_CAP_PROP_FRAME_WIDTH, width);
        camera_.set(CV_CAP_PROP_FRAME_HEIGHT, height);

            setPlay(true);
        }
        

        }

        void openCVCamera::open(size_t index)
        {
        camera_.open(index);
        if(!camera_.isOpened()){
        log_ = "could not access the camera or video";
        qDebug() << log_;
        }
        }

        void openCVCamera::paint(QPainter *painter)
        {
        if(cameraFrame_.empty()){
        log_ = "could not grab the camera frame";
        qDebug() << log_;
        return;
        }

        if(camaraFrame_.cols != imageWidth_ || cameraFrame_.rows != imageHeight_){
            cv::resize(cameraFrame_, result_, cv::Size(imageWidth_, imageHeight_));
        }else{
            result_ = cameraFrame_;
        }
        QImage const img = mat_to_qimage_ref(result_);
        painter->drawImage(0, 0, img);
        

        }

        bool openCVCamera::play() const
        {
        return play_;
        }

        void openCVCamera::release()
        {
        camera_.release();
        }

        void openCVCamera::setImageHeight(int value)
        {
        if(value != imageHeight()){
        imageHeight_ = value;
        qDebug()<<"height changed : "<<value;
        emit imageHeightChanged();
        }
        }

        void openCVCamera::setImageWidth(int value)
        {
        if(value != imageWidth()){
        imageWidth_ = value;
        qDebug()<<"width changed : "<<value;
        emit imageWidthChanged();
        }
        }

        void openCVCamera::setPlay(bool value)
        {
        if(value != play_){
        play_ = value;

            if(play_){
                timer_->start(33);
            }else{
                timer_->stop();
            }
        
            emit playChanged();
        }
        

        }

        /**********************************************************
        ****************** implementation ************************
        **********************************************************/

        void openCVCamera::captureFrame()
        {
        if(play_){
        camera_ >> cameraFrame_;
        if(cameraFrame_.empty()){
        log_ = "could not grab the camera frame";
        qDebug() << log_;
        return;
        }
        update();
        }
        }

        @

        qml
        @
        import QtQuick 2.0
        import CVCamera 1.0

        Rectangle {
        id: root
        width: 480
        height: 320

        Component{
            id: compCamera
            CVCam{
                id: cam1
                imageHeight: root.height
                imageWidth: root.width
            }
        }
        
        Loader{
            id: loaderCam
        
            anchors.fill: parent
            sourceComponent: compCamera
        }
        
        MouseArea{
            anchors.fill: parent
        
            onClicked: {
                loaderCam.sourceComponent = null
                loaderCam.sourceComponent = compCamera
            }
        }
        

        }

        @

        I haven't test all of the api(I prefer the Qt5 api when it is possible)
        you could give it a try if you like

        1 Reply Last reply
        0
        • B Offline
          B Offline
          bts-007
          wrote on last edited by
          #11

          sure. I haven't handled resources properly, I tried my best. Here is the source code

          common.h
          @
          #ifndef COMMON_H
          #define COMMON_H

          extern int next_screen;

          #endif // COMMON_H
          @

          MyCameraWindow.h
          @
          #ifndef MYCAMERAWINDOW_H_
          #define MYCAMERAWINDOW_H_

          #include <QWidget>
          #include <QVBoxLayout>
          #include "QOpenCVWidget.h"
          #include <opencv/cv.h>
          #include <opencv/highgui.h>
          #include<QDebug>

          class MyCameraWindow : public QWidget
          {
          Q_OBJECT
          private:
          QOpenCVWidget *cvwidget;
          CvCapture *camera;
          QVBoxLayout *layout;

          public:
          MyCameraWindow(CvCapture *cam, QWidget *parent=0);
          int timerid;

          protected:
          void timerEvent(QTimerEvent*);
          };

          #endif /MYCAMERAWINDOW_H_/
          @

          myitem.h
          @

          #ifndef MYITEM_H
          #define MYITEM_H

          #include "MyCameraWindow.h"
          #include <QtDeclarative/QDeclarativeItem>
          #include <QGraphicsProxyWidget>
          #include<QDebug>
          #include <QObject>
          #include<QOpenCVWidget.h>
          #include"common.h"

          extern CvCapture * camera;

          class MyItem : public QDeclarativeItem
          {
          Q_OBJECT
          Q_PROPERTY(int func_next_screen READ func_next_screen WRITE set_func_next_screen)
          public:

          explicit MyItem(QDeclarativeItem *parent = 0);
          MyCameraWindow *mycamera;
          
          int func_next_screen(){
              return m_func_next_screen;
          
          }
          
          void set_func_next_screen(int &m_func){
              next_screen=m_func;
          }
          

          private:
          QGraphicsProxyWidget* mProxy;
          int m_func_next_screen;

          };

          #endif // MYITEM_H
          @

          QOpenCVWidget.h
          @

          #ifndef QOPENCVWIDGET_H
          #define QOPENCVWIDGET_H

          #include <opencv/cv.h>
          #include <opencv/highgui.h>
          #include <QPixmap>
          #include <QLabel>
          #include <QWidget>
          #include <QVBoxLayout>
          #include <QImage>
          #include<QDesktopWidget>
          #include<QDialog>
          #include<QApplication>
          #include<QDebug>

          class QOpenCVWidget : public QWidget {
          private:
          QLabel *imagelabel;
          QVBoxLayout *layout;

          QImage image;
          cv::Mat source_image;     // Variable pointing to the same input frame
          cv::Mat dest_image;
          

          public:
          QOpenCVWidget(QWidget *parent = 0);
          void putImage(IplImage *);
          QDialog *aboutDialog;
          QLabel *label;
          };

          #endif

          @

          I used common.h for controlling but it didn't work. I used timer for changing the frame.

          1 Reply Last reply
          0
          • B Offline
            B Offline
            bts-007
            wrote on last edited by
            #12

            common.cpp
            @
            int next_screen=0;

            @

            main.cpp
            @
            #include <QApplication>
            #include"myitem.h"
            #include<QDeclarativeView>

            #include<qdeclarative.h>
            #include<QDeclarativeView>
            #include<QDeclarativeItem>
            #include<QDeclarativeContext>

            CvCapture * camera = cvCreateCameraCapture(0);

            int main(int argc, char *argv[])
            {
            QApplication a(argc, argv);
            qmlRegisterType<MyItem>("mywindow",1,0,"MyItem");

            QDeclarativeView view;
            view.setSource(QUrl("main.qml"));
            view.showMaximized();
            return a.exec&#40;&#41;;
            

            }

            @

            MyCameraWIndow.cpp
            @

            #include "MyCameraWindow.h"
            #include"myitem.h"
            #include"common.h"

            MyCameraWindow::MyCameraWindow(CvCapture *cam, QWidget *parent) : QWidget(parent) {

            camera = cam;
            layout = new QVBoxLayout;
            cvwidget = new QOpenCVWidget(this);
            layout->addWidget(cvwidget);
            layout->setContentsMargins(0,0,0,0);
            setLayout(layout);
            
            timerid=startTimer(10);  // 0.1-second timer
            

            }

            void MyCameraWindow::timerEvent(QTimerEvent*) {
            IplImage *image=cvQueryFrame(camera);
            cvwidget->putImage(image);
            if(next_screen==1)
            {
            killTimer(timerid);
            delete cvwidget;
            next_screen=0;
            }
            }

            @

            myitem.cpp
            @
            #include "myitem.h"

            #include <QtDeclarative/qdeclarative.h>

            #include <QGraphicsProxyWidget>

            MyItem::MyItem(QDeclarativeItem *parent): QDeclarativeItem(parent)
            {
            mycamera = new MyCameraWindow(camera);
            mProxy = new QGraphicsProxyWidget(this);
            mProxy->setWidget(mycamera);
            }

            @

            QOpenCVWidget.cpp
            @

            #include "QOpenCVWidget.h"
            #include"myitem.h"

            // Constructor
            QOpenCVWidget::QOpenCVWidget(QWidget *parent) : QWidget(parent) {

            aboutDialog = new QDialog;
            label = new QLabel(aboutDialog);
            
            layout = new QVBoxLayout;
            imagelabel = new QLabel;
            layout->addWidget(imagelabel);
            layout->setContentsMargins(0,0,0,0);
            
            setLayout(layout);
            

            }

            void QOpenCVWidget::putImage(IplImage *cvimage) {

            source_image = cvimage;
            
            dest_image=cvimage;
            
            
            cv::resize(source_image, source_image, cv::Size(768,576) , 0, 0);
            cv::resize(dest_image, dest_image, cv::Size(1920,1080) , 0, 0);
            
            
            cv::cvtColor(source_image,source_image,CV_BGR2RGB);
            cv::cvtColor(dest_image,dest_image,CV_BGR2RGB);
            
            QImage qimg = QImage((const unsigned char*) source_image.data, source_image.cols, source_image.rows, QImage::Format_RGB888);
            QImage qimg1 = QImage((const unsigned char*) dest_image.data, dest_image.cols, dest_image.rows, QImage::Format_RGB888); // convert to QImage
            
            
            if(QApplication::desktop()->screenCount()==2)
            {
                aboutDialog->setGeometry(QApplication::desktop()->screenGeometry(1));
            
                label->setPixmap(QPixmap::fromImage(qimg1));
                aboutDialog->show();
            }
            
            imagelabel->setPixmap(QPixmap::fromImage(qimg));
            

            }

            @

            Important to know I am using dual screen that is why I am displaying it in 1080. I tried destructor but it crashed that is why I used common variable to stop the timer and delete the object(didn't work)

            Here is the qml part

            main.qml
            @
            import QtQuick 1.1
            import mywindow 1.0

            Rectangle {

            id:item_id
            width:1300
            height:700
            Rectangle{
                width: 80
                height: 60
                color: "red"
                x:900
                y:30
                MouseArea{
                    anchors.fill: parent
                    onClicked:{
                        myitem_id.func_next_screen=1;
            
                        pageloader.source="second.qml"
                    }
                }
            }
            
            Rectangle{
                width:800
                height: 500
                x:100
                y:100
            
                MyItem{
                    id:myitem_id
                }
            
            }
            Loader {
                id: pageloader
            }
            

            }
            @

            second.qml
            @
            import QtQuick 1.1
            import mywindow 1.0

            Rectangle {
            id:item_id
            width:1300
            height:700

            Rectangle{
                width: 80
                height: 60
                color: "red"
                x:30
                y:30
                MouseArea{
                    anchors.fill: parent
                    onClicked:{
                        myitem_id.func_next_screen=1;
            
                        pageloader.source="main.qml"
                    }
                }
            }
            Rectangle{
                width:800
                height: 500
                x:100
                y:100
            
                MyItem{
                    id:myitem_id
                }
            
            }
            

            }

            @

            1 Reply Last reply
            0
            • S Offline
              S Offline
              stereomatching
              wrote on last edited by
              #13

              I don't have Qt4 and don't know how to use QGraphicsProxyWidget, but
              there are five problems in your codes I find by now.

              1 : you can't delete cvwidget and you don't need to do that, because
              cvwidget has a parent, the QObject(parent of cvwidget in this case) will
              delete it when the class destroy. Delete it manually may cause undefined
              behavior.

              2 : your codes wouldn't work in some cases
              @
              QImage qimg = QImage((const unsigned char*) source_image.data, source_image.cols, source_image.rows, QImage::Format_RGB888);
              @
              cv::Mat of openCV may or may not do some byte patching on
              every row(for performance sake), you have to tell the QImage how
              many bytes per row it is

              example
              @
              QImage((T*)(mat.data), mat.cols, mat.rows, mat.step, format);
              @

              by the way, wrap the codes of transfer between cv::Mat and QImage, this
              should save you some headaches(maybe you already done)

              3 : please use the api of openCV2 to deal with the camera, it is very easy
              to use, check the function I wrote above(open and captureFrame).The
              camera of openCV2 will released when the object is destroyed, you don't
              need to released it explicitly.Besides, with the camera of openCV2, you
              don't have to convert between IplImage and cv::Mat, this should make
              your program faster

              4 : you should not modify the IplImage you get from cvQueryFrame,
              the IplImage you take may always point to the same buffer, if you
              alter it, the camera may have some undefined behaviors.
              You should copy the cv::Mat before you alter it

              5 : When you transfer between cv::Mat
              and IplImage, you better don't do anything may reallocate memory, because
              it may have some weird behaviors(my own experiences), but I also don't know
              the reason.

              Another suggestion, please don't use global parameter if possible.

              1 Reply Last reply
              0
              • B Offline
                B Offline
                bts-007
                wrote on last edited by
                #14

                stereo can you share this file "openCVToQt.hpp". how did you use qml register.

                1 Reply Last reply
                0
                • S Offline
                  S Offline
                  stereomatching
                  wrote on last edited by
                  #15

                  you can find it on github
                  "github":https://github.com/stereomatchingkiss/qimage_and_mat

                  The function "copy_qimage_to_mat_policy" has bug
                  I should not copy the data by memcpy, a more proper solution
                  is take the reference of qimage and clone it.

                  example
                  @
                  cv::Mat copy_qimage_to_mat_policy::start(QImage &img, int format)
                  {
                  return qimage_to_mat_ref(img).clone();
                  }
                  @

                  There are another weird bug, when the images are bmp(or png),
                  the channel is one and you take the reference of the cv::Mat
                  by the function "mat_to_qimage_ref", the result of the QImage would
                  become very weird, don't know the reason yet.I use a workaround
                  (change one channel image to three channel image) to make the codes work,
                  not a good solution, hope someday I could find the source of the bug.

                  1 Reply Last reply
                  0
                  • R Offline
                    R Offline
                    Ryein
                    wrote on last edited by
                    #16

                    Great post stereo.

                    Just so everyone knows here is how you can implement it. For a QML noob this is surprising help to know.

                    @qmlRegisterType<openCVCamera>("CVCamera",1,0,"CVCam");@

                    1 Reply Last reply
                    0
                    • J Offline
                      J Offline
                      joshmarshall95
                      wrote on last edited by
                      #17

                      I know this an old post but I was hoping someone could tell me how to physically display the camera on the QML side?

                      1 Reply Last reply
                      0

                      • Login

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved