如何将视频(帧)输入到GLSL着色器中

时间:2014-09-16 21:54:56

标签: opencv opengl glsl video-processing

我正在尝试使用GLSL进行视频处理。我正在使用OpenCV打开视频文件并将每个帧作为单个图像然后我想在GLSL着色器中使用每个帧

使用GLSL视频的最佳/理想/智能解决方案是什么?

从视频中读取

VideoCapture cap("movie.MOV");
Mat image;
bool success = cap.read(image);
if(!success)
{
    printf("Could not grab a frame\n\7");
    exit(0);
}

图像到纹理

 GLuint tex;
 glGenTextures(1, tex);
 glActiveTexture(GL_TEXTURE0);
 glBindTexture(GL_TEXTURE_2D, tex);
 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.cols, image.rows, 0,
                GL_BGR, GL_UNSIGNED_BYTE, image.data);

 glUniform1i(glGetUniformLocation(shaderProgram, "Texture"), 0);

循环渲染时需要什么?

我是否每次都需要重新编译/重新连接/重新链接我的着色器?或者一旦我的着色器被创建和编译,我使用glUseProgram(shaderProgram)我可以继续发送新的纹理吗?

我用来向屏幕渲染纹理的当前循环如下。我如何使其适应视频?我需要在哪里调用以更新着色器中使用的纹理?

while(!glfwWindowShouldClose(window))
{
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    glViewport(0,0,512,512);

    glBindFramebuffer(GL_READ_FRAMEBUFFER, frameBuffer);
    glReadBuffer(GL_COLOR_ATTACHMENT0);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
    glBlitFramebuffer(0, 0, image.cols, image.rows, 0, 0, image.cols, image.rows, GL_COLOR_BUFFER_BIT, GL_LINEAR);


    glfwSwapBuffers(window);
    glfwPollEvents();
}

2 个答案:

答案 0 :(得分:3)

让我们澄清一些需要在循环之前发生的事情

  • 使用glPixelStorei();
  • 设置像素存储模式
  • 仅使用glGenTextures()生成一个纹理,因为在循环的每次迭代中,其内容都将替换为新数据;
  • 使用glCompileShader()编译着色器,使用glCreateShader()创建着色器对象,调用glCreateProgram()创建程序,调用glAttachShader()将着色器对象附加到新程序,最后glLinkProgram()让一切准备就绪。

那就是说,循环的每次迭代都必须:

  • 清除颜色和深度缓冲区;
  • 使用单位矩阵加载 modelview 矩阵;
  • 指定绘图将要发生的位置glTranslatef();
  • 从视频中检索新框架;
  • 启用相应的纹理目标,绑定,然后使用glTexImage2D()将帧传输到GPU;
  • 调用glUseProgram()以激活您的GLSL着色器;
  • 使用GL_QUADS或其他任何内容绘制2D脸部;
  • 使用glUseProgram(0);
  • 停用该程序
  • 使用glDisable(GL_TEXTURE_YOUR_TEXTURE_TARGET);
  • 禁用纹理目标

这或多或少需要做什么。

顺便提一下here's my OpenCV/OpenGL/Qt application从相机中检索帧并将其显示在窗口中。但是没有着色器。

祝你好运!

答案 1 :(得分:1)

您不需要使用帧缓冲区将纹理发送到着色器。一旦您将纹理0选为活动纹理并将0设置为着色器中均匀sampler2D的值,每次调用glBindTexture()时,它都会将sampler2D设置为您使用的纹理。 ve在函数参数中指定。所以不,每次想要改变纹理时,都不需要重新链接或重新编译着色器。