2012-04-15 36 views
9

私は一度にいくつかの非常に大きな画像を読み込んで操作する必要があるインタラクティブなアプリケーションに取り組んでいます(一度に25枚、合計350Mb程度)。 OpenCVは非常に高速で、比較的簡単にアルゴリズムを処理します。しかし、Qtでそれらを描くことは問題であることが証明されています。ここで私が試した2つのあまり理想的でない解決法があります。QtとOpenCVの効率的な統合

ソリューション1(遅すぎる)

あなたは、別のOpenCVの画像を描画 QImageに変換し、それを描画する必要があるたびに。残念ながら変換には時間がかかり、 インタラクティブな速度で画像を切り替えることはできません。

溶液2(すぎメモリ集約)

画像の2つのスタック、OpenCVのための1とQtのための1つを維持します。適切なタイミングで適切な を使用してください。

私はOpenCVピクセルデータに直接アクセスできます。私は画像の幅と高さを知っており、ピクセルは3バイトのRGB値であることを知っています。 OpenCVの画像を(それがわかる限りは)データの複製だけを含むQImageコンテナにコピーせずにすばやく描画することが可能なようです。

Qtからこのような機能を得るには、どこで調べる必要がありますか?

答えて

5

QImageとopenCVの間でデータを共有することができます。どちらも、ポインタによって提供される既存のデータを使用するctorを持っています。

cv::Mat(int _rows, int _cols, int _type, void* _data, size_t _step=AUTO_STEP)
QImage (uchar * data, int width, int height, int bytesPerLine, Format format)

行は4バイトの倍数になってしまうしませんが、私はパディングが同じピクセルサイズとの両方のタイプに合わせることを期待する場合には、パディングに問題があるかもしれない - で少なくとも同じハードウェア上にある

openCVはデフォルトでBGRを使用しますが、これはQImage(または他のディスプレイ)にはあまり最適ではありません。 QImage :: Format_ARGB32_Premultipliedが、QImageをレンダリングするためにアクセラレーションされたOpenGLを使用するQtでは、はるかに速くなっていることは確かではありません。

代わりにopencvを使用して、結果のデータをOpenGLテクスチャに直接コピーし、QGlWidgetを使用して別のコピーなしでイメージを表示することもできます。

+0

BGRのことは間違いありません。 OpenCVに画像をBGR形式(QtのRGBと同等ですが、残念ながらQtにはBGR形式がありません)で保存するように依頼することで、この問題を回避しています。つまり、OpenCVのルーチンに注意する必要がありますが、問題ではありません。また、OpenGLのテクスチャオプションも見ていきます。ありがとう! – Calvin

+0

FWIW、それは効率的かどうかわからないので、メソッドQImage :: rgbSwappedはRGBをBGRに変換します。http://qt-project.org/doc/qt-5.0/qtgui/qimage.html#rgbSwappedを参照してください。私はこのプロジェクトのソースコードからこれを学びました:http://code.google.com/p/qt-opencv-multithreaded/ –

+0

@JongBorそれは、ディスプレイAPIがBGRAを使う傾向があるという問題であるRGB/BGRではないことを教えてください(QImageを含む)画像処理APIはBGRを使用しているので、画像全体を渡り、余分な「A」バイトをパディングする必要があります。 –

8

3ヶ月後にこれが役に立つかどうかはわかりません。しかし、私はOpenCVを使って一連の画像を操作し、それをQTインタフェース上に表示する必要があるのと同じ種類のアプリケーションを持っています。かなりの周りでグーグルグーグルをした後、私は非常に滑らかなソリューションを見つけた。 OpenGLのglDrawPixelsを使用して、生の画像データを直接Qtインタフェースに描画します。最高の部分は、あなたは余分なコンバージョンコードを書く必要はありません。ビューポートと座標を設定するためのopenglの基本コード。 IplImage *ポインタを取得し、そのデータを使って画像を描画する関数を持つコードを調べてください。特定のサイズの画像を表示するには、パラメータ(特にWIDTHとHEIGHT変数)を微調整する必要があるかもしれません。 そして、私はあなたが使っているシステムをどのように構築しているのか分かりません。私はcmakeを使い、QtのOpenGLライブラリを使用していますが、OpenGLの依存関係をセットアップする必要がありました。

QGLWidgetから派生したクラスQIplImageを実装し、paintGLメソッドをオーバーライドしてピクセルデータをフレームに描画しました。

