【问题标题】:Convert UIImage to CVImageBufferRef将 UIImage 转换为 CVImageBufferRef
【发布时间】:2011-12-29 14:18:20
【问题描述】:

这段代码大部分都可以工作,但结果数据似乎失去了一个颜色通道(我在想什么),因为结果图像数据在显示时被染成蓝色!

代码如下:

UIImage* myImage=[UIImage imageNamed:@"sample1.png"];
CGImageRef imageRef=[myImage CGImage];
CVImageBufferRef pixelBuffer = [self pixelBufferFromCGImage:imageRef];

该方法 pixelBufferFromCGIImage 是从 stackoverflow 上的另一篇文章中获取的:How do I export UIImage array as a movie?(尽管此应用程序与我正在尝试做的事情无关)它是

+ (CVPixelBufferRef)pixelBufferFromCGImage:(CGImageRef)image
{
    CGSize frameSize = CGSizeMake(CGImageGetWidth(image), CGImageGetHeight(image));
    NSDictionary *options = @{
                              (__bridge NSString *)kCVPixelBufferCGImageCompatibilityKey: @(NO),
                              (__bridge NSString *)kCVPixelBufferCGBitmapContextCompatibilityKey: @(NO)
                              };
    CVPixelBufferRef pixelBuffer;
    CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, frameSize.width,
                                          frameSize.height,  kCVPixelFormatType_32ARGB, (__bridge CFDictionaryRef) options,
                                          &pixelBuffer);
    if (status != kCVReturnSuccess) {
        return NULL;
    }

    CVPixelBufferLockBaseAddress(pixelBuffer, 0);
    void *data = CVPixelBufferGetBaseAddress(pixelBuffer);
    CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(data, frameSize.width, frameSize.height,
                                                 8, CVPixelBufferGetBytesPerRow(pixelBuffer), rgbColorSpace,
                                                 (CGBitmapInfo) kCGImageAlphaNoneSkipLast);
    CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image),
                                           CGImageGetHeight(image)), image);
    CGColorSpaceRelease(rgbColorSpace);
    CGContextRelease(context);
    CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);

    return pixelBuffer;
}

我认为这与 kCVPixelFormatType_32ARGB 和 kCGImageAlphaNoneSkipLast 之间的关系有关,尽管我尝试了每种组合并得到相同的结果或应用程序崩溃。再一次,这会将 UIImage 数据放入 CVImageBufferRef 中,但是当我在屏幕上显示图像时,它似乎失去了颜色通道并显示为蓝色。图片是 png。

【问题讨论】:

    标签: iphone ios bitmap uiimage


    【解决方案1】:

    听起来可能就是这种关系。可能是 jpg 和 RGB,而不是带有 png 的索引颜色?

    【讨论】:

    • 感谢您的回答。解决方案是此代码按预期完美运行。问题在于使用数据创建 OpenGL 纹理。与此代码完全无关。任何搜索如何将 UIImage 转换为 CVImageBufferRef 的人,您的答案都在上面的代码中!
    • 供参考:PNG不一定是索引的(像GIF一样),它还支持无损全彩RGB图像(显然这对线条图和纯色块效果更好)
    【解决方案2】:

    解决方案是此代码按预期完美运行。 :) 问题在于使用数据创建 OpenGL 纹理。与此代码完全无关。任何搜索如何将 UIImage 转换为 CVImageBufferRef 的人,您的答案都在上面的代码中!

    【讨论】:

    • 不,它绝对行不通。您需要使用kCVPixelFormatType_32BGRA,并使用(CGBitmapInfo) kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst 作为context 的最后一个变量。更重要的是,NSDictionary *options 没用 IMO
    【解决方案3】:

    只是为了澄清上面的答案:我遇到了同样的问题,因为我的着色器代码期望图像缓冲区中有两个分层样本,而我使用的是单层缓冲区

    这一行从一个样本中获取 rgb 值并将它们传递给(我不知道是什么),但最终结果是全彩色图像。

     gl_FragColor = vec4(texture2D(SamplerY, texCoordVarying).rgb, 1);
    

    【讨论】:

      【解决方案4】:

      如果有人还在寻找这个问题的解决方案,我通过切换 pixelBuffer 选项中的 BOOL 来解决它:

      NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                           [NSNumber numberWithBool:NO], kCVPixelBufferCGImageCompatibilityKey,
                           [NSNumber numberWithBool:NO], kCVPixelBufferCGBitmapContextCompatibilityKey,
                           nil];
      

      从否到是:

      NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                           [NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey,
                           [NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey,
                           nil];
      

      【讨论】:

        【解决方案5】:

        我遇到同样的问题并找到一些示例:http://www.cakesolutions.net/teamblogs/2014/03/08/cmsamplebufferref-from-cgimageref
        尝试改变

        CGBitmapInfo  bitmapInfo = (CGBitmapInfo)kCGBitmapByteOrder32Little |
                          kCGImageAlphaPremultipliedFirst)
        

        【讨论】:

        • 对我来说这行得通!只是为了让人们可以看到它的代码部分,CGContextRef context = 将传入的值从 kCGImageAlphaNoneSkipLast 更改为 kCGImageAlphaPremultipliedFirst。
        【解决方案6】:

        以下是真正有效的方法:

        + (CVPixelBufferRef)pixelBufferFromImage:(CGImageRef)image {
            CGSize frameSize = CGSizeMake(CGImageGetWidth(image), CGImageGetHeight(image)); // Not sure why this is even necessary, using CGImageGetWidth/Height in status/context seems to work fine too
        
            CVPixelBufferRef pixelBuffer = NULL;
            CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, frameSize.width, frameSize.height, kCVPixelFormatType_32BGRA, nil, &pixelBuffer);
            if (status != kCVReturnSuccess) {
                return NULL;
            }
        
            CVPixelBufferLockBaseAddress(pixelBuffer, 0);
            void *data = CVPixelBufferGetBaseAddress(pixelBuffer);
            CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
            CGContextRef context = CGBitmapContextCreate(data, frameSize.width, frameSize.height, 8, CVPixelBufferGetBytesPerRow(pixelBuffer), rgbColorSpace, (CGBitmapInfo) kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
            CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), CGImageGetHeight(image)), image);
        
            CGColorSpaceRelease(rgbColorSpace);
            CGContextRelease(context);
            CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
        
            return pixelBuffer;
        }
        

        您可以将像素缓冲区更改回 UIImage(然后显示或保存)以确认它可以使用此方法:

        + (UIImage *)imageFromPixelBuffer:(CVPixelBufferRef)pixelBuffer {
            CIImage *ciImage = [CIImage imageWithCVPixelBuffer:pixelBuffer];
            CIContext *context = [CIContext contextWithOptions:nil];
            CGImageRef myImage = [context createCGImage:ciImage fromRect:CGRectMake(0, 0, CVPixelBufferGetWidth(pixelBuffer), CVPixelBufferGetHeight(pixelBuffer))];
            UIImage *image = [UIImage imageWithCGImage:myImage];
        
            // Uncomment the following lines to say the image to your application's document directory
            //NSString *imageSavePath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"myImageFromPixelBuffer.png"]];
            //[UIImagePNGRepresentation(image) writeToFile:imageSavePath atomically:YES];
            return image;
        }
        

        【讨论】:

          猜你喜欢
          • 2011-03-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-07-30
          • 2012-07-15
          • 2013-01-01
          • 2015-12-12
          • 2011-09-22
          相关资源
          最近更新 更多