Qt Designer & Runtime Qt libraries on the service of OpenCV developer, or dragging IplImage on QLabel

Introduction


Like most Qt developers using the OpenCV library, I was interested in the topic of representing an image received from a web camera as a component of visual interface design for Qt Designer.
Break a bunch of information on the net, noticed that most of the articles repeat each other, and finding the “highlight” is too difficult. I think my experience with creating a visual component to represent an image of the OpenCV library for Qt Designer will be useful. In addition, I will share information on how to separate the libraries of design time and code execution time. This approach is very well established in RAD Delphi for operating systems of the Windows family.

Remarks

  • The author of coffeesmoke does not “chew” simple truths, methods, and subtleties. The code is clear. Functions do not exceed 20 lines.
  • The project and use case are implemented on Qt Creator for Linux. Windows application developers must set the settings in .pro files according to their OS
  • The author does not enter into discussions like “otherwise it would be better”. Found the best solution, implement it.
  • The author does not answer questions about the settings of Qt Creator and / or Qt Designer. Search engines to help you!
  • Fasting is for guidance only and serves to indicate the direction of your thoughts. Where they go, you know better.


Design and implementation


Performance

Let us leave the OpenCV image manipulation library for a short while. Our task is a universal runtime library (code runtime library).
Perhaps what I will show now is used universally. However, I did not meet in the open spaces on the topic of building plug-ins for Qt Designer a similar approach.
The task is not to “drag” the Qt Designera plug-in library into the project, but to manage the runtime library. Obviously, the runtime library can be “framed” with a widget representing the component in the Qt Dessigner palette. The

designer contains a simple QLabel component that can transmit images using the pixmap property . This is enough for our purposes. Turning to the translation of documentation Adding Qt Designer Modules
and the very source of information using the link Using Custom Widgets with Qt Designer. The most useful is information about the location of custom plug-in libraries! now we know the destination path: $$ QTDIR / plugin / designer
Let us leave the wrapping of the new component aside. We will deal directly with the component of the runtime library. Create a dynamically loaded library with the CQtOpenCVImage class of our new widget. Cqtopencvimage.h
header file

#ifndef QTOPENCVIMAGE_H
#define QTOPENCVIMAGE_H

#include

#include 
#include 
#include 
#include "opencv2/opencv.hpp"
#include 
/*----------------------------------------------------------------------------*/

class CQtOpenCVImagePrivate;

/*----------------------------------------------------------------------------*/
class
    #if defined(QDESIGNER_EXPORT_WIDGETS)
      QDESIGNER_WIDGET_EXPORT
    #else
      Q_DECL_EXPORT
    #endif
CQtOpenCVImage
 : public QWidget
{
    Q_OBJECT
    Q_PROPERTY(QUrl           capture         READ getCapture         WRITE slot_setCapture)
    Q_PROPERTY(QString        text            READ getLabelText       WRITE slot_setLabelText)
    Q_PROPERTY(QPixmap        pixmap          READ getPixmap          WRITE slot_setPixmap)
    Q_PROPERTY(bool           scaledContents  READ hasScaledContents  WRITE slot_setScaledContents)
    Q_PROPERTY(bool           grayscale       READ isGrayscale        WRITE slot_setGrayscale)
    Q_PROPERTY(Qt::Alignment  alignment       READ getAlignment       WRITE setAlignment)
  public:
    explicit
    CQtOpenCVImage(QWidget* parent = 0, Qt::WindowFlags f = 0);
    virtual
    ~CQtOpenCVImage();
    QUrl&     getCapture ();
    QString   getLabelText () const;
    const
    QPixmap*  getPixmap () const;
    const
    QImage*   getImage () const;
    Qt::Alignment getAlignment() const;
    void      setAlignment(Qt::Alignment);
    const
    QLabel*   getQLabel () const;
    bool      hasScaledContents() const;
    bool      isGrayscale() const;
  public Q_SLOTS:
    void      slot_setCapture ( const QUrl& );
    void      slot_setLabelText ( const QString& );
    void      slot_setPixmap ( const QPixmap& );
    void      slot_setImage ( const QImage& );
    void      slot_setQLabel ( const QLabel& );
    void      slot_setGrayscale(bool);
    void      slot_setScaledContents(bool);
  Q_SIGNALS:
    void      signal_Grayscale(bool);
    void      signal_ImageChanged();
    void      signal_CaptureChanged();
    void      signal_PixmapChanged();
    void      signal_LabelChanged();
    void      signal_AlignmentChanged();
  private:
    Q_DISABLE_COPY(CQtOpenCVImage)
    Q_DECLARE_PRIVATE(CQtOpenCVImage)

QScopedPointer d_ptr;

};
/*----------------------------------------------------------------------------*/
#endif // QTOPENCVIMAGE_H


