【问题标题】:iOS OpenGL using parameters for glTexImage2D to make a UIImage?iOS OpenGL 使用 glTexImage2D 的参数来制作 UIImage?
【发布时间】:2011-01-10 22:23:42
【问题描述】:

我正在处理分配给我的项目的一些现有代码。

我已成功调用 glTexImage2D,如下所示:
glTexImage2D(GL_TEXTURE_2D, 0, texture->format, texture->widthTexture, texture->heightTexture, 0, texture->format, texture->type, texture->data);

我想使用传递给glTexImage2D 的变量创建一个图像(最好是CGImageUIImage),但不知道是否可行。

我需要从 OpenGL 视图创建许多连续图像(每秒有很多)并将它们保存以供以后使用。

我应该能够使用我在glTexImage2D 中使用的变量创建CGImageUIImage 吗?

如果我应该可以,我应该怎么做?

如果不是,为什么我不能,你对我每秒多次保存/捕获我的 opengl 视图内容的任务有什么建议?

编辑:我已经使用苹果提供的glReadPixels等技术成功捕获了图像。我想要更快的东西,这样我每秒可以获得更多图像。

编辑:查看并添加来自 Thomson 的代码后,生成的图像如下:

图像与图像的外观非常相似,只是水平复制了约 5 次,并且下方有一些随机的黑色空间。

注意:视频(每一帧)数据是通过与 iPhone 的临时网络连接来的。我相信相机正在使用 YCbCr 色彩空间拍摄每一帧

编辑:进一步审查 Thomson 的代码 我已将您的新代码复制到我的项目中,结果得到了不同的图像:

宽度:320 高度:240

我不确定如何找到纹理-> 数据中的字节数。它是一个空指针。

编辑:格式和类型

texture.type = GL_UNSIGNED_SHORT_5_6_5

texture.format = GL_RGB

【问题讨论】:

  • 字节数为:int length = width * height * channels;这仅适用于每种颜色的 8 位。找出纹理->格式和纹理->类型是什么。如果您获取十六进制值并搜索 opengl.org 的文档,您应该能够准确地找出您的数据是什么;有多少通道(RGB 或 RGBA)以及您是否发送无符号字节(很可能)
  • 嗨,binny,GL_UNSIGNED_SHORT_5_6_5 是非常重要的信息,很高兴知道。当我有时间时,我会在这里发布如何将其解压缩为可用于我在下面提供的 UIImage 代码的格式。

标签: objective-c cocoa-touch ios opengl-es


【解决方案1】:

嘿,binnyb,这是使用存储在texture->data 中的数据创建UIImage 的解决方案。 v01d 肯定是正确的,您不会获得出现在 GL 帧缓冲区中的 UIImage,但它会在数据通过帧缓冲区之前从数据中为您获取图像。

原来你的纹理数据是 16 位格式,红色 5 位,绿色 6 位,蓝色 5 位。在创建 UIImage 之前,我添加了用于将 16 位 RGB 值转换为 32 位 RGBA 值的代码。我期待听到结果如何。

float width    = 512;
float height   = 512;
int   channels = 4;

// create a buffer for our image after converting it from 565 rgb to 8888rgba
u_int8_t* rawData = (u_int8_t*)malloc(width*height*channels);

// unpack the 5,6,5 pixel data into 24 bit RGB
for (int i=0; i<width*height; ++i) 
{
    // append two adjacent bytes in texture->data into a 16 bit int
    u_int16_t pixel16 = (texture->data[i*2] << 8) + texture->data[i*2+1];      
    // mask and shift each pixel into a single 8 bit unsigned, then normalize by 5/6 bit
    // max to 8 bit integer max.  Alpha set to 0.
    rawData[channels*i]   = ((pixel16 & 63488)       >> 11) / 31.0 * 255;
    rawData[channels*i+1] = ((pixel16 & 2016)  << 5  >> 10) / 63.0 * 255;
    rawData[channels*i+2] = ((pixel16 & 31)    << 11 >> 11) / 31.0 * 255;
    rawData[channels*4+3] = 0;
}

