Miyabiarts.net

一年に一度の更新頻度

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+OpenGLで画像を表示」への1件のフィードバック

  1. ピンバック:Tweets that mention Qt+OpenCV+OpenGLで画像を表示 | Miyabiarts.net -- Topsy.com

%d人のブロガーが「いいね」をつけました。