【问题标题】:Porting CVOpenGLESTextureCacheCreateTextureFromImage to normal OpenGL ES methods将 CVOpenGLESTextureCacheCreateTextureFromImage 移植到普通的 OpenGL ES 方法
【发布时间】:2012-08-15 21:18:16
【问题描述】:

我正在开发一个应用程序,它将来自相机的视频帧输入 OpenGL ES 纹理以创建一些效果。该应用程序使用 Core Video 及其许多便捷方法来创建 OpenGL 纹理和缓存。

现在我想使用静态图像而不是视频缓冲区,并且我正在寻找标准 OpenGL 方法来代替 Core Video 中可用的方法。

例如:

  • CVOpenGLESTextureRef;
  • CVOpenGLESTextureCacheRef;
  • CVOpenGLESTextureCacheCreateTextureFromImage();
  • CVOpenGLESTextureGetTarget();
  • CVOpenGLESTextureGetName();
  • CVOpenGLESTextureCacheFlush();

我可以使用哪些标准 OpenGL 类型和方法来代替上面的代码从法线图像加载和创建纹理?

谢谢

*编辑*

按照布拉德的建议,我能够取得一些进展......但仍然无法正常工作。我认为问题在于着色器期望两个单独的纹理正常工作。一个用于 Y 平面,一个用于 UV 平面。

这是用于设置它们的代码

// Y-plane
glActiveTexture(GL_TEXTURE0);
err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault, _videoTextureCache, pixelBuffer, NULL, GL_TEXTURE_2D, GL_RED_EXT, _textureWidth, _textureHeight, GL_RED_EXT, GL_UNSIGNED_BYTE, 0, &_lumaTexture);
glBindTexture(CVOpenGLESTextureGetTarget(_lumaTexture), CVOpenGLESTextureGetName(_lumaTexture));
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

// UV-plane
glActiveTexture(GL_TEXTURE1);
err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault, _videoTextureCache, pixelBuffer, NULL, GL_TEXTURE_2D, GL_RG_EXT, _textureWidth/2, _textureHeight/2, GL_RG_EXT, GL_UNSIGNED_BYTE, 1, &_chromaTexture);
glBindTexture(CVOpenGLESTextureGetTarget(_chromaTexture), CVOpenGLESTextureGetName(_chromaTexture));
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

所以我这样改了:

这里是设置

glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &_lumaImageTexture);
glBindTexture(GL_TEXTURE_2D, _lumaImageTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

glActiveTexture(GL_TEXTURE1);
glGenTextures(1, &_chromaImageTexture);
glBindTexture(GL_TEXTURE_2D, _chromaImageTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

这是我创建它们的方法

// Y-plane
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, _lumaImageTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _textureWidth, _textureHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, imageData);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

// UV-plane
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, _chromaImageTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _textureWidth, _textureHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, imageData);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

我猜问题出在 glTexImage2D 函数中的参数之一。我尝试了不同结果的不同组合......但从来没有正确的组合:)

【问题讨论】:

    标签: objective-c ios opengl-es core-video


    【解决方案1】:

    所有这些方法都会为您提供与 CVPixelBuffer 对应的 OpenGL ES 纹理。在 iOS 5.0 中引入这些之前,我们必须手动从 CVPixelBuffer 中获取像素数据并将其上传到纹理。您可以对从另一个来源提取的静态图像使用相同的过程(除非您想使用某些 GLKit 便利类)。

    以下是我用于上传静态图片的代码。首先,您需要将图像放入 BGRA 字节数组中:

    if (shouldRedrawUsingCoreGraphics)
    {
        // For resized image, redraw
        imageData = (GLubyte *) calloc(1, (int)pixelSizeToUseForTexture.width * (int)pixelSizeToUseForTexture.height * 4);
    
        CGColorSpaceRef genericRGBColorspace = CGColorSpaceCreateDeviceRGB();    
        CGContextRef imageContext = CGBitmapContextCreate(imageData, (int)pixelSizeToUseForTexture.width, (int)pixelSizeToUseForTexture.height, 8, (int)pixelSizeToUseForTexture.width * 4, genericRGBColorspace,  kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
        CGContextDrawImage(imageContext, CGRectMake(0.0, 0.0, pixelSizeToUseForTexture.width, pixelSizeToUseForTexture.height), newImageSource);
        CGContextRelease(imageContext);
        CGColorSpaceRelease(genericRGBColorspace);
    }
    else
    {
        // Access the raw image bytes directly
        dataFromImageDataProvider = CGDataProviderCopyData(CGImageGetDataProvider(newImageSource));
        imageData = (GLubyte *)CFDataGetBytePtr(dataFromImageDataProvider);
    }    
    

    在上面的代码中,newImageSource 是一个 CGImageRef。这显示了提取位图数据的两种不同路径,在我运行的每个基准测试中,第一个路径出奇地快。

    一旦你有了它,你只需要将它上传到你的 OpenGL ES 纹理:

        glBindTexture(GL_TEXTURE_2D, outputTexture);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (int)pixelSizeToUseForTexture.width, (int)pixelSizeToUseForTexture.height, 0, GL_BGRA, GL_UNSIGNED_BYTE, imageData);
    

    这假设您已经使用以下内容创建了 outputTexture:

        glActiveTexture(GL_TEXTURE0);
        glGenTextures(1, &outputTexture);
        glBindTexture(GL_TEXTURE_2D, outputTexture);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        // This is necessary for non-power-of-two textures
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    

    并且正确的 EAGLContext 使用 +setCurrentContext: 与当前线程相关联。

    如果我可以提出建议,为什么不看看 my open source framework 为您处理所有这些以便执行图像处理任务?这可能会为您节省一些精力。

    【讨论】:

    • 嗨布拉德,我知道你的框架......确实很棒!但是我只是认为对于这样简单的任务来说开销太大了。我会尝试遵循您的建议,看看我是否可以先以这种方式工作。谢谢!
    • 嘿布拉德,谢谢!它有点工作......我得到了纹理,唯一的问题是它是绿色的。那是因为纹理格式错误并且没有包含每个通道的所有必要位吗?抱歉,如果问题不是很精确……但我完全是 OpenGL 的菜鸟。 :)
    • @Andrea - 如果它是绿色的,但图像仍然显示并且没有填充一堆对角线,那么您可能对输入图像的字节顺序有问题。它可能采用 RGBA 而不是 BGRA、ARGB 或 ABGR。我用于位图上下文的上述设置是专门为生成 BGRA 帧以供稍后的纹理上传使用的。确保您没有使用其他上下文设置。
    • 我严格按照您的代码进行操作,但不幸的是它不起作用。我想我很清楚其中的原因。请检查对我原始问题的编辑...我添加了更多详细信息。 (我该怎么做和@yourname 用你的名字?)
    • @Andrea - 是的,当然对于平面 YUV,这不会像上面描述的那样工作。当您说“现在我想使用静态图像”时,我假设您是从 UIImage 源中提取的,您可以在其中绘制到 BGRA 图像缓冲区。你现在问的是一个完全不同的问题。对于 YUV 平面源,您需要将 Y 和 UV 纹理的 glTexImage2d() 参数替换为您在更新的第一个代码中显示的纹理缓存函数中的参数。注意新的字节大小以及GL_RED_EXTGL_RG_EXT 纹理类型的使用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多