// same as before
int                    bitsPerComponent = 8;
int                    bitsPerPixel     = channels*bitsPerComponent;
int                    bytesPerRow      = channels*width;
CGColorSpaceRef        colorSpaceRef    = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo           bitmapInfo       = kCGBitmapByteOrderDefault;
CGColorRenderingIntent renderingIntent  = kCGRenderingIntentDefault;

CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, 
                                                          rawData, 
                                                          channels*width*height,
                                                          NULL);
free( rawData );
CGImageRef        imageRef = CGImageCreate(width,
                                           height,
                                           bitsPerComponent,
                                           bitsPerPixel,
                                           bytesPerRow,
                                           colorSpaceRef,
                                           bitmapInfo,
                                           provider,NULL,NO,renderingIntent);

UIImage *newImage = [UIImage imageWithCGImage:imageRef];

创建新图像的代码来自Creating UIImage from raw RGBA data,感谢 Rohit。我已经用我们原始的 320x240 图像尺寸对此进行了测试,将 24 位 RGB 图像转换为 5、6、5 格式,然后再转换为 32 位。我尚未在 512x512 图像上对其进行测试,但我预计不会有任何问题。

【讨论】:

  • 好的,我已经审查并测试了这段代码。我在我的问题中添加了一张图片和一些其他注释
  • 嘿binnby,你能列出texture->widthTexture 和texture->heightTexture 以及texture->data 中存储了多少字节吗?现在您遇到的错误是因为分配的 UIImage 的大小与纹理-> 数据中图像的大小不一致。看起来您的数据没有 alpha 分量,因此没有对齐。像这样找出完美的像素配置可能很困难,尤其是在我没有实际数据的情况下。最好让您进行实验。如果每个图像像素都是 YCbCr 格式,这是我们以后可以处理的另一个问题。
  • 上面的源代码已经被修改为支持原始RGB数据而不是RGBA数据。当通道设置为 4 时,我使用 RGB 数据测试了我的代码,并得到了与您现在所经历的非常相似的图像伪影。应该这样做。
  • 谢谢!用另一个图像和宽度/高度更新了我的问题
  • 嘿,binnyb,你有没有注意到我更新了我的答案来处理你的 16 位纹理?
【解决方案2】:

您可以根据发送给 GL 的数据制作图像,但我怀疑这是否真的是您想要实现的目标。

我的猜测是你想要帧缓冲区的输出。为此,您需要 glReadPixels()。请记住,对于一个大缓冲区(例如 1024x768),从 GL 读取像素需要几秒钟,每秒不会超过 1 个。

【讨论】:

  • 确实,我应该提到我已经通过glReadPixels 成功捕获了图像,但是它太慢了,我正在寻找替代方法
  • 此时你不会在 iOS 上获得更快的速度。 glReadPixels 是从 GL 拉回数据的唯一选项。
【解决方案3】:

您应该能够为此使用 UIImage 初始化程序 imageWithData。您只需确保 texture->data 中的数据采用 UIImage 构造函数可识别的结构化格式。

NSData* imageData = [NSData dataWithBytes:texture->data length:(3*texture->widthTexture*texture->heightTexture)];
UIImage* theImage = [UIImage imageWithData:imageData];

imageWithData: 支持的类型没有很好的文档记录,但是您可以从 .png、.jpg、.gif 创建 NSData,我认为 .ppm 文件没有任何困难。如果纹理->数据是其中一种二进制格式,我怀疑你可以通过一些实验来运行它。

【讨论】:

  • texture->data 是原始像素数据。 imageWithData: 在原始数据上将不成功,因为不知道图像打包格式或大小。您可以从原始数据制作 CGImage,然后从中制作 UIImage。但我怀疑@binnyb 想要来自 GL FBO 的更新数据。您不会从纹理数据中获取它,因为它被复制到您无权访问的 GL 内部缓冲区中。见opengl.org/sdk/docs/man/xhtml/glTexImage2D.xml
  • 好的,你可以使用 imageWithCGImage: 代替。您必须自定义代码以反映您的图像数据,但之前的 StackOverflow 解决了这个问题:stackoverflow.com/questions/4545237/…您可以将原始图像数据写入 CGImageRef 并从中创建您的 UIImage。
  • 关于“您必须自定义代码以反映您的图像数据”的任何建议?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-07-12
  • 2013-01-06
  • 2012-04-09
  • 1970-01-01
  • 2017-08-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多