Miyabiarts.net

一年に一度の更新頻度

カテゴリーアーカイブ: Qt

Qt名古屋勉強会

関西ゲームプログラミング勉強会の時に補足されたようで、そこからお話があって、発表させていただくことになりました。
名古屋ではQt勉強会は初ということで、結構注目されていたようです。

  • 日付:2011年7月9日(土) 13:00 – 17:30
  • 場所: 株式会社 エイチーム セミナールーム1 (名古屋市西区牛島町6番1号 名古屋ルーセントタワー32F)
  • イベントページ:http://atnd.org/events/16926

元々は物理エンジンBulletについて話すことでしたが、そのままだとQt全く関係なかったりしますし、普段3Dを触ってない方には分からない点も多かろうと、丁度良く出ていたQtの3D周りを扱うQt/3Dとともに紹介することにしました。
Qt/3Dのインストール方法などは前の記事で書いています。

発表資料はこちらに置いておきます。
内容としては、前半はQt/3Dで、後半はBulletについて話しました。
前半については自分もQt/3Dは初めてだったのでなるべく分かりやすい資料を作っていたのですが、後半のBulletは関西ゲームプログラミング勉強会のものをほとんどそのまま使っていたら、自分で話していて、あぁコード量多くて、普段やっていない人には分かりづらいな。と感じてしまい、その点では反省しているところです。
ただ、一応デモとして見えるものは作っていたので、なんとなくでも理解していただけたようなので、それは良かったです。
あと、最初にQtで作っていたものとして、3Dモデラをちょっと紹介していましたが、言葉足らずでメタセコイアの開発者と間違えられたようで、どうもすみません。
ちなみに3Dモデラの方は現在再開発中で、ひと通りできたらシェアウェアとして公開しようかと考えております。

他の方の発表では、Qt5の紹介、QMLのライブコーディング、MeeGoの紹介と名前は知っているけど、実際はあまり理解していなかったものを詳しく聴けたため、とても面白かったです。
特にQMLは手軽にアニメーションできるUIを作れるので楽で良いなと思いました。

懇親会は、名古屋に結構長く居るのに行ったことがなかった世界の山ちゃんでした。
他の勉強会とはまた違った方向性の面白さがあり、懇親会中ずっと話しておりました。
それと、とにかく言われていたことは「英語を勉強しろ」でした。
英語を勉強して、海外に行きましょうかな。本気で。

二次会として立ち飲み居酒屋に行って、また色々話させて頂き、最後まで楽しい時間を過ごせました。
次回があれば、またなんだか発表しそうな雰囲気が漂っていましたが、時間がある限り、いくらでも発表しますので是非お願いいたします。

最後にですが、本当に暑い日でした。
名古屋駅前は40度近くの外気温があり、汗が止めどなく出る状態でした。

広告

Qt/3Dのインストール

今週末の土曜にQt名古屋勉強会でQt/3Dについて話すこともあり、インストール方法くらいは書いておこうかと思います。
情報としては、公式ドキュメントとほぼ同じです。
対象とする環境は、Windows・VisualStudioとなります。

Qt/3Dは、以前からあったOpenGLまわりをより充実させたもので、最近のOpenGLに合わせた設計となっています。
具体的にはGLSLシェーダを用いたレンダリングですが、これだけだと些か面倒くさいところもあるので、もう一段階ラッパしており、従来の固定機能みたいな使いかたもできます。
単純な図形や、カメラ・ライトなどをシーングラフとして持つこともできるため、非常に扱いやすくなっています。

将来的(Qt5以降?)では、標準のものとして統合されるでしょうが、現段階(Qt4.7)ではQtLabの方にあるので、自分でインストールする必要があります。
今回は、このインストール方法を簡単に紹介します。

ソースコードの入手

ソースコードはQtLabのgitリポジトリに存在していますため、WindowsならばTortoiseGitなどの環境を構築しておいてください。
あらかじめインストールしていたQtのディレクトリ(例えば、C:\Qt4.7)以下にディレクトリ(ここではqt-labs)を作成し、そこにqt3dのソースコードをcloneします。
gitリポジトリのURLは「git://gitorious.org/qt-labs/qt3d.git」です。

インストール