Pay attention to the areas marked with a special font
  • Including the QtDesigner / QDesignerExportWidget header file ensures that the necessary QDESIGNER_WIDGET_EXPORT macro is included when using the directive in the project file
    DEFINES += QDESIGNER_EXPORT_WIDGETS
  • The CQtOpenCVImagePrivate class hides internal variables and pointers from the declaration of the CQtOpenCVImage main class . It seems to me that this is correct: you should not overload ads with unnecessary information;
  • Declare a single private pointer variable
    QScopedPointer d_ptr;
    on the structure of the internal implementation of algorithms and data within the framework of Qt rules. IMHO, "good tone."

Our CQtOpenCVImage class provides Qt Designer properties (Q_PROPERTY) for visual image control. Property recording methods are implemented by void slot _ **** (***) slots .
And so, the class of representation of the image obtained from the web (IP) camera inherited from QWidget during visual design gives access to the properties:
  • capture - video capture device URL or webcam number;
  • text - text inscription. Analogue of the text property QLabel;
  • pixmap - a pointer to an object of type QPixmap. An analog of the pixmap QLabel property;
  • scaledContents - image scalability. Analogue of the property scaledContents QLabel;
  • grayscale - a boolean switch for the color mode of the image output, where true corresponds to grayscale, and false - color (RGB);
  • alignment - alignment of the contents of text and pixmap. Analog of alignment property QLabel;


I think that it makes no sense to describe the purpose of the class methods: the name speaks for itself.

Let's move on to the class implementation code (file cqtopencvimage.cpp ).

Consider the hidden class CQtOpenCVImagePrivate , its attributes and methods.
class CQtOpenCVImagePrivate
{
    Q_DECLARE_PUBLIC(CQtOpenCVImage)
  public:
    CQtOpenCVImagePrivate(CQtOpenCVImage* owner);
    virtual
    ~CQtOpenCVImagePrivate();
    CQtOpenCVImage* q_ptr; // указатель на экземпляр основного класса
    QGridLayout*  f_grid_layout; // сетка выравнивания находящихся в ней компонент по всему периметру
    QLabel*       f_label;// экземпляр типа QLabel для вывода изображения
    QUrl          f_capture_path;// URL устройства видеозахвата или его номер 
    QImage*       p_qt_image; // Указател на экземпляр изображения типа QImage
    CvCapture*    p_capture; // Указател на экземпляр устройства видеозахвата в рамках описания OpenCV
    IplImage*     p_opencv_frame; // Указател на текущий фрем из p_capture
    uint          f_grayscaled:1; // признак представления изобравжения в градациях серого
    void init (); // инициализация данных
    void close (); // корекктное закрытие всех указателей
    void free_qt_image (); // освобождение памяти экземпляра p_qt_image
    void new_qt_image ();// распределение  памяти для экземпляра p_qt_image
    void free_capture (); // освобождение памяти экземпляра p_capture
    void new_capture (); // распределение  памяти для экземпляра p_capture
};

Let's move on to the implementation of the methods.
/*----------------------------------------------------------------------------*/
void
CQtOpenCVImagePrivate::init ()
{
  Q_ASSERT(q_ptr);
  f_grid_layout = new QGridLayout(q_ptr);
  Q_ASSERT(f_grid_layout);
  f_label = new QLabel(q_ptr/*, Qt::WindowNoState*/);
  Q_ASSERT(f_label);
  f_grid_layout->addWidget (f_label);
  p_qt_image = 0,
  p_capture = 0,
  p_opencv_frame = 0,
  f_grayscaled = 0;
}
/*----------------------------------------------------------------------------*/
inline void
CQtOpenCVImagePrivate::close ()
{
  free_qt_image ();
  free_capture ();
}
/*----------------------------------------------------------------------------*/
CQtOpenCVImagePrivate::CQtOpenCVImagePrivate(CQtOpenCVImage* owner)
  : q_ptr(owner)
{
  init ();
}
/*----------------------------------------------------------------------------*/
CQtOpenCVImagePrivate::~CQtOpenCVImagePrivate ()
{
  close ();
  if(!(f_label->parent ()))
    delete f_label;
  if(!(f_grid_layout->parent ()))
    delete f_grid_layout;
}
/*----------------------------------------------------------------------------*/
inline void
CQtOpenCVImagePrivate::free_qt_image ()
{
  if(p_qt_image) {
    delete p_qt_image;
    p_qt_image = 0;
  }
}
/*----------------------------------------------------------------------------*/
inline void
CQtOpenCVImagePrivate::free_capture ()
{
  if(p_capture) {
    cvReleaseCapture(&p_capture);
    p_capture = 0;
  }
}

