11

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

解決策 1 (遅すぎる)

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

解決策 2 (メモリを大量に消費する)

OpenCV 用と Qt 用の 2 つのイメージ スタックを維持します。適切なタイミングで適切なものを使用してください。

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

この種の機能を Qt から取得するには、どこを探す必要がありますか?

4

2 に答える 2

10

3か月経った今、これがあなたに役立つかどうかはわかりません。しかし、OpenCV を使用して画像のストリームを操作し、QT インターフェイスに表示する必要がある同じ種類のアプリケーションを使用しています。かなりグーグルで調べた後、非常に洗練されたソリューションに出くわしました。opengl の glDrawPixels を使用して、生の画像データを Qt インターフェイスに直接描画します。最良の部分は、追加の変換コードを記述する必要がないことです。ビューポートと座標を設定するための opengl の基本的なコードです。IplImage* ポインターを受け取り、そのデータを使用して画像を描画する関数を含むコードを確認してください。特定のサイズの画像を表示するには、パラメーター (特に WIDTH 変数と HEIGHT 変数) を少し調整する必要がある場合があります。そして、ええ、私はあなたが使用しているビルドシステムを知りません。

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

それが役立つことを願っています。

于 2012-07-20T12:37:59.627 に答える
7

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バイトの倍数にならない場合、パディングに問題がある可能性がありますが、少なくとも同じハードウェアでは、同じピクセルサイズの両方のタイプでパディングが整列すると予想されます

1 つの問題は、openCV がデフォルトで BGR を使用することです。これは、QImage (またはその他のディスプレイ) には最適ではありません。QImage::Format_ARGB32_Premultiplied が、QImage のレンダリングに高速化された openGL を使用する Qt では、必ずしもそれほど高速であるかどうかはわかりませんが。

別の方法として、opencv を使用し、結果のデータを直接 openGL テクスチャにコピーしてから、QGlWidget を使用して別のコピーなしで画像を表示する方法があります。

于 2012-04-15T04:02:56.607 に答える