ソースコードのビルドは、Qt本体と同じように行います。
VisualStudioのプロンプトを開き、ソースコードを取得したディレクトリ(C:\Qt4.7\qt-labs\qt3d)に移動します。
そして、以下のコマンドによりビルド・インストールが行えます。
なお、qmake.exeへのパスは事前に通しておいてください。

qmake.exe
nmake
nmake install

これによって、元のQtのディレクトリ以下にQt/3D関連のヘッダファイルやライブラリがインストールされます。

.proファイルの設定

Qt/3D関連の機能を使う際には、対応したライブラリをリンクする必要があります。
公式ドキュメントでは「CONFIG+=system_3ds」とすれば良さそうですが、これだと上手くいかなかったため、以下のように直接ライブラリをリンクするように指定しました。

LIBS += -lQt3D

実際に3Dオブジェクトをレンダリングするためには、QGLViewなどを使っていけば良いのですが、今回は割愛します。
サンプル・チュートリアルを一通り見れば、大体は分かるかと思います。
Qt名古屋勉強会では、ここらへんの話を発表する予定です。

Qt+OpenCV+OpenGLで画像を表示

昨日予告したばかりですが、今度はQt+OpenGLを用いて、OpenCVの画像(cv::Mat_)を表示するGUIの実装を紹介します。

今回も、対象とするOpenCVは2.2以上で、C++インタフェースのみを対象としています。 画像形式は、グレースケール画像(cv::Mat_)とRGB画像(cv::Mat_)です。

実装は下記の通りで、QGLWidgetを継承したViewportクラスを作成しています。

#include <QWidget>
#include <QImage>
#include <opencv2/opencv.hpp>

// 画像表示用ウィジェット(OpenGL)
class Viewport : public QGLWidget
{
public:
  //
  Viewport( QWidget *parent = 0, QGLWidget *shared = 0 ) :
    QGLWidget( parent, shared ),
    updated_( true )
  {
  }

  // OpenGL初期化
  void initializeGL()
  {
    // テクスチャを生成
    glEnable( GL_TEXTURE_2D );
    glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
    glGenTextures( 1, &amp;texId_ );
    glBindTexture( GL_TEXTURE_2D, texId_ );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
    glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );

    // タイマー設定
    QTimer *timer = new QTimer( this );
    connect( timer, SIGNAL( timeout() ), this, SLOT( updateGL() ) );
    timer-&gt;setInterval( 30 );
    timer-&gt;setSingleShot( false );
    timer-&gt;start();
  }

  // 描画
  void paintGL()
  {
    // ビューポートの大きさをウィンドウと一致させる
    glViewport( 0, 0, width(), height() );

    glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
    glClear( GL_COLOR_BUFFER_BIT );

    // 射影行列を単位行列にする
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();

    // ワールド行列も単位行列にする
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();

    glEnable( GL_TEXTURE_2D );
    glBindTexture( GL_TEXTURE_2D, texId_ );
    if( !updated_ )
      {
	// テクスチャを更新
	glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA , img_.width(), img_.height(), 0, GL_BGR , GL_UNSIGNED_BYTE, img_.bits() );
	updated_ = true;
      }

    // テクスチャを設定した画面サイズの矩形を描画
    glColor3d( 1.0, 1.0, 1.0 );
    glBegin( GL_QUADS );
    glTexCoord2d( 0.0, 0.0 );
    glVertex2d( -1.0, -1.0 );
    glTexCoord2d( 1.0, 0.0 );
    glVertex2d( 1.0, -1.0 );
    glTexCoord2d( 1.0, 1.0 );
    glVertex2d( 1.0, 1.0 );
    glTexCoord2d( 0.0, 1.0 );
    glVertex2d( -1.0, 1.0 );
    glEnd();
  }

  // 画像を設定(グレースケール画像用)
  void setImage( const cv::Mat_< unsigned char > &img )
  {
    // 画像作成
    cv::cvtColor( img, tmp, CV_GRAY2BGR );
    img_ = QImage( tmp.data, img.cols, img.rows, QImage::Format_RGB888 );
    img_ = QImage( img.data, img.cols, img.rows, QImage::Format_RGB888 );

    // OpenGL用に画像変換
    img_ = QGLWidget::convertToGLFormat( img_ );

    // テクスチャ更新を設定
    updated_ = false;
  }

  // 画像を設定(RGB画像用)
  void setImage( const cv::Mat_< cv::Vec3b > &img )
  {
    // 画像を作成
    img_ = QImage( img.data, img.cols, img.rows, QImage::Format_RGB888 );

    // OpenGL用に画像変換
    img_ = QGLWidget::convertToGLFormat( img_ );

    // テクスチャ更新を設定
    updated_ = false;
  }