The code is clear and readable. No questions should arise. The constructor’s CQtOpenCVImage * owner parameter represents a pointer to a CQtOpenCVImage object that contains an instance of the hidden class as a variable CQtOpenCVImage :: d_ptr.
In the words of the doctor, the hero of Leonid Bronevoy, from the film “Formula of Love”, “So, I will continue ...”.

Consider the definition of a capture device using the new_capture method .
/*----------------------------------------------------------------------------*/
void
CQtOpenCVImagePrivate::new_capture ()
{
  free_capture ();//освобождение устройства захвата
  bool b_ok;
  int i_index = f_capture_path.toString ().toInt (&b_ok); // определение номера камеры, если это номер, а не URL
/* информация к размышлению:
   перезахват устройства, если камера реализована как CGI для вебсервера, возвращающий по одному кадру
  if(b_ok) {
    p_capture = cvCreateCameraCapture(i_index);
    if(p_capture)
      if(!p_opencv_frame)
        p_opencv_frame = cvQueryFrame (p_capture);
  } else {
    while((p_capture =cvCaptureFromFile(f_capture_path.toString ().toStdString ().c_str ()))) {
      p_opencv_frame = cvQueryFrame (p_capture);
      new_qt_image ();
      cvWaitKey (1000);
    }
  }
*/
  // да, ну его, этот перезахват. Перезахватим по запросу методами OpenCV.
  p_capture =
      b_ok ?
        cvCreateCameraCapture(i_index) : 
        cvCaptureFromFile(f_capture_path.toString ().toStdString ().c_str ());
  p_opencv_frame = p_capture ? cvQueryFrame (p_capture) : 0; // получение фрейма методом из OpenCV
  new_qt_image (); // формирование экземпляра QImage
}

For a detailed introduction to OpenCV, read the Table of Contents

Forming an Image of the QImage Type:
/*----------------------------------------------------------------------------*/
void
CQtOpenCVImagePrivate::new_qt_image ()
{
  if(!p_capture) return;
  free_qt_image (); // освободим указатель на изображение
  if(p_opencv_frame) {
  // создадим OpenCV экземпляр изображения согласно параметру оттенка серого
    IplImage *_tmp =
      f_grayscaled ?
        cvCreateImage(
          cvSize( p_opencv_frame->width, p_opencv_frame->height ),
          IPL_DEPTH_8U,
          1
        ) :
        cvCloneImage (p_opencv_frame)
    ;
    try
    {
      // пребразование цвета в RGB или оттенки серого
      cvCvtColor( p_opencv_frame, _tmp, f_grayscaled ? CV_RGB2GRAY : CV_BGR2RGB );
      // формирование изображения типа QImage
      p_qt_image = new QImage(
                 (const uchar*)(_tmp->imageData),
                 _tmp->width,
                 _tmp->height,
                 _tmp->widthStep,
                 (f_grayscaled ? QImage::Format_Indexed8 : QImage::Format_RGB888)
               );
      emit q_ptr->signal_ImageChanged (); // оповещение о готовности
      q_ptr->slot_setPixmap (QPixmap::fromImage (*p_qt_image)); // отрисовать изображение на QLabel
    } catch(...) {
     // упс... Дрова -- в исходное, пельмени разлепить!
      close ();
    }
    // не забываем прибрать за собой!
    cvReleaseImage(&_tmp);
  }
}



I think everything is clear with the underwater part of the iceberg.

