2010-10-01 18 views
10

Quiero convertir un objeto UIImage en un objeto CVPixelBufferRef, pero no tengo absolutamente ninguna idea. Y no puedo encontrar ningún código de ejemplo que haga algo como esto.Convertir UIImage en CVPixelBufferRef

¿Alguien puede ayudarme? ¡THX por adelantado!

C YA

+0

Ver https://stackoverflow.com/a/44475334/1418457 – onmyway133

Respuesta

0

Un CVPixelBufferRef es lo que utiliza el vídeo básico para la entrada de la cámara.

Puede crear mapas de bits de píxel similares a partir de imágenes usando CGBitmapContextCreate y luego dibujar la imagen en el contexto de mapa de bits.

+1

Lo que quiero hacer es añadir cuadros individuales de una película con la Fundación AV . Esto se hará usando la clase AVAssetWriterInputPixelBufferAdaptor. Pero esta clase espera objetos CVPixelBufferRef. Entonces, ¿cómo puedo convertir un UIImage a un objeto CVPixelBufferRef? – Nuker

1

Google siempre es tu amigo. La búsqueda de "CVPixelBufferRef" el primer resultado conduce a this snippet de snipplr:

- (CVPixelBufferRef)fastImageFromNSImage:(NSImage *)image{ 
CVPixelBufferRef buffer = NULL; 

// config 
size_t width = [image size].width; 
size_t height = [image size].height; 
size_t bitsPerComponent = 8; // *not* CGImageGetBitsPerComponent(image); 
CGColorSpaceRef cs = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); 
CGBitmapInfo bi = kCGImageAlphaNoneSkipFirst; // *not* CGImageGetBitmapInfo(image); 
NSDictionary *d = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey, [NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey, nil]; 

// create pixel buffer 
CVPixelBufferCreate(kCFAllocatorDefault, width, height, k32ARGBPixelFormat, (CFDictionaryRef)d, &buffer); 
CVPixelBufferLockBaseAddress(buffer, 0); 
void *rasterData = CVPixelBufferGetBaseAddress(buffer); 
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(buffer); 

// context to draw in, set to pixel buffer's address 
CGContextRef ctxt = CGBitmapContextCreate(rasterData, width, height, bitsPerComponent, bytesPerRow, cs, bi); 
if(ctxt == NULL){ 
    NSLog(@"could not create context"); 
    return NULL; 
} 

// draw 
NSGraphicsContext *nsctxt = [NSGraphicsContext graphicsContextWithGraphicsPort:ctxt flipped:NO]; 
[NSGraphicsContext saveGraphicsState]; 
[NSGraphicsContext setCurrentContext:nsctxt]; 
[image compositeToPoint:NSMakePoint(0.0, 0.0) operation:NSCompositeCopy]; 
[NSGraphicsContext restoreGraphicsState]; 

CVPixelBufferUnlockBaseAddress(buffer, 0); 
CFRelease(ctxt); 

return buffer; 
} 

ni idea de si esto funciona en absoluto, sin embargo. (Su kilometraje puede ser cauteloso :)

+3

La pregunta era sobre la conversión de un 'UIImage' a' CVPixelBufferRef', no 'NSImage' – srgtuszy

+1

La línea sobre size_t bytesPerRow = CVPixelBufferGetBytesPerRow (buffer); es lo que hizo el truco para mí.Todas las demás muestras de código usaban una constante mágica que resultaba incorrecta en este dispositivo, pudiendo determinar que el valor real era la clave. Gracias. –

1

Puede usar Core Image para crear un CVPixelBuffer a partir de un UIImage.

// 1. Create a CIImage with the underlying CGImage encapsulated by the UIImage (referred to as 'image'): 

CIImage *inputImage = [CIImage imageWithCGImage:image.CGImage]; 

// 2. Create a CIContext: 

Context *ciContext = [CIContext contextWithCGContext:UIGraphicsGetCurrentContext() options:nil]; 

// 3. Render the CIImage to a CVPixelBuffer (referred to as 'outputBuffer'): 

[self.ciContext render:img toCVPixelBuffer:outputBuffer]; 

AVFoundation proporciona clases que leen archivos de vídeo (llamados activos) y de la salida de otros objetos AVFoundation que manejan (o que ya han leído) activos en tampones de píxeles. Si esa es su única preocupación, encontrará lo que está buscando en el código de muestra Extensión de edición de fotos.

Si su fuente se genera a partir de una serie de objetos UIImage (tal vez no hubo un archivo fuente y está creando un nuevo archivo a partir de contenido generado por el usuario), el código de muestra proporcionado anteriormente será suficiente.