private:
  QImage img_; // 内部用画像
  GLuint texId_; // OpenGLテクスチャ
  bool updated_; // テクスチャ更新フラグ
};

QGLWidgetを継承したクラスでは、作成時にinitializeGLが呼ばれるため、ここでテクスチャを作成した後、タイマーを設定することで、定期的にOpenGLによる画面更新を行うようにしています。
画面の描画は、paintGLで行なっており、画面の座標系をXY軸ともに[-1,1]の範囲となるようにプロジェクション行列・ワールド行列を単位行列にした上で、画面いっぱいにテクスチャを貼りつけた矩形を描画しています。
今回気をつける点として、GUIが表示された後にテクスチャを更新しないと上手く表示されないため、画面描画中にsetImageにより画像が更新されていたならば、テクスチャの更新を行うようにしてます。

OpenGLの場合、画像の幾何変換などがより簡単に行えるため、paintGL内での描画を変更したり、マウスイベントに対する処理を加えることで色々な見せ方をすることが出来ます。

Qt+OpenCVで画像を表示

OpenCV2.2から、OpenCVに対してQtを組み込むことが出来ますが、反対のQtにOpenCVを組み込む方法を今更紹介します。
組み込むというか、単純にOpenCVの画像をQtのWidgetで表示するだけです。
表示するためのクラスとして、QWidget(もしくは、QDialog)を継承したImageWidgetクラスを作成します。

対象とするOpenCVは2.2以上で、C++インタフェースのみを対象としています。
画像形式は、グレースケール画像(cv::Mat_)とRGB画像(cv::Mat_)です。
ちなみにエラー処理は行っていないため、設定する画像形式を間違ったらおかしなことになるでしょう。

あまり詳しい説明はしないのですが、下記がImageWidgetクラスの実装となります。

#include <QWidget>
#include <QImage>
#include <opencv2/opencv.hpp>

// 画像表示用ウィジェット
class ImageWidget : public QImage
{
public:
  // 画像を設定(グレースケール画像用)
  void setImage( const cv::Mat_< unsinged char > &img )
  {
    // 画像作成
    cv::Mat_< unsigned char > tmp;
    cv::cvtColor( img, tmp, CV_GRAY2BGR );
    img_ = QImage( tmp.data, img.cols, img.rows, QImage::Format_RGB888 );

      // 更新
     update();
  }

  // 画像を設定(RGB画像用)
  void setImage( const cv::Mat_< cv::Vec3b > &img )
  {
    // 画像を作成
    img_ = QImage( img.data, img.cols, img.rows, QImage::Format_RGB888 );

    // 更新
    update();
  }
private:
  QImage img_;  // 保持するための画像

  // 描画
  void paintEvent( QPaint  * )
  {
    QPainter painter( this );
    // 画像を描画
    painter.drawImage( QPoint( 0, 0 ), img_ );
  }
};

やっていることは、単純にメンバ変数としてQtで画像を扱うQImageのインスタンスを保持しておいて、setImageが呼び出されたら、内部でcv::Mat_からQImageに対応する画素のコピーしているだけです。注意することは、cv::Mat_はあくまで行列なのでQImageとは画像の方向が異なることです。

利点としては、、OpenCVからQtを使うためには色々とめんどくさいことをしないといけないのですが、こちらはQtに対してOpenCVを組み込むので、普通にQtはQtとして使うことができます。
より便利にするためには、元のOpenCVの画像を参照として持っておいて、そちらに変化したら表示も変わるようにするとかですかね。

やりかたは概ね同じであるため、OpenGLで表示させるようにQGLWidgetを継承したクラスについてもいずれ載せたいと思います。