我正在开发一个交互式应用程序,它需要一次读取和操作几个非常大的图像(一次25个图像,总大小约350 Mb).OpenCV非常快速,并且相对容易处理算法.但用Qt绘制它们证明是一个问题.以下是我尝试过的两种不太理想的解决方案.
解决方案1(太慢)
每次需要绘制不同的OpenCV图像时,将其转换为a
QImage
并绘制它.不幸的是,转换需要一段时间,我们无法以交互速度在图像之间切换.解决方案2(内存密集型)
保持两叠图像,一个用于OpenCV,另一个用于Qt.在适当的时候使用适当的一个.
我可以直接访问OpenCV像素数据.我知道图像的宽度和高度,我知道像素是3字节的RGB值.看起来应该可以快速绘制OpenCV图像而不将其复制到QImage
容器(据我所知)只包含数据的副本.
我在哪里需要从Qt中获得这种功能?
我不知道3个月后这对你是否有用.但我有相同的应用程序,我必须使用OpenCV操作图像流并在QT界面上显示它.在谷歌搜索了很多,我遇到了一个非常光滑的解决方案.使用opengl的glDrawPixels直接在Qt界面上绘制原始图像数据.最好的部分,你不必编写任何额外的转换代码.只是opengl的基本代码,用于设置视口和坐标.查看具有函数的代码,该函数采用IplImage*指针并使用该数据绘制图像.您可能需要稍微调整参数(尤其是WIDTH和HEIGHT变量)以显示具有特定大小的图像.是的,我不知道你正在使用什么构建系统.我使用cmake并且必须为opengl设置依赖项,尽管我使用的是Qt的opengl库.
我已经实现了一个类QIplImage,它派生自QGLWidget并覆盖其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=ℑ
//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();
}
Run Code Online (Sandbox Code Playgroud)
希望有所帮助.
您可以在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(或任何其他显示器)来说不是最佳的.虽然我不确定Qtmage :: Format_ARGB32_Premultiplied在Qt上使用加速的openGL渲染QImage会更快.
另一种方法是使用opencv然后将结果数据直接复制到openGL纹理,然后使用QGlWidget显示图像而不需要另一个副本.