NOTA: No es el medio más eficiente ni el único medio para convertir un UIImage en un CVPixelBuffer; pero es, de lejos, el medio más fácil. El uso de Core Graphics para convertir un UIImage en un CVPixelBuffer requiere mucho más código para configurar atributos, como el tamaño del búfer de píxeles y el espacio de color, que Core Image se ocupa de ti.

6

Existen diferentes formas de hacerlo, esas funciones convierten un búfer de píxeles de CGImage. UImage es un contenedor alrededor de CGImage, por lo tanto, para obtener un CGImage solo necesita llamar al método .CGImage.
Las otras formas también son crear un CIImage desde el búfer (ya publicado) o utilizar el marco Accelerate, que es probablemente el más rápido pero también el más difícil.

- (CVPixelBufferRef) pixelBufferFromCGImage: (CGImageRef) image 
{ 
    NSDictionary *options = @{ 
           (NSString*)kCVPixelBufferCGImageCompatibilityKey : @YES, 
           (NSString*)kCVPixelBufferCGBitmapContextCompatibilityKey : @YES, 
           }; 

    CVPixelBufferRef pxbuffer = NULL; 
    CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, CGImageGetWidth(image), 
         CGImageGetHeight(image), kCVPixelFormatType_32ARGB, (__bridge CFDictionaryRef) options, 
         &pxbuffer); 
    if (status!=kCVReturnSuccess) { 
     NSLog(@"Operation failed"); 
    } 
    NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL); 

    CVPixelBufferLockBaseAddress(pxbuffer, 0); 
    void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer); 

    CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB(); 
    CGContextRef context = CGBitmapContextCreate(pxdata, CGImageGetWidth(image), 
               CGImageGetHeight(image), 8, 4*CGImageGetWidth(image), rgbColorSpace, 
               kCGImageAlphaNoneSkipFirst); 
    NSParameterAssert(context); 

    CGContextConcatCTM(context, CGAffineTransformMakeRotation(0)); 
    CGAffineTransform flipVertical = CGAffineTransformMake(1, 0, 0, -1, 0, CGImageGetHeight(image)); 
    CGContextConcatCTM(context, flipVertical); 
    CGAffineTransform flipHorizontal = CGAffineTransformMake(-1.0, 0.0, 0.0, 1.0, CGImageGetWidth(image), 0.0); 
    CGContextConcatCTM(context, flipHorizontal); 

    CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), 
              CGImageGetHeight(image)), image); 
    CGColorSpaceRelease(rgbColorSpace); 
    CGContextRelease(context); 

    CVPixelBufferUnlockBaseAddress(pxbuffer, 0); 
    return pxbuffer; 
} 
+0

¿por qué voltear vertical y horizontal? –

+0

@MaxiMus Debido a que UIKit y grphics centrales tienen diferentes sistemas de coordenadas https://developer.apple.com/library/content/documentation/2DDrawing/Conceptual/DrawingPrintingiOS/GraphicsDrawingOverview/GraphicsDrawingOverview.html – Andrea

+0

La y coordina sí, pero no la x. ..? –

0

Muy tarde aunque para alguien que necesita.

// call like this 
    CVPixelBufferRef videobuffer = [self pixelBufferFromCGImage:yourImage.CGImage]; 

// método que convierte

-(CVPixelBufferRef)pixelBufferFromCGImage:(CGImageRef)image{ 

    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: 
          [NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey, 
          [NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey, nil]; 
    CVPixelBufferRef pxbuffer = NULL; 
    CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, videoSize.width, videoSize.height, 
              kCVPixelFormatType_32ARGB, (__bridge CFDictionaryRef)options, &pxbuffer); 
    NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL); 

    CVPixelBufferLockBaseAddress(pxbuffer, 0); 
    void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer); 
    NSParameterAssert(pxdata != NULL); 

    CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB(); 
    CGContextRef context = CGBitmapContextCreate(pxdata, videoSize.width, videoSize.height, 8, 4*videoSize.width, rgbColorSpace, kCGImageAlphaNoneSkipFirst); 
    NSParameterAssert(context); 
    CGContextConcatCTM(context, CGAffineTransformIdentity); 
    CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), CGImageGetHeight(image)), image); 
    CGColorSpaceRelease(rgbColorSpace); 
    CGContextRelease(context); 
    CVPixelBufferUnlockBaseAddress(pxbuffer, 0); 

    return pxbuffer; 
}