2011-11-15 7 views
14

Este código funciona principalmente, pero los datos resultantes parecen perder un canal de color (es lo que estoy pensando) ya que los datos de imagen resultantes cuando se muestran son de color azul.Convertir UIImage en CVImageBufferRef

Aquí está el código:

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

El pixelBufferFromCGIImage método se agarró de otro post sobre StackOverflow aquí: How do I export UIImage array as a movie? (aunque esta aplicación no está relacionada con lo que estoy tratando de hacer) es

+ (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; 
} 

Creo que tiene algo que ver con la relación entre kCVPixelFormatType_32ARGB y kCGImageAlphaNoneSkipLast aunque he probado todas las combinaciones y he obtenido el mismo resultado o una falla de la aplicación. Una vez más, esto obtiene los datos de UIImage en CVImageBufferRef, pero cuando visualizo la imagen en la pantalla, parece perder un canal de color y aparece de color azul. La imagen es un png.

Respuesta

-1

Parece que podría ser esa relación. Posiblemente tiene que ser un jpg y RGB en lugar de colores indexados con un png?

+2

Gracias por la respuesta. La solución es que este código funciona perfectamente según lo previsto. El problema estaba en utilizar los datos para crear una textura OpenGL. Completamente no relacionado con este código. ¡Cualquiera que esté buscando cómo convertir UIImage a CVImageBufferRef, su respuesta está en el código de arriba! – Eric

+0

Como referencia: PNG no está necesariamente indexado (como GIF), también admite imágenes RGB sin pérdida de color (obviamente, esto funciona mejor con dibujos de líneas y bloques de colores sólidos) – Ethan

5

La solución es que este código funciona perfectamente según lo previsto. :) El problema estaba en utilizar los datos al crear una textura OpenGL. Completamente no relacionado con este código. ¡Cualquiera que esté buscando cómo convertir UIImage a CVImageBufferRef, su respuesta está en el código de arriba!

+0

No, definitivamente no funciona.Necesita usar 'kCVPixelFormatType_32BGRA', y usar' (CGBitmapInfo) kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst' como la última variable para el 'context'. Lo que es más, las opciones 'NSDictionary * son inútiles IMO –

0

sólo para aclarar la respuesta anterior: He encontré con el mismo problema porque mi código shader esperaba dos muestras en capas dentro de un buffer de imagen, mientras que utilicé una sola capa de amortiguación

Esta línea tuvo los valores RGB de una muestra y los pasé a (no sé qué), pero el resultado final es una imagen a todo color.

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

Si alguien todavía está buscando una solución a este problema, lo solucioné cambiando las BOOL en las opciones del pixelBuffer:

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

de no a sí:

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

Me encuentro con el mismo problema y encuentro algunas muestras: http://www.cakesolutions.net/teamblogs/2014/03/08/cmsamplebufferref-from-cgimageref
intente cambiar

CGBitmapInfo bitmapInfo = (CGBitmapInfo)kCGBitmapByteOrder32Little | 
        kCGImageAlphaPremultipliedFirst) 
+0

¡Para mí esto funcionó! solo para que la gente pueda ver el código como parte de él, CGContextRef context = cambia el valor pasado desde kCGImageAlphaNoneSkipLast a kCGImageAlphaPremultipliedFirst. – Charlie

1

Esto es lo que realmente funciona:

+ (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; 
} 

Puede cambiar el búfer de píxeles de nuevo a un UIImage (y luego mostrar o guardarlo) para confirmar que funciona con este método:

+ (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; 
}