Как конвертировать CVImageBufferRef в UIImage
Я пытаюсь захватить видео с камеры. я получил 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 ответа
То, как вы передаете baseAddress, предполагает, что данные изображения находятся в форме
СКПК
(где C - некоторая цветовая составляющая, R || G || B).
Если вы настроили AVCaptureSession для захвата видеокадров в собственном формате, скорее всего, вы вернете видеоданные обратно в плоский формат YUV420. (см.: текст ссылки). Чтобы сделать то, что вы пытаетесь сделать здесь, вероятно, проще всего было бы указать, что вы хотите, чтобы видеокадры были захвачены в kCVPixelFormatType_32RGBA . Apple рекомендует захватывать видеокадры в kCVPixelFormatType_32BGRA, если вы вообще захватываете его в непланарном формате, причина чего не указана, но я могу предположить, что это связано с соображениями производительности.
Предостережение: я этого не делал, и я предполагаю, что такой доступ к содержимому CVPixelBufferRef является разумным способом построения образа. Я не могу ручаться за то, что это действительно работает, но я / могу / сказать вам, что то, как вы делаете вещи сейчас, надежно не будет работать из-за формата пикселя, который вы (вероятно) захватывает видеокадры.
Если вам просто нужно конвертировать 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.
Вы можете напрямую позвонить:
self.yourImageView.image=[[UIImage alloc] initWithCIImage:[CIImage imageWithCVPixelBuffer:imageBuffer]];
Бенджамин Лульер написал действительно хороший пост о выводе CVImageBufferRef с учетом скорости при нескольких подходах.
Вы также можете найти рабочий пример на github;)
Как насчет назад во времени?;) Вот и вы: http://web.archive.org/web/20140426162537/http://www.benjaminloulier.com/posts/ios4-and-direct-access-to-the-camera