The implementation of the main class is even simpler. Even too lazy to explain. See for yourself:
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
CQtOpenCVImage::CQtOpenCVImage(QWidget* parent, Qt::WindowFlags f)
  : QWidget(parent, f),
    d_ptr(new CQtOpenCVImagePrivate(this))
{
}
/*----------------------------------------------------------------------------*/
CQtOpenCVImage::~CQtOpenCVImage()
{
}
/*----------------------------------------------------------------------------*/
QUrl& CQtOpenCVImage::getCapture ()
{
  return (d_func ()->f_capture_path);
}
/*----------------------------------------------------------------------------*/
QString CQtOpenCVImage::getLabelText () const
{
  return (d_func ()->f_label->text ());
}
/*----------------------------------------------------------------------------*/
bool  CQtOpenCVImage::hasScaledContents() const
{
  return d_func ()->f_label->hasScaledContents ();
}
/*----------------------------------------------------------------------------*/
void CQtOpenCVImage::slot_setScaledContents(bool Value )
{
  d_func ()->f_label->setScaledContents (Value);
}
/*----------------------------------------------------------------------------*/
bool CQtOpenCVImage::isGrayscale() const
{
  return d_func ()->f_grayscaled;
}
/*----------------------------------------------------------------------------*/
void
CQtOpenCVImage::slot_setGrayscale( bool Value )
{
  if(d_func ()->f_grayscaled != Value)
  {
    d_func ()->f_grayscaled = Value;
    if(!(d_func ()->p_capture))
      d_func ()->new_capture ();
    else
      d_func ()->new_qt_image ();
    emit signal_Grayscale (d_func ()->f_grayscaled);
  }
}
/*----------------------------------------------------------------------------*/
void  CQtOpenCVImage::slot_setLabelText ( const QString& Value )
{
  d_func ()->f_label->setText (Value);
}
/*----------------------------------------------------------------------------*/
void  CQtOpenCVImage::slot_setCapture ( const QUrl& Value )
{
// Раскомментировать при необходимости исключения переинициализации захвата
//  if(getCapture ().toString () != Value.toString () || !d_func ()->p_opencv_frame)
//  {
    d_func ()->f_capture_path = Value.toString ().trimmed ();
    d_func ()->new_capture ();
    emit signal_CaptureChanged ();
//  }
}
/*----------------------------------------------------------------------------*/
const QPixmap*
CQtOpenCVImage::getPixmap () const
{
  return ((const QPixmap*)(d_func ()->f_label->pixmap ()));
}
/*----------------------------------------------------------------------------*/
void
CQtOpenCVImage::slot_setPixmap ( const QPixmap& Value )
{
  d_func ()->f_label->setPixmap (Value);
  emit signal_PixmapChanged ();
}
/*----------------------------------------------------------------------------*/
const QImage*
CQtOpenCVImage::getImage () const
{
  return(d_func ()->p_qt_image);
}
/*----------------------------------------------------------------------------*/
void
CQtOpenCVImage::slot_setImage ( const QImage& Value )
{
  d_func ()->free_qt_image ();
  d_func ()->p_qt_image = new QImage(Value);
  slot_setPixmap (QPixmap::fromImage (*(d_func ()->p_qt_image)));
  emit signal_ImageChanged ();
}
/*----------------------------------------------------------------------------*/
void
CQtOpenCVImage::slot_setQLabel ( const QLabel& Value)
{
  d_func ()->f_label->setText (Value.text ());
  emit signal_LabelChanged ();
}
/*----------------------------------------------------------------------------*/
Qt::Alignment
CQtOpenCVImage::getAlignment() const
{
  return(d_func ()->f_label->alignment ());
}
/*----------------------------------------------------------------------------*/
void
CQtOpenCVImage::setAlignment(Qt::Alignment Value)
{
  d_func ()->f_label->setAlignment (Value);
  emit signal_AlignmentChanged ();
}
/*----------------------------------------------------------------------------*/
const QLabel*
CQtOpenCVImage::getQLabel () const
{
  return ((const QLabel*)(d_func ()->f_label));
}


We form a runtime library. We describe the project file images.pro:
TARGET = QtOpenCVImages
TARGET = $$qtLibraryTarget($$TARGET)
TEMPLATE = lib
CONFIG += debug_and_release

Do not forget to include:
DEFINES += QDESIGNER_EXPORT_WIDGETS

Define the path to the library files:

unix:!symbian {
    target.path = $$PWD/../../../../lib
    DESTDIR    = $$PWD/../../../../lib
    INSTALLS += target
}


Add class files:
SOURCES += \
    cqtopencvimage.cpp
HEADERS += \
    cqtopencvimage.h


Define the paths of the headers of the OpenCV library files and the paths of the project dependencies:
INCLUDEPATH += /usr/include/opencv2
DEPENDPATH += /usr/include/opencv2


