Конвертировать UIImage в CVImageBufferRef - PullRequest
15 голосов
/ 15 ноября 2011

Этот код в основном работает, но результирующие данные, кажется, теряют цветной канал (это то, о чем я думаю), так как результирующие данные изображения при отображении окрашены в синий цвет!

Вот код:

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

Метод pixelBufferFromCGIImage был извлечен из другого поста по stackoverflow здесь: Как экспортировать массив UIImage как фильм? (хотя это приложение не связано с тем, что я пытаюсь сделать), это

+ (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.

Ответы [ 6 ]

5 голосов
/ 16 ноября 2011

Решение состоит в том, что этот код работает отлично, как и предполагалось.:) Проблема заключалась в использовании данных при создании текстуры OpenGL.Полностью не связано с этим кодом.Любой, кто ищет, как конвертировать UIImage в CVImageBufferRef, ваш ответ в коде выше!

1 голос
/ 30 ноября 2016

Вот что действительно работает:

+ (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;
}
1 голос
/ 18 марта 2016

Я сталкиваюсь с той же проблемой и нахожу несколько образцов: http://www.cakesolutions.net/teamblogs/2014/03/08/cmsamplebufferref-from-cgimageref
попробуйте изменить

CGBitmapInfo  bitmapInfo = (CGBitmapInfo)kCGBitmapByteOrder32Little |
                  kCGImageAlphaPremultipliedFirst)
1 голос
/ 20 июля 2015

Если кто-то все еще ищет решение этой проблемы, я решил его, переключив BOOL в параметрах pixelBuffer:

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];
0 голосов
/ 15 июня 2012

Просто чтобы прояснить ответ выше: я столкнулся с той же проблемой, потому что мой шейдерный код ожидал двухслойные выборки в буфере изображения, в то время как я использовал однослойный буфер

Эта строка заняла rgbзначения из одного образца и передать их (я не знаю, что), но конечным результатом является полноцветное изображение.

 gl_FragColor = vec4(texture2D(SamplerY, texCoordVarying).rgb, 1);
0 голосов
/ 15 ноября 2011

Похоже, что это могут быть эти отношения. Возможно, это будут jpg и RGB вместо индексированных цветов с png?

...