OpenCV + OpenGL - 获取 OpenGL 图像作为 OpenCV 相机

Posted

技术标签:

【中文标题】OpenCV + OpenGL - 获取 OpenGL 图像作为 OpenCV 相机【英文标题】:OpenCV + OpenGL - Get OpenGL image as OpenCV camera 【发布时间】:2013-10-23 23:15:41 【问题描述】:

我想获取一个 OpenGL 图像并将其提供给 OpenCV 进行分析(作为 OpenCV 算法的模拟器),但我没有找到太多关于它的信息,我只能找到相反的方法(放置一个 OpenCV OpenGL 中的图像)。有人能解释一下怎么做吗?

编辑:

我将在机器人顶部模拟相机,因此我将实时渲染 3D 环境并在 Qt GUI 中为用户显示它。我将为用户提供使用真实网络摄像头馈送或模拟 3D 场景(随着机器人移动而变化)的选项,并且 OpenCV 算法对于两种输入都是​​相同的,因此用户可以测试他的代码而无需使用真实的一直都是机器人。

【问题讨论】:

在这种情况下“OpenGL 图像”是什么意思?质感?渲染到帧缓冲区的场景?渲染到某个屏幕外缓冲区的场景? @MatsPetersson 我用更多解释更新了这个问题 @MatsPetersson 我想它是“渲染到帧缓冲区的场景”选项,更清楚。我仍在更深入地学习 OpenGL,因此我试图找到有关我必须阅读的所有内容的更多信息,但我找不到太多...欢迎任何方向! 对,所以如果你渲染到离屏缓冲区,你应该能够将离屏缓冲区转换为图像(事实上,只要你对离屏足够了解缓冲区,我认为应该可以从中创建 IPLImage)。 @MatsPetersson 如果我渲染到屏幕外缓冲区,我不会看到正在渲染的场景吗?为什么我不能使用屏幕缓冲区? 【参考方案1】:

您可能正在寻找函数glReadPixels。它会将 OpenGL 当前显示的内容下载到缓冲区中。

unsigned char* buffer = new unsigned char[width*height*3];
glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer);
cv::Mat image(height, width, CV_8UC3, buffer);
cv::imshow("Show Image", image);

对于 OpenCV,您可能还需要翻转并转换为 BGR。

编辑:由于仅使用 glReadPixels 并不是一种非常有效的方法,因此这里有一些使用帧缓冲区和像素缓冲区对象来有效传输的示例代码: How to render offscreen on OpenGL?

【讨论】:

我是 OpenCV 新手,BGR 是特定的东西还是只是 RGB 倒退? 请注意,glReadPixels 是让 300 美元的显卡产生 5 fps 的绝佳方法,因为每次调用 glReadPixels 时,图形芯片都必须耗尽整个工作流水线。如果您听说过 CPU 中的“分支错误预测”,那也是同样的情况,但要差 10000 倍。 @MatsPetersson 该死的,它看起来像一个干净的解决方案......你有什么更好的选择,也许我可以搜索一些代码? 就像我说的,在屏幕外绘制,然后用屏幕外绘制制作一个四边形。 当然,如果您不需要 100+ fps,并且您不是每帧绘制 2000 万个三角形,它可能工作得很好。我只是指出这有点像在繁忙的城市交通中驾驶法拉利跑车 - 你不会经常使用全部动力,或者很长时间......【参考方案2】:

我在以前的研究项目中做过。这里没有太大的困难。

你要做的基本上是:

将纹理从 OpenGL 读取到某个预先分配的内存缓冲区; 应用一些几何变换(翻转 X 和/或 Y 坐标)来解释 OpenGL 和 OpenCV 之间可能不同的坐标系。这是一个细节,但有助于可视化(提示:使用内部带有 F 字母的纹理来快速找到需要翻转的坐标!); 您可以直接围绕预分配的内存缓冲区构建 OpenCV cv::Matobject,然后直接对其进行处理或将其复制到其他矩阵对象并进行处理。

如另一个答案所示,读取 OpenGL 纹理很简单,只需调用 glRead() 函数即可。 您得到的通常是 3 或 4 个通道,每个数据 8 位(RGB / RGBA - 每个通道 8 位),尽管它可能取决于您的实际 OpenGL 上下文。

如果颜色对您很重要,您可能需要(但不是必须)将 RGB 图像数据转换为 BGR 格式(蓝 - 绿 - 红)。由于历史原因,这是 OpenCV 中默认的颜色通道排序。 例如,您可以通过调用 cv::cvtColor(source, dest, cv::COLOR_RGB2BGR) 来执行此操作。

【讨论】:

【参考方案3】:

我的研究需要这个。 我接受了 littleimp 的建议,但修复颜色和翻转图像需要宝贵的时间来弄清楚。

这就是我最终的结果。

typedef Mat Image ;

typedef struct 
  int width;
  int height;
  char* title;
  float field_of_view_angle;
  float z_near;
  float z_far;
 glutWindow;

glutWindow win;

Image glutTakeCVImage() 
  // take a picture within glut and return formatted
  // for use in openCV
  int width = win.width;
  int height = win.height;
  unsigned char* buffer = new unsigned char[width*height*3];
  glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer);
  Image img(height, width, CV_8UC3, buffer);
  Image flipped_img;
  flip(img,flipped_img,0);
  Image BGR_img;
  cvtColor(flipped_img,BGR_img, COLOR_RGB2BGR);
  return BGR_img;

我希望有人觉得这很有用。

【讨论】:

以上是关于OpenCV + OpenGL - 获取 OpenGL 图像作为 OpenCV 相机的主要内容,如果未能解决你的问题,请参考以下文章

带有 OpenCV 人脸检测的 OpenGL 字节缓冲区

OpenGL ES 上的图像几何重新映射

OpenCV:是不是可以使用它执行 openGL 像素着色?

OpenCV 为啥勾搭上 OpenGL

OpenCV图像处理基本操作 Open_CV系列

OpenCV-3.0 的 OpenGL 支持