Qt 将OpenCV IplImage呈现到QGLWidget

Qt 将OpenCV IplImage呈现到QGLWidget,qt,opengl,opencv,qglwidget,Qt,Opengl,Opencv,Qglwidget,我在渲染OpenGL场景时遇到问题 背景是我想在预览窗口中显示视频捕获设备的帧。我正在使用OpenCV和Qt。为了进行测试,我从MacBook网络摄像头中捕获。预览窗口为200x200,捕获的帧为640x480。我不担心保持纵横比 IplImage结构中的其他信息: 调试:通道:3 调试:深度:8 调试:数据顺序:0 调试:对齐:4。图像行4或8的对齐 调试:源代码:0。0=左上角,1=左下角 调试:步数:2560 调试:colorModel:RGB 所以这张图片显示了当前的情况 我开始使

我在渲染OpenGL场景时遇到问题

背景是我想在预览窗口中显示视频捕获设备的帧。我正在使用OpenCV和Qt。为了进行测试,我从MacBook网络摄像头中捕获。预览窗口为200x200,捕获的帧为640x480。我不担心保持纵横比

IplImage结构中的其他信息:

  • 调试:通道:3
  • 调试:深度:8
  • 调试:数据顺序:0
  • 调试:对齐:4。图像行4或8的对齐
  • 调试:源代码:0。0=左上角,1=左下角
  • 调试:步数:2560
  • 调试:colorModel:RGB
所以这张图片显示了当前的情况

我开始使用glDrawPixels,但效果不好。我得到了输出,但没有缩放

目前我正在尝试使用纹理,下面是我用于GL交互的代码

void VideoCaptureWidget::initializeGL()
{
    qDebug("initializeGL called");
    qglClearColor(QColor::fromRgb(0,0,0));      // set clear colur to black
    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, &m_texture);
    glBindTexture(GL_TEXTURE_2D, m_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,m_texture);
    glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,this->width(),this->height(),0,GL_BGR,GL_UNSIGNED_BYTE,NULL);
    glDisable(GL_TEXTURE_2D);
}


void VideoCaptureWidget::paintGL()
{    
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glDisable(GL_DEPTH_TEST);

    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,m_texture);
    glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,m_image->width,m_image->height,0,GL_BGR_EXT,GL_UNSIGNED_BYTE,m_image->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 VideoCaptureWidget::resizeGL(int width,int height)
{
    qDebug("reszieGL called");

    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();
 }
图像被捕获在一个计时器插槽中,m_图像是一个i_图像指针

void VideoCaptureWidget::_captureFrame() {
    m_image = cvQueryFrame(m_capture);
    if(!m_image) {
        qDebug("VideoCaptureWidget::_captureFrame(): Error capturing a frame...");
    }

    //Draw the scene
    glDraw();
}

我真的希望有人以前见过这种扭曲的图像,知道问题出在哪里

再仔细想想,看看这张图片,我想这一定是字节/通道对齐问题。所以更多的谷歌搜索将mt指向了

glPixelStorei with GL_UNPACK_ALIGNMENT and then also GL_UNPACK_ROW_LENGTH
现在有效的最终代码是:

glPixelStorei(GL_UNPACK_ALIGNMENT, 4 );
glPixelStorei(GL_UNPACK_ROW_LENGTH, m_image->widthStep/m_image->nChannels);
这需要添加到glTexImage2D调用之上


这是一种奇怪的图像数据格式。但这就是苹果iSight内置网络摄像头的输出。希望这对其他人有所帮助。

另一种方法是将BGR帧转换为RGBA,然后使用
glTexImage2D()
将其上载到GPU。我上传了一个完整的演示,请检查

以下是相关代码:

// Note: trying to retrieve more frames than the camera can give you
// will make the output video blink a lot.
cv_capture >> cv_frame;
if (cv_frame.empty())
{
    std::cout << "GLWidget::paintGL: !!! Failed to retrieve frame" << std::endl;
    return;
}
cv::cvtColor(cv_frame, cv_frame, CV_BGR2RGBA);

glEnable(GL_TEXTURE_RECTANGLE_ARB);

// Typical texture generation using data from the bitmap
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _texture);

// Transfer image data to the GPU
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0,
             GL_RGBA, cv_frame.cols, cv_frame.rows, 0,
             GL_RGBA, GL_UNSIGNED_BYTE, cv_frame.data);
if (glGetError() != GL_NO_ERROR)
{
    std::cout << "GLWidget::paintGL: !!! Failed glTexImage2D" << std::endl;
}
//注意:尝试检索的帧数超出了摄影机所能提供的帧数
//将使输出视频闪烁很多。
cv_捕获>>cv_帧;
if(cv_frame.empty())
{

std::谢谢。我也会试试。你认为性能会有什么不同吗?例如,在GL之外进行转换?无需感谢,如果你觉得有趣的话,就投票回答。是的,我的方法可能会慢一点。