Можно ли визуализировать AVCaptureVideoPreviewLayer в графическом контексте? - PullRequest
19 голосов
/ 26 января 2012

Это кажется простой задачей, но это сводит меня с ума. Можно ли преобразовать UIView, содержащий AVCaptureVideoPreviewLayer в качестве подслоя, в изображение для сохранения? Я хочу создать наложение дополненной реальности и иметь кнопку для сохранения изображения в кадре камеры.Удерживая кнопку питания + клавишу «Домой», снимок экрана снимается в рулоне камеры, а это означает, что вся моя логика захвата работает, И задача возможна.Но я не могу заставить его работать программно.

Я делаю предварительный просмотр изображения с камеры с помощью AVCaptureVideoPreviewLayer.Все мои попытки отрисовки изображения терпят неудачу:

  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);
}

// это отрисовывает все, КРОМЕ для слоя предварительного просмотра, который является пустым.

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

Я где-то читал, что это может быть связано с проблемами безопасности iPhone.Это правда?

Просто чтобы прояснить: Я не хочу сохранять изображение для камеры.Я хочу сохранить прозрачный слой предварительного просмотра, наложенный поверх другого изображения, таким образом создавая прозрачность. И все же по какой-то причине я не могу заставить его работать.

Ответы [ 2 ]

17 голосов
/ 09 июня 2013

Мне нравится предложение @ Roma использовать GPU Image - отличная идея.,,,однако если вы хотите использовать подход CocoaTouch, вот что нужно сделать:

Реализация 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];
        }
    }
}

Capture as следующим образом:

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

Смешайте UIImage с наложением

  • Теперь, когда у вас есть UIImage, добавьте его в новый UIView.
  • Добавить оверлей сверху в качестве дополнительного вида.

Захват нового UIView

+ (UIImage*)imageWithView:(UIView*)view
{
    UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, [UIScreen    mainScreen].scale);
    [view.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage* img = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return img;
}
4 голосов
/ 09 июня 2013

Я могу посоветовать вам попробовать GPU Image.

https://github.com/BradLarson/GPUImage

Он использует openGL, поэтому он довольно быстрый.Он может обрабатывать изображения с камеры и добавлять к ним фильтры (их много), включая обнаружение краев, обнаружение движения и многое другое

Это похоже на OpenCV, но, исходя из моего собственного опыта, с графическим процессором легче связываться сваш проект и язык объективный-c.

Проблема может возникнуть, если вы решили использовать box2d для физики - она ​​тоже использует openGl, и вам нужно будет потратить некоторое время, пока эти 2 фреймворка перестанут сражаться))

...