2012-01-26 9 views
18

Esto parece una tarea simple, sin embargo, me está volviendo loco. ¿Es posible convertir un UIView que contenga AVCaptureVideoPreviewLayer como una subcapa en una imagen para guardar? Quiero crear una superposición de realidad aumentada y tener un botón para guardar la imagen en el rollo de la cámara. Presionando el botón de encendido + tecla de inicio captura la captura de pantalla en el rollo de la cámara, lo que significa que toda mi lógica de captura está funcionando, Y la tarea es posible. Pero parece que no puedo hacer que funcione programáticamente.¿Es posible renderizar AVCaptureVideoPreviewLayer en un contexto de gráficos?

Estoy capturando una vista previa en vivo de la imagen de la cámara usando AVCaptureVideoPreviewLayer. Todos mis intentos de representar la imagen fallan:

previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:captureSession]; 
//start the session, etc... 


//this saves a white screen 
- (IBAction)saveOverlay:(id)sender { 
    NSLog(@"saveOverlay"); 

    UIGraphicsBeginImageContext(appDelegate.window.bounds.size); 
     UIGraphicsBeginImageContext(scrollView.frame.size); 

    [previewLayer.presentationLayer renderInContext:UIGraphicsGetCurrentContext()]; 


// [appDelegate.window.layer renderInContext:UIGraphicsGetCurrentContext()]; 

    UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 

    UIImageWriteToSavedPhotosAlbum(screenshot, self, 
            @selector(image:didFinishSavingWithError:contextInfo:), nil); 
} 

// ello convierte a todo, a excepción de la capa de vista previa, que está en blanco.

[appDelegate.window.layer renderInContext:UIGraphicsGetCurrentContext()]; 

He leído en alguna parte que esto puede ser debido a problemas de seguridad del iPhone. ¿Es esto cierto?

Sólo para ser claro: No quiero guardar la imagen para la cámara. Quiero guardar la capa de vista previa transparente superpuesta sobre otra imagen, creando transparencia. Sin embargo, por alguna razón no puedo hacerlo funcionar.

Respuesta

4

Puedo aconsejarle que pruebe la imagen de GPU.

https://github.com/BradLarson/GPUImage

Se utiliza OpenGL, por lo que es bastante rápido. Puede procesar imágenes de la cámara y agregarles filtros (hay muchas) incluyendo detección de bordes, detección de movimiento y mucho más.

Es como OpenCV, pero según mi propia experiencia, la imagen de GPU es más fácil de conectar con su proyecto y el lenguaje es objetivo-c.

problema podría aparecer si ha decidido usar Box2D para la física - es utiliza OpenGL también y usted tendrá que pasar algún tiempo hasta que estos 2 marcos a dejar de luchar))

+0

supongo que lo que el PO y yo estamos tratando, es conseguir un video en vivo usando avcapturevideopreviewlayer y están tratando de agregar una imagen escalada. Intento agregar una imagen escalada encima de la transmisión de video en vivo basada en la detección de rostros, y la captura de pantalla guardada es solo la de la superposición y no la de avcapturevideopreviewlayer. –

+0

En la imagen de la GPU, estoy agregando filtros en las capas, así que estoy bastante seguro de que hay una manera de guardar solo la capa actual (hay un método en la imagen de la GPU para hacer UIImage del marco) Si quieres obtener lo que está en la pantalla: es una forma de hacer una captura de pantalla programáticamente. No puedo recordarlo ahora pero lo he visto en Stackoverflow) – Roma

+0

Roma, muchas gracias por su respuesta. Aunque no utilicé GPUImage, lo usaré pronto. Gracias por publicarlo como una opción alternativa. –

15

me gusta @ sugerencia de utilizar la GPU imagen de la Roma - gran idea. . . . sin embargo si quieres un enfoque Cocoa Touch pura, esto es lo que debe hacer:

Implementar AVCaptureVideoDataOutputSampleBufferDelegate

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer 
fromConnection:(AVCaptureConnection *)connection 
{ 
    // Create a UIImage+Orientation from the sample buffer data 
    if (_captureFrame) 
    { 
     [captureSession stopRunning]; 

     _captureFrame = NO; 
     UIImage *image = [ImageTools imageFromSampleBuffer:sampleBuffer]; 
     image = [image rotate:UIImageOrientationRight]; 

     _frameCaptured = YES; 

     if (delegate != nil) 
     { 
      [delegate cameraPictureTaken:image]; 
     } 
    } 
} 

captura de la siguiente manera:

+ (UIImage *) imageFromSampleBuffer:(CMSampleBufferRef) sampleBuffer 
{ 
    // Get a CMSampleBuffer's Core Video image buffer for the media data 
    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); 
    // Lock the base address of the pixel buffer 
    CVPixelBufferLockBaseAddress(imageBuffer, 0); 

    // Get the number of bytes per row for the pixel buffer 
    void *baseAddress = CVPixelBufferGetBaseAddress(imageBuffer); 

    // Get the number of bytes per row for the pixel buffer 
    size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer); 
    // Get the pixel buffer width and height 
    size_t width = CVPixelBufferGetWidth(imageBuffer); 
    size_t height = CVPixelBufferGetHeight(imageBuffer); 

    // Create a device-dependent RGB color space 
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 

    // Create a bitmap graphics context with the sample buffer data 
    CGContextRef context = CGBitmapContextCreate(baseAddress, width, height, 8, 
              bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst); 
    // Create a Quartz image from the pixel data in the bitmap graphics context 
    CGImageRef quartzImage = CGBitmapContextCreateImage(context); 
    // Unlock the pixel buffer 
    CVPixelBufferUnlockBaseAddress(imageBuffer,0); 

    // Free up the context and color space 
    CGContextRelease(context); 
    CGColorSpaceRelease(colorSpace); 

    // Create an image object from the Quartz image 
    UIImage *image = [UIImage imageWithCGImage:quartzImage]; 

    // Release the Quartz image 
    CGImageRelease(quartzImage); 

    return (image); 
} 

Mezcla la UIImage con la superposición

  • Ahora que tiene el UIImage, agréguelo a un nuevo UIView.
  • Agregue la superposición en la parte superior como una subvista.

captura de la nueva UIView

+ (UIImage*)imageWithView:(UIView*)view 
{ 
    UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, [UIScreen mainScreen].scale); 
    [view.layer renderInContext:UIGraphicsGetCurrentContext()]; 
    UIImage* img = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 
    return img; 
} 
+0

Creo que esto es lo que estoy buscando. Intentaremos que esto funcione y le haremos saber cómo funciona. ¡Gracias por la rápida respuesta! –

+0

¿está utilizando una extensión de uiimage para image = [image rotar: UIImageOrientationRight]; ? –

+0

Sí, ese paso es opcional. Sin embargo, déjame darte el código. –

Cuestiones relacionadas