Add the OpenCV library (core and highgui) to our project:
#win32:CONFIG(release): LIBS += -L/usr/lib/ -lopencv_core
#else:win32:CONFIG(debug, debug|release): LIBS += -L/usr/lib/ -lopencv_cored
#else:
unix: LIBS += -L/usr/lib/ -lopencv_core
#win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../../../../../usr/lib/release/ -lopencv_highgui
#else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../../../../../usr/lib/debug/ -lopencv_highguid
#win32:CONFIG(release): LIBS += -L/usr/lib/release/ -lopencv_highgui
#else:symbian: LIBS += -lopencv_highgui
#else:
unix: LIBS += -L/usr/lib/ -lopencv_highgui


Dear Windows developers, I “jumped off” the Microsoft needle for a long time and I apologize for commenting on the library paths for your OS. You are not stupid people, you’ll figure it out.
* NIX oids, use the ln -s command to create links to your libraries from a location to a directory /usr/lib
Once you create the link, just rebuild the project, and everything will work fine!

So, we have created a dynamic Qt library of the visual component for displaying a picture obtained from a web camera using OpenCV tools.

Source code: Wu a La (literally)

Design

It is time to connect our runtime library to the plugin class shell for Qt Designer.
Create a plugin library project:
TARGET = QtOpenCVWidgets
TARGET = $$qtLibraryTarget($$TARGET)
TEMPLATE = lib
CONFIG += designer plugin release
DEFINES += QDESIGNER_EXPORT_WIDGETS
SOURCES += \
    qtopencvimageplugin.cpp \
    ../qtopencvwidgets.cpp
HEADERS +=\
    qtopencvimageplugin.h \
    ../qtopencvwidgets.h \
    ../runtime/images/cqtopencvimage.h
RESOURCES += \
    qtopencvimages.qrc
unix:!symbian {
     target.path = $$PWD/../../../lib
     DESTDIR    = $$PWD/../../../lib
    INSTALLS += target
}
INCLUDEPATH += /usr/include/opencv2
DEPENDPATH += /usr/include/opencv2
#win32:CONFIG(release, debug|release): LIBS += -L/usr/lib/ -lQtOpenCVImages
#else:win32:CONFIG(debug, debug|release): LIBS += -L/usr/lib -lQtOpenCVImages
#else:symbian: LIBS += -lQtOpenCVImages
#else:
unix: LIBS += -L/usr/lib -lQtOpenCVImages
INCLUDEPATH += $$PWD/../runtime/images
DEPENDPATH += $$PWD/../runtime/images

Looks like a Runtime project, doesn't it? Let's consider some differences:
  • The name of the library has changed: TARGET = QtOpenCVWidgets ;
  • The CONFIG + = designer plugin release parameter contains plugin and designer tags ;
  • The plugin is implemented in two files, one per header and the implementation of qtopencvimageplugin. * Qtopencvwidgets. * <. I>;
    There is still a dependency on OpenCV library headers as added dependency on the included cqtopencvimage.h header of our QtOpenCVImages widget ;
    The dynamic runtime library libQtOpenCVImages is enabled by a symbolic link from /usr/lib/libQtOpenCVImages.soindicating its real location in the project directory

We create a Qt Designer plugin widget according to all the canons of Qt: Creating Custom Widgets for Qt Designer ( coffeesmoke , as it is said loudly!):
Qtopencvimageplugin.h
#ifndef QTOPENCVIMAGEPLUGIN_H
#define QTOPENCVIMAGEPLUGIN_H
#include 
#include 
class QtOpenCVImagePlugin : public QObject, public QDesignerCustomWidgetInterface
{
    Q_OBJECT
    Q_INTERFACES(QDesignerCustomWidgetInterface)
  public:
    explicit QtOpenCVImagePlugin(QObject *parent = 0);
    QString     name() const;
    QString     includeFile() const;
    QString     group() const;
    QIcon       icon() const;
    QString     toolTip() const;
    QString     whatsThis() const;
    bool        isContainer() const;
    QWidget*  createWidget(QWidget *parent);
    void      initialize(QDesignerFormEditorInterface *core);
    bool      isInitialized() const;
    QString   domXml() const;
  signals:
  public slots:
  private:
    bool f_init;
};
#endif // QTOPENCVIMAGEPLUGIN_H

The main idea: declare as Q_INTERFACE, inheriting from QDesignerCustomWidgetInterface and overload the methods of the designer interface class according to your requirements.

