OpenGL渲染到帧缓冲区,转换为OpenCV Umat以进行OpenCL加速处理。

7
在以前的OpenCV版本中,我可以使用OpenGL渲染到后备缓冲区,使用glReadPixels将像素“复制”到OpenCV图像(iplimage?)中进行一些处理(模糊、与另一种由OpenCV加载的图像进行模板匹配)。 但是,这会在GPU和CPU之间转移数据,如果我想显示它,则需要再次将数据从CPU传输回GPU。
现在我可以只使用OpenGL和OpenCL来做类似的事情,通过使用clEnqueueAcquireGLObjects,我根本不必转移数据。我使用OpenGL渲染到帧缓冲区,并让OpenCL控制它。
然而,这迫使我编写自己的OpenCL内核(没人有时间去做那个...实际上,在Nvidia上调试OpenCL非常困难),用于任何我想要执行的处理。现在,由于OpenCV具有一些出色的OpenCL加速流程,我想尝试一下它们。
所以我的问题是:是否可能将渲染结果绑定在帧缓冲区(或GPU上的另一个GL上下文),并将其控制权(或副本)交给OpenCV上下文(umat?)以进行OpenCL加速处理?如果可以,那么如何实现(大致思路、关键组件)?
我感觉可以使用cv :: ogl :: Buffer将缓冲区包装起来,但是文档不是很清楚,然后使用ogl :: Buffer::copyTo进行复制。类似问题:是否可能将OpenCV GpuMat绑定为OpenGL纹理? 其他参考资料:从Mat / oclMat传输数据到cl_mem(OpenCV + OpenCL)

这是我目前正在使用UMat句柄探索的一条路径(也是我找不到太多文档的东西): `cv::Umat x;err = clEnqueueAcquireGLObjects(ocl_queue, 1, (cl_mem*)x.handle(ACCESS_WRITE), 0, NULL, NULL);`虽然编译通过,但并不起作用...也许我在创建时需要定义x以匹配GL缓冲区的大小? - Biaspoint
你有找到做这件事的方法吗? - rhardih
1
我可能有,那是一年多以前的事了。如果您正在使用opencv的opengl部分,则可以在以下网址找到:https://fossies.org/linux/opencv/samples/opengl/opengl_interop.cpp。我记得我尝试创建一个MAT,然后使用MAT文件中的“data”使用clCreateImage2D...即image = clCreateImage2D(context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, &format, mat.cols, mat.rows, 0, (void*)mat.data, &err); 然后我使用GL进行渲染,并使用clEnqueueAcquireGLObjects将其同时移动到CL和CV...我知道这是一个糟糕的答案,但我很快就放弃了。 - Biaspoint
2个回答

1
opencv-opengl的互操作现在非常容易使用(感谢开发者们的努力)! 我现在可以在不复制到CPU的情况下使用OpenCV作为后处理效果。
初始化纹理和opencv包装器:
cv::ogl::Texture2D texture;
GLuint fbo_texture;

glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &fbo_texture);
glBindTexture(GL_TEXTURE_2D, fbo_texture);
<...>
texture = cv::ogl::Texture2D(cv::Size(screen_width, screen_height), cv::ogl::Texture2D::Format::RGBA, fbo_texture, false);

使用固定功能管线,将图像渲染到FBO,并进行模糊处理和显示。
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glClear(GL_COLOR_BUFFER_BIT);
//draw to FBO
<...>
glBindFramebuffer(GL_FRAMEBUFFER, 0);


cv::UMat u;
cv::ogl::convertFromGLTexture2D(texture, u); // The magic
cv::blur(u, u, cv::Size(10,10));
cv::ogl::convertToGLTexture2D(u, texture); // The magic


texture.bind();
glEnable(GL_TEXTURE_2D);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex2f(-1.0f, -1.0f);
glTexCoord2f(1.0f, 0.0f);
glVertex2f(1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex2f(1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f);
glVertex2f(-1.0f, 1.0f);
glEnd();
glDisable(GL_TEXTURE_2D);

不要忘记在创建OpenGL上下文之后初始化OpenCL的OpenCV。
if (cv::ocl::haveOpenCL())
{
   cv::ogl::ocl::initializeContextFromGL();
}

1
是的,现在可能已经可以了。我写了demos来演示OpenGL/OpenCL/VAAPI互操作性。tetra-demo使用OpenGL渲染旋转四面体,将帧缓冲(实际上是附加到帧缓冲的纹理)传递给OpenCV/CL(作为cv::UMat),并将其编码为VP9。所有这些都在GPU上完成。唯一的问题是需要修复在我的OpenCV 4.x fork中,并且您必须自己构建它。 它还需要两个OpenCL扩展:cl_khr_gl_sharing和cl_intel_va_api_media_sharing

有两个开放的github问题解决了我的努力:


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接