将数据从glReadPixels()转换为OpenCV :: Mat

Jav*_*ock 21 c++ opengl opencv glreadpixels

我想通过glReadPixels()从动画中获取每个OpenGL帧,并将数据转换为OpenCV :: Mat.我知道glReadPixels()从左到右按行从下一行到上一行获取数据.另一方面,OpenCV以不同方式存储数据.

有没有人知道任何库或任何帮助我将数据从glReadPixels转换为OpenCV的教程/示例: C++中的Mat

摘要

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

Data from left to right,                    Data from left to right,
bottom to top.                              top to bottom.
Run Code Online (Sandbox Code Playgroud)

Chr*_*ica 46

首先,我们cv::Mat为我们的数据创建一个空(或unititialized)直接读入.这可以在启动时完成一次,但另一方面cv::Mat::create,当图像已经具有匹配的大小和类型时,实际上并不会花费太多.类型取决于您的需求,通常类似于CV_8UC324位彩色图像.

cv::Mat img(height, width, CV_8UC3);
Run Code Online (Sandbox Code Playgroud)

要么

img.create(height, width, CV_8UC3);
Run Code Online (Sandbox Code Playgroud)

然后你必须考虑cv::Mat不连续存储图像行连续.每行末尾可能有一个小的填充值,使行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());
Run Code Online (Sandbox Code Playgroud)

接下来,矩阵的类型会影响格式和类型参数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);
Run Code Online (Sandbox Code Playgroud)

最后,OpenCV从上到下存储图像.所以你可能需要在获得它们之后翻转它们或者首先在OpenGL中渲染它们(这可以通过调整投影矩阵来完成,但在这种情况下要注意三角形方向).要cv::Mat垂直翻转,您可以使用cv::flip:

cv::flip(img, flipped, 0);
Run Code Online (Sandbox Code Playgroud)

所以要记住OpenCV:

  • 从上到下,从左到右存储图像
  • 以BGR顺序存储彩色图像
  • 可能无法存储紧密打包的图像行