как конвертировать CVImageBufferRef в UIImage - PullRequest
22 голосов
/ 30 июня 2010

Я пытаюсь захватить видео с камеры.я получил captureOutput:didOutputSampleBuffer: обратный вызов для запуска, и он дает мне пример буфера, который я затем преобразовать в CVImageBufferRef.затем я пытаюсь преобразовать это изображение в UIImage, которое затем можно просмотреть в моем приложении.

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
{
    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); 
    /*Lock the image buffer*/
    CVPixelBufferLockBaseAddress(imageBuffer,0); 
    /*Get information about the image*/
    uint8_t *baseAddress = (uint8_t *)CVPixelBufferGetBaseAddress(imageBuffer); 
    size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer); 
    size_t width = CVPixelBufferGetWidth(imageBuffer); 
    size_t height = CVPixelBufferGetHeight(imageBuffer); 

    /*We unlock the  image buffer*/
    CVPixelBufferUnlockBaseAddress(imageBuffer,0);

    /*Create a CGImageRef from the CVImageBufferRef*/
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
    CGContextRef newContext = CGBitmapContextCreate(baseAddress, width, height, 8, bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst); 
    CGImageRef newImage = CGBitmapContextCreateImage(newContext); 

    /*We release some components*/
    CGContextRelease(newContext); 
     CGColorSpaceRelease(colorSpace);

     /*We display the result on the custom layer*/
    /*self.customLayer.contents = (id) newImage;*/

    /*We display the result on the image view (We need to change the orientation of the image so that the video is displayed correctly)*/
    UIImage *image= [UIImage imageWithCGImage:newImage scale:1.0 orientation:UIImageOrientationRight];
    self.capturedView.image = image;

    /*We relase the CGImageRef*/
    CGImageRelease(newImage);
}

код работает нормально до вызова CGBitmapContextCreate.он всегда возвращает указатель NULL.следовательно, ни одна из остальных функций не работает.Независимо от того, что я, кажется, передать его, функция возвращает ноль.я понятия не имею, почему.

Ответы [ 4 ]

20 голосов
/ 04 июля 2010

То, как вы передаете baseAddress, предполагает, что данные изображения имеют вид

ACCC

(где C - некоторый компонент цвета, R || G || B).

Если вы настроили AVCaptureSession для захвата видеокадров в собственном формате, скорее всего, вы вернете видеоданные обратно в плоский формат YUV420. (см .: текст ссылки ). Чтобы сделать то, что вы пытаетесь сделать здесь, вероятно, проще всего было бы указать, что вы хотите, чтобы видеокадры были захвачены в kCVPixelFormatType_32RGBA. Apple рекомендует захватывать видеокадры в kCVPixelFormatType_32BGRA, если вы вообще захватываете его в непланарном формате, причина которого не указана, но я могу предположить, что это связано с соображениями производительности.

Предостережение: я этого не делал, и я предполагаю , что такой доступ к содержимому CVPixelBufferRef является разумным способом построения образа. Я не могу ручаться за то, что это действительно работает, но я / могу / сказать вам, что то, как вы делаете вещи сейчас, надежно не будет работать из-за формата пикселей, который вы (вероятно) захватывает видеокадры как.

13 голосов
/ 20 марта 2015

Если вам просто нужно преобразовать CVImageBufferRef в UIImage, это будет гораздо сложнее, чем должно быть.По сути, вам нужно конвертировать в CIImage, затем CGImage, THEN UIImage.Я хотел бы сказать вам, почему.Кто знает.

-(void) screenshotOfVideoStream:(CVImageBufferRef)imageBuffer
{
    CIImage *ciImage = [CIImage imageWithCVPixelBuffer:imageBuffer];
    CIContext *temporaryContext = [CIContext contextWithOptions:nil];
    CGImageRef videoImage = [temporaryContext
                             createCGImage:ciImage
                             fromRect:CGRectMake(0, 0,
                             CVPixelBufferGetWidth(imageBuffer),
                             CVPixelBufferGetHeight(imageBuffer))];

    UIImage *image = [[UIImage alloc] initWithCGImage:videoImage];
    [self doSomethingWithOurUIImage:image];
    CGImageRelease(videoImage);
}

Этот конкретный метод работал для меня, когда я конвертировал видео H.264 с использованием обратного вызова VTDecompressionSession для получения CVImageBufferRef (но он должен работать для любого CVImageBufferRef).Я использовал iOS 8.1, XCode 6.2.

4 голосов
/ 08 января 2016

Вы можете напрямую позвонить:

self.yourImageView.image=[[UIImage alloc] initWithCIImage:[CIImage imageWithCVPixelBuffer:imageBuffer]];
2 голосов
/ 24 августа 2012

Бенджамин Лульер написал действительно хороший пост о выводе CVImageBufferRef с учетом скорости при нескольких подходах.

Вы также можете найти рабочий пример на github;)

Как насчет возвращениявремя?;) Вот, пожалуйста: http://web.archive.org/web/20140426162537/http://www.benjaminloulier.com/posts/ios4-and-direct-access-to-the-camera

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...