OpenCV開発者のサービス上のQt DesignerおよびRuntime Qtライブラリ、またはQLabelでのIplImageのドラッグ

はじめに



OpenCVライブラリを使用するほとんどのQt開発者と同じように、Webカメラから受け取った画像をQt Designerのビジュアルインターフェイスデザインのコンポーネントとして表すというトピックに興味がありました。

ネット上の多くの情報を破壊し、ほとんどの記事が互いに繰り返されていることに気付き、「ハイライト」を見つけるのは非常に困難です。 Qt DesignerのOpenCVライブラリのイメージを表すビジュアルコンポーネントを作成した経験は役に立つと思います。 さらに、設計時とコード実行時のライブラリを分離する方法に関する情報を共有します。 このアプローチは、Windowsファミリのオペレーティングシステム用にRAD Delphiで確立されています。



備考






設計と実装



フルフィルメント


OpenCV画像操作ライブラリをしばらく放置します。 私たちのタスクは、ユニバーサルランタイムライブラリ(コードランタイムライブラリ)です。

おそらく、私が今見せることは普遍的に使用されています。 ただし、Qt Designerでプラグインを構築するというトピックに関するオープンスペースでは、同様のアプローチはありませんでした。

タスクは、Qt Designeraプラグインライブラリをプロジェクトに「ドラッグ」するのではなく、ランタイムライブラリを使用することです。 明らかに、ランタイムライブラリは、Qt Dessignerパレットのコンポーネントプレゼンテーションウィジェットで「フレーム化」できます。



デザイナーには、pixmapプロパティを使用して画像送信できる単純なQLabelコンポーネントが含まれています。 私たちの目的にはこれで十分です。 ドキュメントの翻訳に目を向けるQt Designerモジュールの追加

また、 Qt Designerでカスタムウィジェットを使用するリンクを使用して情報のソースを作成します最も有用なのは、カスタムプラグインライブラリの場所に関する情報です! 宛先パスがわかりました:$$ QTDIR / plugin / designer

新しいコンポーネントのラッピングは別として、ランタイムライブラリのコンポーネントを直接扱います。 新しいウィジェットのCQtOpenCVImageクラスを使用して、動的にロードされるライブラリを作成します。

ヘッダーファイルcqtopencvimage.h



#ifndef QTOPENCVIMAGE_H #define QTOPENCVIMAGE_H
      
      





#include <QtDesigner / QDesignerExportWidget>



 #include <QWidget> #include <QUrl> #include <QLabel> #include "opencv2/opencv.hpp" #include <QScopedPointer> /*----------------------------------------------------------------------------*/
      
      





クラス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
      
      







特別なフォントでマークされた領域に注意してください



CQtOpenCVImageクラスは、視覚的な画像制御のためにQt Designerプロパティ(Q_PROPERTY)を提供します。 プロパティ記録メソッドは、 voidスロット_ ****(***)スロットによって実装されます。

したがって、ビジュアルデザイン中にQWidgetから継承されたWeb(IP)カメラから取得した画像を表すクラスは、プロパティへのアクセスを提供します。





クラスメソッドの目的を説明することは意味がないと思います。名前はそれ自身を表しています。



クラスの実装コード(ファイルcqtopencvimage.cpp )に進みましょう



隠しクラスCQtOpenCVImagePrivate 、その属性とメソッドを検討してください。

 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 };
      
      





メソッドの実装に移りましょう。

 /*----------------------------------------------------------------------------*/ 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; } }
      
      





コードは明確で読みやすいです。 質問はありません。 コンストラクターのCQtOpenCVImage * ownerパラメーターは、変数CQtOpenCVImage :: d_ptrとして非表示クラスのインスタンスを含むCQtOpenCVImageオブジェクトへのポインターを表します。

映画「愛の式」のレオニード・ブロネヴォイのヒーローである医者の言葉で、「だから、私は続けます...」。



new_captureメソッドを使用したキャプチャデバイスの定義を検討します

 /*----------------------------------------------------------------------------*/ 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 }
      
      





OpenCVの詳細については、目次をご覧ください



タイプQImageのイメージング:

 /*----------------------------------------------------------------------------*/ 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); } }
      
      









私はすべてが氷山の水中部分ではっきりしていると思います。



メインクラスの実装はさらに単純です。 説明するのが面倒です。 自分で見てください:

 /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ 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)); }
      
      







