捕获仍然没有压缩的 UIImage(来自 CMSampleBufferRef)?
Posted
技术标签:
【中文标题】捕获仍然没有压缩的 UIImage(来自 CMSampleBufferRef)?【英文标题】:Capture still UIImage without compression (from CMSampleBufferRef)? 【发布时间】:2013-03-22 14:30:39 【问题描述】:我需要从 CMSampleBufferRef 的未压缩图像数据中获取UIImage
。我正在使用代码:
captureStillImageOutput captureStillImageAsynchronouslyFromConnection:connection
completionHandler:^(CMSampleBufferRef imageSampleBuffer, NSError *error)
// that famous function from Apple docs found on a lot of websites
// does NOT work for still images
UIImage *capturedImage = [self imageFromSampleBuffer:imageSampleBuffer];
http://developer.apple.com/library/ios/#qa/qa1702/_index.html 是指向imageFromSampleBuffer
函数的链接。
但它不能正常工作。 :(
有一个jpegStillImageNSDataRepresentation:imageSampleBuffer
方法,但它给出了压缩数据(嗯,因为JPEG)。
如何在捕获静止图像后使用最原始的非压缩数据创建UIImage
?
也许,我应该为视频输出指定一些设置?我目前正在使用这些:
captureStillImageOutput = [[AVCaptureStillImageOutput alloc] init];
captureStillImageOutput.outputSettings = @ (id)kCVPixelBufferPixelFormatTypeKey : @(kCVPixelFormatType_32BGRA) ;
我注意到,该输出的默认值为AVVideoCodecKey
,即AVVideoCodecJPEG
。是否可以通过任何方式避免它,或者在捕获静止图像时这是否重要?
我在那里找到了一些东西:Raw image data from camera like "645 PRO",但我只需要一个 UIImage,而不使用 OpenCV 或 OGLES 或其他第 3 方。
【问题讨论】:
SO上有很多类似的问题和解决方案。 @Jeepston 找不到任何可用于静止图像的工作... 【参考方案1】:imageFromSampleBuffer
方法确实有效,实际上我正在使用它的更改版本,但如果我没记错的话,您需要正确设置 outputSettings。我认为您需要将键设置为kCVPixelBufferPixelFormatTypeKey
,将值设置为kCVPixelFormatType_32BGRA
。
例如:
NSString* key = (NSString*)kCVPixelBufferPixelFormatTypeKey;
NSNumber* value = [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA];
NSDictionary* outputSettings = [NSDictionary dictionaryWithObject:value forKey:key];
[newStillImageOutput setOutputSettings:outputSettings];
编辑
我正在使用这些设置拍摄静止图像而不是视频。 你的 sessionPreset 是 AVCaptureSessionPresetPhoto 吗?可能有问题
AVCaptureSession *newCaptureSession = [[AVCaptureSession alloc] init];
[newCaptureSession setSessionPreset:AVCaptureSessionPresetPhoto];
编辑 2
关于将其保存到 UIImage 的部分与文档中的部分相同。这就是我要求问题的其他根源的原因,但我想那只是抓住稻草。 我知道还有另一种方法,但这需要 OpenCV。
- (UIImage *) imageFromSampleBuffer:(CMSampleBufferRef) sampleBuffer
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
CVPixelBufferLockBaseAddress(imageBuffer, 0);
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);
我想这对你没有帮助,对不起。我知道的不够多,无法为您的问题考虑其他根源。
【讨论】:
您是否使用imageFromSimpleBuffer
从静止图像而非视频中获取数据?如果是,请您将更改后的实现添加到您的答案中吗?我的设置和你的完全一样,看问题中的第二个代码块:)
很抱歉,我应该更仔细地阅读您的问题。我编辑了我的答案。
谢谢,当然是这样的预设等等。你能把你的imageFromSimpleBuffer
实现发给我吗?
抱歉,我认为这不会有帮助。
成功了!但它的方向错误:(但我会自己弄清楚,谢谢!【参考方案2】:
这里有一个更有效的方法:
UIImage *image = [UIImage imageWithData:[self imageToBuffer:sampleBuffer]];
- (NSData *) imageToBuffer:(CMSampleBufferRef)source
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(source);
CVPixelBufferLockBaseAddress(imageBuffer,0);
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
size_t width = CVPixelBufferGetWidth(imageBuffer);
size_t height = CVPixelBufferGetHeight(imageBuffer);
void *src_buff = CVPixelBufferGetBaseAddress(imageBuffer);
NSData *data = [NSData dataWithBytes:src_buff length:bytesPerRow * height];
CVPixelBufferUnlockBaseAddress(imageBuffer, 0);
return data;
【讨论】:
以上是关于捕获仍然没有压缩的 UIImage(来自 CMSampleBufferRef)?的主要内容,如果未能解决你的问题,请参考以下文章