qtopencvimageplugin.cpp
#include "qtopencvimageplugin.h"
#include "cqtopencvimage.h"
QtOpenCVImagePlugin::QtOpenCVImagePlugin(QObject *parent) :
  QObject(parent),
  f_init(false)
{
}
QString
QtOpenCVImagePlugin::name() const
{
  return "CQtOpenCVImage";// имя класса виджета
}
QString
QtOpenCVImagePlugin::includeFile() const
{
    return QLatin1String("cqtopencvimage.h"); // название включения в файл ui_*.h новой формы
}
QString
QtOpenCVImagePlugin::group() const
{
    return tr("OpenCV Widgets"); // название группы отображения на панели компонентов Qt Designer
}
QIcon
QtOpenCVImagePlugin::icon() const
{
  return QIcon(":QtOpenCVLogo.png"); // значок виджета
}
QString
QtOpenCVImagePlugin::toolTip() const
{
    return QString();
}
QString
QtOpenCVImagePlugin::whatsThis() const
{
    return QString();
}
bool
QtOpenCVImagePlugin::isContainer() const
{
    return false;
}
QWidget*
QtOpenCVImagePlugin::createWidget(QWidget *parent)
{
    return new CQtOpenCVImage(parent); // вот она, реализация экземпляра класса нашего виджета!
}
void
QtOpenCVImagePlugin::initialize(QDesignerFormEditorInterface *core)
{
// установка признака инициализации при помещении на форму
    if (f_init) return; 
    f_init = true;
}
bool
QtOpenCVImagePlugin::isInitialized() const
{
    return f_init;
}
QString
QtOpenCVImagePlugin::domXml() const
{
// основные параметры для дизайнера
    return "\n"
               " \n"
               "  \n"
               "   \n"
               "    0\n"
               "    0\n"
               "    400\n"
               "    200\n"
               "   \n"
               "  \n"
               " \n"
               "";
}



There is very little left: create a common wrapper-container for all our widgets of the qtopencvwidgets.h groupQt <-> OpenCV

#ifndef QTOPENCVWIDGETS_H
#define QTOPENCVWIDGETS_H
#include 
#include 
#include 
class QtOpenCVWidgets :
    public QObject,
    public QDesignerCustomWidgetCollectionInterface
{
    Q_OBJECT
    Q_INTERFACES(QDesignerCustomWidgetCollectionInterface)
public:
    explicit QtOpenCVWidgets(QObject *parent = 0);
    QList customWidgets() const { return f_plugins; }
private:
    QList f_plugins;
};
#endif // QTOPENCVWIDGETS_H


qtopencvwidgets.cpp
#include "qtopencvwidgets.h"
#include "images/qtopencvimageplugin.h"
QtOpenCVWidgets::QtOpenCVWidgets(QObject *parent) :
    QObject(parent)
{
    f_plugins << new QtOpenCVImagePlugin(this);
}
//Q_DECLARE_INTERFACE(QtOpenCVWidgets, "com.trolltech.Qt.Designer.QtOpenCV")
Q_EXPORT_PLUGIN2(qtopencvwidgetsplugin, QtOpenCVWidgets)

Of interest is the constructor, as follows: f_plugins << new QtOpenCVImagePlugin(this);. The next time you add new components to the collection, it will be enough to rewrite the constructor by adding another f_plugins operator << new <Next> Plugin (this);
Application

Open Qt Designer and look for our СQtOpenCVImage in the component palette. We place it on a new form. Change capture to the desired URL 192.168.0.20:8080/image.jpg. In this case, this is the Java applet of the camera server that provides the current requested frame.
Put a “tick” on the grayscale
Source code property : If you downloaded it earlier, do not click on it .

conclusions


  • We learned how to create a runtime library for implementing our own class based on the visual components of Qt;
  • We learned how to frame the runtime library in the Qt Designer plugin, making applications independent of the designer plugin at runtime;

Applications


Simple test case

Let's create a standard Qt GUI application, open the main form of the window, place our component from it, create some service controls, build and run it.
Change the "Address ..." to the value 0 (built-in video camera) and look at the image changes.

Source code: If you downloaded earlier, do not click on it .

What's next?


  • Optimization of the current project;
  • Description of the proven visual component for searching the borders of the image using the Canny method: CQtOpenCVCannyWidget based on the CQtOpenCVCanny class;
  • The relationship between QtOpenCVImage and QtOpenCVCanny

All the best.

Also popular now: