- PVSM.RU - https://www.pvsm.ru -

Qt + OpenCV. Runtime и Widget для CvCapture (устройства видеозахвата)

Введение.

Анализируя замечания предыдущего поста (Qt Designer & Runtime Qt библиотеки на службе OpenCV... [1]), пришлось более детально проработать устройство видеозахвата библиотеки OpenCV и методы разделения библиотек runtime и виджетов.
Работа с Qt Designer удобна (я — лентяй), поэтому и возник компонент проектирования интерфейса для CvCapture. После начала работы подтянулось и «научное » тому объяснение — удобно применить нечто похожее, скажем, при проектировании интерфейса свойств или параметров приложения, использующего устройство видеозахвата.
Пока идёт скачивание архива проекта [2], читайте далее.

Благодарности.

Спасибо всем, кто оставил свои замечания по предыдущему посту.

Библиотека времени выполнения.

Итак, библиотека 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 подключим библиотеки OpenCV
unix: LIBS += -L/usr/lib/ -lopencv_core -lopencv_highgui

INCLUDEPATH += /usr/include/opencv2/core
/usr/include/opencv2/highgui
DEPENDPATH += /usr/include/opencv2/core
/usr/include/opencv2/highgui

Всё. Библиотека создана. Проверим её работу.

Тестовый пример.

Создадим графический интерфейс к нашему устройству видеозахвата. Зачем графический? Всё просто: мы используем его и компоненты форматирования при построении виджета в коллекции плагинов к Qt Designer.

Не буду утруждать рисунками, вы найдёте форму в каталоге examples проекта testCaptureRuntime
Укажем видеофайл:

image

Скорость кадров можно регулировать значением таймаута, «поиграйте» с ним.

Переключим на встроенную в компьютер камеру:
image
Переключим на внешнюю IP-камеру:
Smartek Giganetix GigEVisionSDK

Библиотека работает.

Сегодня добавил в OpenCV поддержку камер Smartek Giganetix [3] на основе их GigEVisionSDK. Возможно, скоро выйдет, но я обязательно напишу в дальнейшем, как подключать своё устройство к списку видеозахвата OpenCV.

Библиотека на основе QWidget.

Здесь всё так же несложно, как и при создании биьблиотеки времени исполнения. Только «родитель» у класса QWidget, и прячем в приватный класс экземпляр нашего runtime класса.

В .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рхива проекта. [2]

Тестовый пример.

После сборки всех библиотек, корректного назначения ссылок и установки ссылки на коллекцию в каталог плагинов для Qt Designer можно создать тестовый пример.

В Дизайнере создаём MainWindow, помещаем наш виджет, собираем.
image

Видим:
image

Заключение.

  • Ещё раз, Исходные коды проекта. [2]
  • Попробуйте добавить ComboBox для выбора типа камер
  • НЕе пишите, пожалуйса, «а можно сделать так». Просто, сделайте. Коды в вашем распоряжении

Спасибо за внимание.

Автор: coffeesmoke


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/qt-2/12043

Ссылки в тексте:

[1] Qt Designer & Runtime Qt библиотеки на службе OpenCV...: http://habrahabr.ru/post/146210/

[2] архива проекта: http://www.wuala.com/coffeesmoke/development/C_CPP/Qt_and_OpenCV/files/QtOpenCVWidgets-20120725.zip

[3] Smartek Giganetix: http://www.smartekvision.com