ランタイムライブラリを作成します。 プロジェクトファイルimages.proについて説明します。

 TARGET = QtOpenCVImages TARGET = $$qtLibraryTarget($$TARGET) TEMPLATE = lib CONFIG += debug_and_release
      
      





含めることを忘れないでください:

 DEFINES += QDESIGNER_EXPORT_WIDGETS
      
      





ライブラリファイルへのパスを定義します。

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







クラスファイルを追加します。

 SOURCES += \ cqtopencvimage.cpp HEADERS += \ cqtopencvimage.h
      
      







OpenCVライブラリファイルのヘッダーのパスとプロジェクトの依存関係のパスを定義します。

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







プロジェクトにOpenCVライブラリ(コアとhighgui)を追加します。

 #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
      
      







親愛なるWindows OS開発者の皆さん、私はMicrosoftの針を長い間「飛ばして」おり、OSのライブラリパスについてコメントすることをおaびします。 あなたは愚かな人ではありません、あなたはそれを理解します。

* NIX OID、ln -sコマンドを使用して、 /usr/lib



ディレクトリ内の場所からライブラリへのリンクを作成します
リンクを作成したら、プロジェクトを再構築するだけで、すべてが正常に機能します!



そのため、OpenCVツールを使用してWebカメラから取得した画像を表示するためのビジュアルコンポーネントの動的Qtライブラリを作成しました。



ソースコード: Wu a La(文字通り)



設計


ランタイムライブラリをQt Designerのプラグインのラッパークラスに接続します。

プラグインライブラリプロジェクトを作成します。

 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
      
      





ランタイムプロジェクトのように見えますか? いくつかの違いを考えてみましょう。



Qtのすべての標準に従ってQt Designerプラグインウィジェットを作成します: Qt Designerのカスタムウィジェットの作成coffeesmoke 、大声で言われたように!):

qtopencvimageplugin.h

 #ifndef QTOPENCVIMAGEPLUGIN_H #define QTOPENCVIMAGEPLUGIN_H #include <QObject> #include <QDesignerCustomWidgetInterface> 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
      
      





主なアイデア:Q_INTERFACEとして宣言し、QDesignerCustomWidgetInterfaceから継承し、その要件に応じてデザイナーのインターフェイスクラスのメソッドをオーバーロードします。



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 "<ui language=\"c++\">\n" " <widget class=\"CQtOpenCVImage\" name=\"QtOpenCVImage\">\n" " <property name=\"geometry\">\n" " <rect>\n" " <x>0</x>\n" " <y>0</y>\n" " <width>400</width>\n" " <height>200</height>\n" " </rect>\n" " </property>\n" " </widget>\n" "</ui>"; }
      
      









Qt <-> OpenCV



グループのすべてのウィジェットに共通のラッパーコンテナーを作成します。

qtopencvwidgets.h

 #ifndef QTOPENCVWIDGETS_H #define QTOPENCVWIDGETS_H #include <QObject> #include <QtPlugin> #include <QDesignerCustomWidgetCollectionInterface> class QtOpenCVWidgets : public QObject, public QDesignerCustomWidgetCollectionInterface { Q_OBJECT Q_INTERFACES(QDesignerCustomWidgetCollectionInterface) public: explicit QtOpenCVWidgets(QObject *parent = 0); QList<QDesignerCustomWidgetInterface*> customWidgets() const { return f_plugins; } private: QList<QDesignerCustomWidgetInterface *> 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)
      
      





興味深いのは、コンストラクタです: f_plugins << new QtOpenCVImagePlugin(this);



。 次回コレクションに新しいコンポーネントを追加するとき、別のf_plugins演算子<< new <Next> Plugin(this);を追加してコンストラクターを書き換えるだけで十分です。

申込み


Qt Designerを開き、コンポーネントパレットでQtOpenCVImageを探します。 新しいフォームに配置します。 キャプチャを目的のURLに変更します 192.168.0.20:8080/image.jpg



192.168.0.20:8080/image.jpg



この場合、これは現在要求されているフレームを提供するカメラサーバーのJavaアプレットです。

grayscale



プロパティをgrayscale





ソースコード: 以前にダウンロードした場合は、クリックしないでください



結論





用途



簡単なテストケース


標準のQt GUIアプリケーションを作成し、ウィンドウのメインフォームを開き、そこからコンポーネントを配置し、サービスコントロールを作成し、ビルドして実行します。

「アドレス...」を値0(内蔵ビデオカメラ)に変更し、画像の変化を確認します。



ソースコード: 以前にダウンロードした場合は、クリックしないでください



次は?





すべて最高。




All Articles