//File qiplimage.h 
class QIplImage : public QGLWidget 
{ 
    Q_OBJECT 

public: 
    QIplImage(QWidget *parent = 0,char *name=0); 
    ~QIplImage(); 
    void paintGL(); 
    void initializeGL(); 
    void resizeGL(int,int); 
    bool drawing; 

public slots: 
    void setImage(IplImage); 

private: 
    Ui::QIplImage ui; 
    IplImage* original; 
    GLenum format; 
    GLuint texture; 
    QColor bgColor; 
    char* name; 
    bool hidden; 
    int startX,startY,endX,endY; 
    QList<QPointF*> slopes; 
    QWidget* parent; 
    int mouseX,mouseY; 

}; 
//End of file qiplimage.h 

//file qiplimage.cpp 
#include "qiplimage.h" 
#include <Globals.h> 

QIplImage::QIplImage(QWidget *parent) : 
    QGLWidget(parent) 
{ 

} 
QIplImage::QIplImage(QWidget *parent,char* name): QGLWidget(parent) 
{ 
    ui.setupUi(this); 
    //This is required if you need to transmit IplImage over 
    // signals and slots.(That's what I am doing in my application 
    qRegisterMetaType<IplImage>("IplImage"); 
    resize(384,288); 
    this->name=name; 
    this->parent=parent; 
    hidden=false; 
    bgColor= QColor::fromRgb(0xe0,0xdf,0xe0); 

    original=cvCreateImage(cvSize(this->width(),this->height()),IPL_DEPTH_8U,3); 
    cvZero(original); 
    switch(original->nChannels) { 
     case 1: 
      format = GL_LUMINANCE; 
      break; 
     case 2: 
      format = GL_LUMINANCE_ALPHA; 
      break; 
     case 3: 
      format = GL_BGR; 
      break; 
     default: 
      return; 
} 
    drawing=false; 
    setMouseTracking(true); 
    mouseX=0;mouseY=0; 
    initializeGL(); 

} 
void QIplImage::initializeGL() 
{ 
    qglClearColor(bgColor); 
    //glClearColor(0.5f, 0.5f, 0.5f, 1.0f);    
    glDisable(GL_DEPTH_TEST); 
    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); 
     glOrtho(0,this->width(),this->height(),0.0f,0.0f,1.0f); 
    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity(); 

    glEnable(GL_TEXTURE_2D); 
    glGenTextures(3,&texture); 
    glBindTexture(GL_TEXTURE_2D,texture); 
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); 
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); 
    glBindTexture(GL_TEXTURE_2D,texture);    glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,this->width(),this->height(),0,GL_BGR,GL_UNSIGNED_BYTE,NULL); 
    glDisable(GL_TEXTURE_2D); 


} 
void QIplImage::setImage(IplImage image){ 
original=&image; 
//cvShowImage(name,original); 

updateGL(); 
} 

void QIplImage::paintGL(){ 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
glDisable(GL_DEPTH_TEST); 
if(!hidden){ 
    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); 
      glOrtho(0.0f,this->width(),this->height(),0.0f,0.0f,1.0f); 
    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity(); 
    glEnable(GL_TEXTURE_2D); 
      glBindTexture(GL_TEXTURE_2D,texture); 
      glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,original->width,original->height,0,GL_BGR_EXT,GL_UNSIGNED_BYTE,original->imageData); 
    glBegin(GL_QUADS); 
      glTexCoord2i(0,1); glVertex2i(0,this->height()); 
    glTexCoord2i(0,0); glVertex2i(0,0); 
      glTexCoord2i(1,0); glVertex2i(this->width(),0); 
      glTexCoord2i(1,1); glVertex2i(this->width(),this->height()); 
    glEnd(); 
    glFlush(); 
    } 

} 


void QIplImage::resizeGL(int width,int height){ 

    glViewport(0,0,this->width(),this->height()); 
    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity();  
    glOrtho(0.0f,this->width(),this->height(),0.0f,0.0f,1.0f); 
    glMatrixMode(GL_MODELVIEW);   
    glLoadIdentity(); 
} 

希望します。

+1

アプリケーションには、画像の上に描画されるオーバーレイがいくつかあります(画像そのものではなく、画面上の上に描画されます)。 OpenGLのビューは、この種のことについて少し奇妙な傾向があります。私はこのアプローチが気に入っていますが、Qtの描画ルーチンからOpenGLの描画ルーチンにコードの一部を移植する必要があるということです。しかし、素晴らしいコードサンプルのために+1。 – Calvin

+0

glDrawPixelsのアップデートが遅く、バグがありました。私は代わりにテクスチャクワッドを使用しました。性能はメモリリークやその他のバグがなくても素晴らしいです。 –

+0

@RichardMacwanこの 'glDrawPixels'バージョンの代わりに 'textured quad'バージョンを共有できますか? – klefevre

関連する問題