从glReadPixels()来的OpenCV ::垫

问题描述:

转换数据我想从动画每一帧的OpenGL与glReadPixels()和数据转换为的OpenCV ::垫。我知道glReadPixels()按从左到右的顺序从低位到高位获取数据。另一方面,OpenCV以不同的方式存储数据。从glReadPixels()来的OpenCV ::垫

有谁知道任何图书馆或任何教程/例子,可以帮助我把数据从glReadPixels转换为OpenCV的:在C++垫

摘要

OpenGL frame  ----------------------->  CV::Mat 

Data from left to right,     Data from left to right, 
bottom to top.        top to bottom. 

首先,我们为我们的数据空(或unititialized)cv::Mat读入直接。这可以在启动时完成一次,但另一方面cv::Mat::create并没有真正花费太多时,图像已经具有匹配的大小和类型。类型取决于您的需求,通常它是类似于CV_8UC3的24位彩色图像。

cv::Mat img(height, width, CV_8UC3); 

img.create(height, width, CV_8UC3); 

那么你必须考虑cv::Mat不neccessarily存储图像行连续。在每行末尾可能会有一个小的填充值,以使行4字节对齐(或8?)。所以,你需要惹像素存储模式:

//use fast 4-byte alignment (default anyway) if possible 
glPixelStorei(GL_PACK_ALIGNMENT, (img.step & 3) ? 1 : 4); 

//set length of one complete row in destination data (doesn't need to equal img.cols) 
glPixelStorei(GL_PACK_ROW_LENGTH, img.step/img.elemSize()); 

接下来,矩阵的类型影响的glReadPixels的格式和类型参数。如果你需要彩色图像,你必须牢记OpenCV通常以BGR顺序存储颜色值,所以你需要使用GL_BGR(A)(这是OpenGL 1.2中添加的)而不是GL_RGB(A)。对于一个分量图像,请使用GL_LUMINANCE(它将各个颜色分量相加)或GL_RED,GL_GREEN,...(以获取单个分量)。所以对于我们的CV_8UC3图像的最终调用直接读入cv::Mat是:

glReadPixels(0, 0, img.cols, img.rows, GL_BGR, GL_UNSIGNED_BYTE, img.data); 

最后,OpenCV的商店图片来自上下。因此,您可能需要在获取它们后将它们翻转或在OpenGL中翻转它们(这可以通过调整投影矩阵来完成,但在这种情况下请注意三角形的方向)。要翻转cv::Mat垂直,您可以使用cv::flip

cv::flip(img, flipped, 0); 

所以要记住OpenCV的:从上到下

  • 将影像存储,从左至右
  • 专卖店在BGR顺序彩色图像
  • 可能无法存储图像行排列紧密
+0

真的很不错的答案。我已经在研究翻转,但我没有注意到glPixelStorei。谢谢 – 2012-02-01 16:34:22

+0

我不能调用GL_BGR,我不知道为什么连接器找不到它,因为我有最新版本 – 2012-02-01 16:37:10

+1

@Jav_Rock它是在OpenGL 1.2中引入的。因此,如果你的硬件和驱动程序支持它(这很有可能,除非你在20年前买了你的显卡),你只需要定义这个符号,包括一个合理的新['glext.h'](http:// www.opengl.org/registry/api/glext.h),或者首先使用扩展管理库(如GLEW),它应该为自己的头文件定义常量。无论如何,一旦你想使用高于1.1的任何功能(如PBO,这可能会加快你正常使用时的读取性能),这将是必要的。 – 2012-02-01 16:39:56

unsigned char* getPixelData(int x1, int y1, int x2, int y2) 
{ 
    int y_low, y_hi; 
    int x_low, x_hi; 

    if (y1 < y2) 
    { 
     y_low = y1; 
     y_hi = y2; 
    } 
    else 
    { 
     y_low = y2; 
     y_hi = y1; 
    } 

    if (x1 < x2) 
    { 
     x_low = x1; 
     x_hi = x2; 
    } 
    else 
    { 
     x_low = x2; 
     x_hi = x1; 
    } 

    while (glGetError() != GL_NO_ERROR) 
    { 
     ; 
    } 

    glReadBuffer(GL_BACK_LEFT); 

    glDisable(GL_TEXTURE_2D); 

    glPixelStorei(GL_PACK_ALIGNMENT, 1); 

    unsigned char *data = new unsigned char[ (x_hi - x_low + 1) * (y_hi - y_low + 1) * 3 ]; 

    glReadPixels(x_low, y_low, x_hi-x_low+1, y_hi-y_low+1, GL_RGB, GL_UNSIGNED_BYTE, data); 

    if (glGetError() != GL_NO_ERROR) 
    { 
     delete[] data; 
     return 0; 
    } 
    else 
    { 
     return data; 
    } 
} 

使用:

CvSize size = cvSize(320, 240); 

unsigned char *pixel_buf = getPixelData(0, 0, size.width - 1, size.height - 1); 

if (pixel_buf == 0) 
    return 0; 

IplImage *result = cvCreateImage(size, IPL_DEPTH_8U, 3); 
memcpy(result->imageData, pixel_buf, size.width * size.height * 3); 
delete[] pixel_buf;