Введение.
Анализируя замечания предыдущего поста (Qt Designer & Runtime Qt библиотеки на службе OpenCV...), пришлось более детально проработать устройство видеозахвата библиотеки OpenCV и методы разделения библиотек runtime и виджетов.
Работа с Qt Designer удобна (я — лентяй), поэтому и возник компонент проектирования интерфейса для CvCapture. После начала работы подтянулось и «научное » тому объяснение — удобно применить нечто похожее, скажем, при проектировании интерфейса свойств или параметров приложения, использующего устройство видеозахвата.
Пока идёт скачивание архива проекта, читайте далее.
Благодарности.
Спасибо всем, кто оставил свои замечания по предыдущему посту.
Библиотека времени выполнения.
Итак, библиотека OpenCV установлена, примеры кода просмотрены. Самое время «прикрутить» устройство видеозахвата к Qt. Да не просто так, а чтобы и изображения получать, меняя устройства динамически. Да, чтобы помнило все пути к изображению, видео. Да, чтобы и номера камер переключало. Да, чтобы и… пост покороче получился.
Библиотека.
Чего проще! Наследуем новый класс библиотеки от QObject, прячем ненужные разработчику поля и методы в приватный класс как элемент коллекции QScopedPointer, монтируем сигналы оповещения и слоты-обработчики.
Получаем файл заголовка 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
Слоты:
- slot_SetNumber отвечает за установку номера камеры
- slot_SetPath нацеливает устройство видеозахвата файл изображения, видео или web-CGI URL
- slot_SetAsInternal указывает, что устройство видеозахвата — камера вашего компьютера (по-моему, лишнее. Сами решите)
- slot_SetTimeout устанавливает время извлечения фрейма из CvCapture в миллисекундах
- slot_captureOn включает/отключает работу CvCapture
- slot_Activate активирует/отключает режим запроса фрейма по таймауту
- slot_SetRecap указывает устройству видеозахвата, что перед извлечением фрейма (изображения) необходимо… пересоздаться. Нужно бывает при использовании web-интерфейса к камерам
В
.pro файл помещаем DEFINES += QDESIGNER_EXPORT_WIDGETS
Больше нет необходимости подключать библиотеку OpenCV, она пойдёт по зависимости от runtime-библиотеки.
А, вот, её, родимую, и прикрутим:
unix: LIBS += -L/usr/lib -lQtOpenCVCapture INCLUDEPATH += $$PWD/../../runtime/capture/QtOpenCVCapture DEPENDPATH += /usr/lib
Обратите внимание! Путь указывает на
/usr/lib. Это удобно. В дальнейшем, просто создайте символическую ссылку на вашу библиотеку в этом каталоге, и не будет проблем с линковкой!Объявим свойства виджета для дизайнера:
... 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 ) ...
Расширим набор слотов и методов для поддержки свойств:
... //собственные методы доступа 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 ); ...
Скопируем настройки окна из тестового примера runtime- библиотеки:
/*----------------------------------------------------------------------------*/ 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); }
Подключим сигналы и слоты:
/*----------------------------------------------------------------------------*/ 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*))); } /*----------------------------------------------------------------------------*/
Собираем библиотеку на основе виджета.
Плагин к Дизайнеру.
Настало время подключить нашу QWidget-библиотеку к Qt Designer.
Создадим проект-коллекцию.
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/
Объявим класс плагина.
#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; };
Объявим класс коллекции:
#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
Реализация:
#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)
Обратите внимание на
// m_widgets.append(new CQtOpenCVImageWidgetPlugin(this)); // m_widgets.append(new CQtOpenCVCannyWidgetPlugin(this));
После реализаций плагинов
CQtOpenCVImageWidgetPlugin и CQtOpenCVCannyWidgetPlugin комментарии можно будет убрать. И в группе OpenCV компонент Qt Designer появятся новые элементы.Aрхива проекта.
Тестовый пример.
После сборки всех библиотек, корректного назначения ссылок и установки ссылки на коллекцию в каталог плагинов для Qt Designer можно создать тестовый пример.
В Дизайнере создаём MainWindow, помещаем наш виджет, собираем.
Заключение.
- Ещё раз, Исходные коды проекта.
- Попробуйте добавить ComboBox для выбора типа камер
- Не пишите, пожалуйса, «а можно сделать так». Просто, сделайте. Коды в вашем распоряжении
Спасибо за внимание.
