关于c ++:Qt和OpenCV的有效集成

Efficient integration of Qt and OpenCV

我正在开发一个交互式应用程序,该应用程序需要一次读取和处理几张非常大的图像(一次25张图像,总大小约为350 Mb)。 OpenCV相当快,并且相对容易地处理算法。 但是事实证明,用Qt绘制它们是一个问题。 这是我尝试过的两种不理想的解决方案。

Solution 1 (too slow)

Every time you need to draw a different OpenCV image, convert it to a
QImage and draw that. The conversion, unfortunately, takes a while and
we cannot switch between images at interactive speeds.

Solution 2 (too memory-intensive)

Maintain two stacks of images, one for OpenCV and one for Qt. Use the
appropriate one at the appropriate time.

我可以直接访问OpenCV像素数据。 我知道图像的宽度和高度,并且我知道像素是3字节RGB值。 似乎应该可以快速绘制OpenCV图像,而无需将其复制到(据我所知)仅包含数据重复项的QImage容器中。

我应该在哪里寻找从Qt中获得这种功能的地方?


我不知道这在3个月后对您是否有用。但是我使用的是同一种应用程序,必须使用OpenCV处理图像流并将其显示在QT界面上。在四处搜寻之后,我遇到了一个非常巧妙的解决方案。使用opengl的glDrawPixels直接在Qt界面上绘制原始图像数据。最好的部分是,您不必编写任何额外的转换代码。只是opengl用于设置视口和坐标的基本代码。签出具有使用IplImage *指针并使用该数据绘制图像的函数的代码。您可能需要微调参数(尤其是WIDTH和HEIGHT变量)以显示具有特定大小的图像。
是的,我不知道您使用的是什么构建系统。尽管我使用的是Qt的opengl库,但我使用cmake并必须为opengl设置依赖项。

我实现了一个从QGLWidget派生的QIplImage类,并重写了它的paintGL方法以将像素数据绘制到帧上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
//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();
 }

希望能有所帮助。


您可以在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是否一定在Qt上更快,Qt使用加速的openGL渲染QImage。

一种替代方法是使用opencv,然后将结果数据直接复制到openGL纹理中,然后使用QGlWidget显示图像而无需其他复制。