📜 ⬆️ ⬇️

Qt + OpenCV. Runtime and Widget for CvCapture (video capture devices)

Introduction


Analyzing the comments of the previous post ( Qt Designer & Runtime Qt library in the OpenCV service ... ), I had to work out in more detail the OpenCV library video capture device and methods for separating runtime libraries and widgets.
Working with Qt Designer is convenient (I'm lazy), so the interface design component for CvCapture appeared. After the start of work, the “scientific” explanation of this was also tightened - it is convenient to apply something similar, say, when designing an interface of properties or parameters of an application using a video capture device.
While the project archive is being downloaded, read on.

Thanks


Thanks to everyone who left their comments on the previous post.

Runtime library.


So, the OpenCV library is installed, code samples are viewed. It's time to “tie” the video capture device to Qt. And not just like that, but also to receive images by changing devices dynamically. Yes, to remember all the way to the image, video. Yes, so that the camera numbers are switched. Yes, that and ... the post is shorter turned out.
Library.

What is easier! We inherit a new library class from QObject, we hide unnecessary fields for a developer and methods in a private class as an element of the QScopedPointer collection, we mount alert signals and slot handlers.

Get the header file cqtopencvcaptureobject.h
#ifndef CQTOPENCVCAPTUREOBJECT_H #define CQTOPENCVCAPTUREOBJECT_H #include "../../../include/qtopencv_global.h" #include <opencv2/opencv.hpp> #include <QObject> #include <QScopedPointer> QT_BEGIN_HEADER QT_BEGIN_NAMESPACE /*----------------------------------------------------------------------------*/ /** \internal \class CQtOpenCVCaptureObjectPrivate \brief                CvCapture  OpenCV. */ class CQtOpenCVCaptureObjectPrivate; /*----------------------------------------------------------------------------*/ /** \class CQtOpenCVCaptureObject \brief       CvCapture  OpenCV. */ class #if defined(QTOPENCV_LIB_EXPORT) QTOPENCV_DECLARE_EXPORT #else Q_DECL_EXPORT #endif CQtOpenCVCaptureObject : public QObject { Q_OBJECT Q_CLASSINFO("brief", "OpenCV Capture class.") Q_CLASSINFO("author", "Vladimir N. Litvinenko") Q_CLASSINFO("URL", "http://www.codepaint.ru") Q_CLASSINFO("email", "litvinenko.vladimir@gmail.com") Q_CLASSINFO("created", "21-JUN-2012") Q_CLASSINFO("edited", "06-JUL-2012") public: explicit CQtOpenCVCaptureObject ( QObject *parent = 0 ); virtual ~CQtOpenCVCaptureObject (); CvCapture* getCapture () const; QString getPath () const; int getNumber () const; int getTimeoutInterval () const; IplImage* getImage () const; int getFrameCount () const; bool isInternal () const; bool isExternal () const; bool isActive () const; bool isRecap () const; signals: /** \fn [SIGNAL] void CQtOpenCVCaptureObject::signal_Errno ( int errno, const QString& errmsg ); \brief      . \param errno -   \param errmsg -   */ void signal_Errno ( int, const QString& ); /** \fn [SIGNAL] void CQtOpenCVCaptureObject::signal_CaptureChanged () \brief       */ void signal_CaptureChanged (); /** \fn [SIGNAL] void CQtOpenCVCaptureObject::signal_CaptureChanged ( const CvCapture* value ) \brief       \param value -       CvCapture  OpenCV */ void signal_CaptureChanged ( const CvCapture* ); /** \fn [SIGNAL] void CQtOpenCVCaptureObject::signal_ImageChanged ( const IplImage* value ) \brief         IplImage  OpenCV. \param value -      IplImage  OpenCV. */ void signal_ImageChanged ( const IplImage* ); /** \fn [SIGNAL] void CQtOpenCVCaptureObject::signal_TimeoutChanged () \brief        */ void signal_TimeoutChanged (); /** \fn [SIGNAL] void CQtOpenCVCaptureObject::signal_TimeoutChanged ( int value ) \brief        \param value -      */ void signal_TimeoutChanged ( int ); /** \fn [SIGNAL] void CQtOpenCVCaptureObject::signal_ActiveChanged ( bool value ) \brief            -. \param value -     .  true   ,  false -      -. */ void signal_ActiveChanged ( bool ); public slots: void slot_SetNumber ( int ); void slot_SetPath ( const QString& ); void slot_SetAsInternal ( bool ); void slot_SetTimeout ( int ); void slot_captureOn ( bool ); void slot_Activate (bool); void slot_SetRecap (bool); protected: virtual void timerEvent(QTimerEvent *event); private: Q_DISABLE_COPY(CQtOpenCVCaptureObject) Q_DECLARE_PRIVATE(CQtOpenCVCaptureObject) QScopedPointer<CQtOpenCVCaptureObjectPrivate> d_ptr; }; /*----------------------------------------------------------------------------*/ QT_END_NAMESPACE QT_END_HEADER #endif // CQTOPENCVCAPTUREOBJECT_H 


')
Slots:

.pro file
 DEFINES += QDESIGNER_EXPORT_WIDGETS 

There is no more need to connect the OpenCV library, it will go according to the runtime library.
And, here, her, darling, and fasten:
 unix: LIBS += -L/usr/lib -lQtOpenCVCapture INCLUDEPATH += $$PWD/../../runtime/capture/QtOpenCVCapture DEPENDPATH += /usr/lib 


Note! The path points to /usr/lib . It's comfortable. In the future, just create a symbolic link to your library in this directory, and there will be no problems with linking!

Let's declare the widget properties for the designer:
 ... Q_PROPERTY( bool visible READ isVisible WRITE slot_setVisible ) Q_PROPERTY( bool internal READ isInternal WRITE slot_SetAsInternal ) Q_PROPERTY( QString path READ getPath WRITE slot_SetPath ) Q_PROPERTY( int number READ getNumber WRITE slot_SetNumber ) Q_PROPERTY( int numberMax READ getNumberMax WRITE slot_SetNumberMax ) Q_PROPERTY( int timeout READ getTimeoutInterval WRITE slot_SetTimeout ) Q_PROPERTY( int timeoutMax READ getTimeoutMax WRITE slot_SetTimeoutMax ) Q_PROPERTY( int timeoutStep READ getTimeoutStep WRITE slot_SetTimeoutStep ) Q_PROPERTY( bool recapture READ isRecap WRITE slot_SetRecap ) Q_PROPERTY( QString FrameTitle READ getFrameTitle WRITE slot_setFrameTitle ) Q_PROPERTY( QString GroupBoxTitle READ getGroupBoxTitle WRITE slot_setGroupBoxTitle ) Q_PROPERTY( QString RadioNumberTitle READ getRadioNumberTitle WRITE slot_setRadioNumberTitle ) Q_PROPERTY( QString RadioPathTitle READ getRadioPathTitle WRITE slot_setRadioPathTitle ) Q_PROPERTY( QString PathTitle READ getPathTitle WRITE slot_setPathTitle ) Q_PROPERTY( QString NumberTitle READ getNumberTitle WRITE slot_setNumberTitle ) Q_PROPERTY( QString TimeOutTitle READ getTimeOutTitle WRITE slot_setTimeOutTitle ) Q_PROPERTY( QString TimeOutExtTitle READ getTimeOutExtTitle WRITE slot_setTimeOutExtTitle ) Q_PROPERTY( QString RecaptureTitle READ getRecaptureTitle WRITE slot_setRecaptureTitle ) ... 



Expand a set of slots and methods to support properties:
 ... //   bool isVisible () const; QString getFrameTitle () const; QString getGroupBoxTitle () const; QString getRadioNumberTitle () const; QString getRadioPathTitle () const; QString getPathTitle () const; QString getNumberTitle () const; QString getTimeOutTitle () const; QString getTimeOutExtTitle () const; QString getRecaptureTitle () const; ... //  void slot_setVisible( bool ); void slot_setFrameTitle( const QString& ); void slot_setGroupBoxTitle( const QString& ); void slot_setRadioNumberTitle( const QString& ); void slot_setRadioPathTitle( const QString& ); void slot_setPathTitle( const QString& ); void slot_setNumberTitle( const QString& ); void slot_setTimeOutTitle( const QString& ); void slot_setTimeOutExtTitle( const QString& ); void slot_setRecaptureTitle( const QString& ); void slot_SetNumberMax ( int ); void slot_SetTimeoutMax ( int ); void slot_SetTimeoutStep ( int ); ... 


Copy the window settings from the test example runtime library:
 /*----------------------------------------------------------------------------*/ void CQtOpenCVCaptureWidgetPrivate::setupUi ( QWidget* parent ) { p_Frame = new QFrame(parent); Q_ASSERT(p_Frame); p_Frame->setObjectName(QString::fromUtf8("p_Frame")); p_Frame->resize(550, 195); p_Frame->setMinimumSize(QSize(550, 195)); // p_Frame->setMaximumSize(QSize(550, 195)); p_Frame->setFrameShape(QFrame::StyledPanel); p_Frame->setFrameShadow(QFrame::Raised); p_gridLayout_Frame = new QGridLayout(p_Frame); Q_ASSERT(p_gridLayout_Frame); p_gridLayout_Frame->setObjectName(QString::fromUtf8("p_gridLayout_Frame")); p_groupBox_Capture = new QGroupBox(p_Frame); Q_ASSERT(p_groupBox_Capture); p_groupBox_Capture->setObjectName(QString::fromUtf8("p_groupBox_Capture")); QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); sizePolicy.setHorizontalStretch(0); sizePolicy.setVerticalStretch(0); sizePolicy.setHeightForWidth(p_groupBox_Capture->sizePolicy().hasHeightForWidth()); p_groupBox_Capture->setSizePolicy(sizePolicy); // p_groupBox_Capture->setMinimumSize(QSize(540, 190)); // p_groupBox_Capture->setMaximumSize(QSize(540, 185)); p_groupBox_Capture->setFlat(true); p_gridLayout_GBox = new QGridLayout(p_groupBox_Capture); Q_ASSERT(p_gridLayout_GBox); p_gridLayout_GBox->setSpacing(1); p_gridLayout_GBox->setContentsMargins(3, 3, 3, 3); p_gridLayout_GBox->setObjectName(QString::fromUtf8("p_gridLayout_GBox")); p_horLayout_Radio = new QHBoxLayout(); Q_ASSERT(p_horLayout_Radio); p_horLayout_Radio->setSpacing(1); p_horLayout_Radio->setObjectName(QString::fromUtf8("p_horLayout_Radio")); p_radioButton_URL = new QRadioButton(p_groupBox_Capture); Q_ASSERT(p_radioButton_URL); p_radioButton_URL->setObjectName(QString::fromUtf8("p_radioButton_URL")); p_horLayout_Radio->addWidget(p_radioButton_URL); p_radioButton_Number = new QRadioButton(p_groupBox_Capture); Q_ASSERT(p_radioButton_Number); p_radioButton_Number->setObjectName(QString::fromUtf8("p_radioButton_Number")); p_radioButton_Number->setChecked(true); p_horLayout_Radio->addWidget(p_radioButton_Number); p_gridLayout_GBox->addLayout(p_horLayout_Radio, 0, 0, 1, 1); p_horLayout_PathNum = new QHBoxLayout(); Q_ASSERT(p_horLayout_PathNum); p_horLayout_PathNum->setSpacing(3); p_horLayout_PathNum->setObjectName(QString::fromUtf8("p_horLayout_PathNum")); p_label_PathNum = new QLabel(p_groupBox_Capture); Q_ASSERT(p_label_PathNum); p_label_PathNum->setObjectName(QString::fromUtf8("p_label_PathNum")); QSizePolicy sizePolicy1(QSizePolicy::Fixed, QSizePolicy::Preferred); sizePolicy1.setHorizontalStretch(0); sizePolicy1.setVerticalStretch(0); sizePolicy1.setHeightForWidth(p_label_PathNum->sizePolicy().hasHeightForWidth()); p_label_PathNum->setSizePolicy(sizePolicy1); p_label_PathNum->setMinimumSize(QSize(150, 0)); p_label_PathNum->setLayoutDirection(Qt::LeftToRight); p_label_PathNum->setFrameShape(QFrame::NoFrame); p_label_PathNum->setAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter); p_horLayout_PathNum->addWidget(p_label_PathNum); p_spinBox_Number = new QSpinBox(p_groupBox_Capture); Q_ASSERT(p_spinBox_Number); p_spinBox_Number->setObjectName(QString::fromUtf8("p_spinBox_Number")); sizePolicy.setHeightForWidth(p_spinBox_Number->sizePolicy().hasHeightForWidth()); p_spinBox_Number->setSizePolicy(sizePolicy); p_spinBox_Number->setMinimum(0); p_spinBox_Number->setMaximum(999999); p_horLayout_PathNum->addWidget(p_spinBox_Number); p_lineEdit = new QLineEdit(p_groupBox_Capture); Q_ASSERT(p_lineEdit); p_lineEdit->setObjectName(QString::fromUtf8("p_lineEdit")); p_lineEdit->setEnabled(true); p_horLayout_PathNum->addWidget(p_lineEdit); p_gridLayout_GBox->addLayout(p_horLayout_PathNum, 1, 0, 1, 1); p_horLayout_TOut = new QHBoxLayout(); Q_ASSERT(p_horLayout_TOut); p_horLayout_TOut->setSpacing(3); p_horLayout_TOut->setObjectName(QString::fromUtf8("p_horLayout_TOut")); p_label_TOut = new QLabel(p_groupBox_Capture); Q_ASSERT(p_label_TOut); p_label_TOut->setObjectName(QString::fromUtf8("p_label_TOut")); sizePolicy1.setHeightForWidth(p_label_TOut->sizePolicy().hasHeightForWidth()); p_label_TOut->setSizePolicy(sizePolicy1); p_label_TOut->setMinimumSize(QSize(150, 0)); p_horLayout_TOut->addWidget(p_label_TOut); p_spinBox_TOut = new QSpinBox(p_groupBox_Capture); Q_ASSERT(p_spinBox_TOut); p_spinBox_TOut->setObjectName(QString::fromUtf8("p_spinBox_TOut")); sizePolicy.setHeightForWidth(p_spinBox_TOut->sizePolicy().hasHeightForWidth()); p_spinBox_TOut->setSizePolicy(sizePolicy); p_spinBox_TOut->setMinimum(0); p_spinBox_TOut->setMaximum(999999); p_horLayout_TOut->addWidget(p_spinBox_TOut); p_label_ms = new QLabel(p_groupBox_Capture); Q_ASSERT(p_label_ms); p_label_ms->setObjectName(QString::fromUtf8("p_label_ms")); sizePolicy1.setHeightForWidth(p_label_ms->sizePolicy().hasHeightForWidth()); p_label_ms->setSizePolicy(sizePolicy1); p_horLayout_TOut->addWidget(p_label_ms); p_horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Preferred, QSizePolicy::Minimum); Q_ASSERT(p_horizontalSpacer); p_horLayout_TOut->addItem(p_horizontalSpacer); p_gridLayout_GBox->addLayout(p_horLayout_TOut, 2, 0, 1, 1); p_horLayout_Buttons = new QHBoxLayout(); Q_ASSERT(p_horLayout_Buttons); p_horLayout_Buttons->setSpacing(3); p_horLayout_Buttons->setObjectName(QString::fromUtf8("p_horLayout_Buttons")); p_checkBox_Recap = new QCheckBox(p_groupBox_Capture); Q_ASSERT(p_checkBox_Recap); p_checkBox_Recap->setObjectName(QString::fromUtf8("p_checkBox_Recap")); sizePolicy.setHeightForWidth(p_checkBox_Recap->sizePolicy().hasHeightForWidth()); p_checkBox_Recap->setSizePolicy(sizePolicy); p_horLayout_Buttons->addWidget(p_checkBox_Recap); p_pushButton_Test = new QPushButton(p_groupBox_Capture); Q_ASSERT(p_pushButton_Test); p_pushButton_Test->setObjectName(QString::fromUtf8("p_pushButton_Test")); p_pushButton_Test->setCheckable(true); p_pushButton_Test->setChecked(false); p_horLayout_Buttons->addWidget(p_pushButton_Test); p_gridLayout_GBox->addLayout(p_horLayout_Buttons, 3, 0, 1, 1); p_gridLayout_Frame->addWidget(p_groupBox_Capture, 0, 0, 1, 1); #ifndef QT_NO_SHORTCUT p_label_PathNum->setBuddy(p_lineEdit); #endif // QT_NO_SHORTCUT retranslateUi(); QMetaObject::connectSlotsByName(p_Frame); } 



Connect signals and slots:
 /*----------------------------------------------------------------------------*/ void CQtOpenCVCaptureWidgetPrivate::setupConnections () { //   runtime-    q_obj->connect (q_obj, SIGNAL(signal_Errno(int,QString)), q_ptr, SIGNAL(signal_Errno(int,QString))); q_obj->connect (q_obj, SIGNAL(signal_CaptureChanged()), q_ptr, SIGNAL(signal_CaptureChanged())); q_obj->connect (q_obj, SIGNAL(signal_CaptureChanged(const CvCapture*)), q_ptr, SIGNAL(signal_CaptureChanged(const CvCapture*))); q_obj->connect (q_obj, SIGNAL(signal_ImageChanged(const IplImage*)), q_ptr, SIGNAL(signal_ImageChanged(const IplImage*))); q_obj->connect (q_obj, SIGNAL(signal_TimeoutChanged()), q_ptr, SIGNAL(signal_TimeoutChanged())); q_obj->connect (q_obj, SIGNAL(signal_TimeoutChanged(int)), q_ptr, SIGNAL(signal_TimeoutChanged(int))); q_obj->connect (q_obj, SIGNAL(signal_ActiveChanged(bool)), q_ptr, SIGNAL(signal_ActiveChanged(bool))); //       q_ptr->connect (p_radioButton_Number,SIGNAL(toggled(bool)), q_ptr, SLOT(slot_SetAsInternal(bool))); q_ptr->connect (p_radioButton_URL, SIGNAL(toggled(bool)), q_ptr, SLOT(slot_SetAsExternal(bool))); //         q_ptr->connect (p_lineEdit, SIGNAL(textChanged(QString)), q_ptr, SLOT(slot_SetPath(QString))); q_ptr->connect (p_lineEdit, SIGNAL(returnPressed()), q_ptr, SLOT(slot_PathComplete())); //       q_ptr->connect (p_spinBox_Number, SIGNAL(valueChanged(int)), q_ptr, SLOT(slot_SetNumber(int))); //    -   q_ptr->connect (p_spinBox_TOut, SIGNAL(valueChanged(int)), q_ptr, SLOT(slot_SetTimeout(int))); //          - q_ptr->connect (p_checkBox_Recap, SIGNAL(toggled(bool)), q_ptr, SLOT(slot_SetRecap(bool))); //      q_ptr->connect (p_pushButton_Test, SIGNAL(toggled(bool)), q_ptr, SLOT(slot_Test(bool))); // q_ptr->connect (q_ptr, SIGNAL(signal_ImageChanged(const IplImage*)), q_ptr, SLOT(slot_ShowImage(const IplImage*))); } /*----------------------------------------------------------------------------*/ 

Build a library based on the widget.
Plugin for the designer.

It's time to connect our QWidget library to Qt Designer.
Create a collection project.
 CONFIG += designer plugin debug_and_release TARGET = $$qtLibraryTarget(CQtOpenCVCollection) TEMPLATE = lib DEFINES += QDESIGNER_EXPORT_WIDGETS HEADERS = cqtopencvcapturewidgetplugin.h cqtopencvcollection.h SOURCES = cqtopencvcapturewidgetplugin.cpp cqtopencvcollection.cpp RESOURCES = icons.qrc //target.path = $$[QT_INSTALL_PLUGINS]/designer INSTALLS += target #include(cqtopencvimagewidget.pri) include(cqtopencvcapturewidget.pri) #include(cqtopencvcannywidget.pri) unix: LIBS += -L/usr/lib/ -lQtOpenCVCaptureWidget INCLUDEPATH += $$PWD/ DEPENDPATH += $$PWD/ 


Let's declare the plugin class.
 #ifndef CQTOPENCVCAPTUREWIDGETPLUGIN_H #define CQTOPENCVCAPTUREWIDGETPLUGIN_H #include <QDesignerCustomWidgetInterface> #include <QtDesigner/QDesignerExportWidget> class #if defined(QDESIGNER_EXPORT_WIDGETS) QDESIGNER_WIDGET_EXPORT #else Q_DECL_EXPORT #endif CQtOpenCVCaptureWidgetPlugin : public QObject, public QDesignerCustomWidgetInterface { Q_OBJECT Q_INTERFACES(QDesignerCustomWidgetInterface) public: CQtOpenCVCaptureWidgetPlugin(QObject *parent = 0); bool isContainer() const; bool isInitialized() const; QIcon icon() const; QString domXml() const; QString group() const; QString includeFile() const; QString name() const; QString toolTip() const; QString whatsThis() const; QWidget *createWidget(QWidget *parent); void initialize(QDesignerFormEditorInterface *core); private: bool m_initialized; }; 



Let's declare a collection class:
 #ifndef CQTOPENCVCOLLECTION_H #define CQTOPENCVCOLLECTION_H #include <QtDesigner/QtDesigner> #include <QtCore/qplugin.h> class CQtOpenCVCollection : public QObject, public QDesignerCustomWidgetCollectionInterface { Q_OBJECT Q_INTERFACES(QDesignerCustomWidgetCollectionInterface) public: explicit CQtOpenCVCollection(QObject *parent = 0); virtual QList<QDesignerCustomWidgetInterface*> customWidgets() const; private: QList<QDesignerCustomWidgetInterface*> m_widgets; }; #endif 

Implementation:
 #include "cqtopencvcapturewidgetplugin.h" //#include "cqtopencvimagewidgetplugin.h" //#include "cqtopencvcannywidgetplugin.h" #include "cqtopencvcollection.h" CQtOpenCVCollection::CQtOpenCVCollection(QObject *parent) : QObject(parent) { m_widgets.append(new CQtOpenCVCaptureWidgetPlugin(this)); // m_widgets.append(new CQtOpenCVImageWidgetPlugin(this)); // m_widgets.append(new CQtOpenCVCannyWidgetPlugin(this)); } QList<QDesignerCustomWidgetInterface*> CQtOpenCVCollection::customWidgets() const { return m_widgets; } Q_EXPORT_PLUGIN2(CQtOpenCVCollection, CQtOpenCVCollection) 


Pay attention to
 // m_widgets.append(new CQtOpenCVImageWidgetPlugin(this)); // m_widgets.append(new CQtOpenCVCannyWidgetPlugin(this)); 


After implementations of the CQtOpenCVImageWidgetPlugin and CQtOpenCVCannyWidgetPlugin you can remove comments. And in the OpenCV component of Qt Designer, new items will appear.

Project archive.

Test case

After assembling all the libraries, correctly assigning the links and setting the link to the collection in the plugins directory for Qt Designer, you can create a test case.

In the Designer, create the MainWindow , put our widget, build it.

Conclusion




Thanks for attention.

Source: https://habr.com/ru/post/148467/


All Articles