3

我需要从 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.htmlimageFromSampleBuffer函数的链接。

但它不能正常工作。:(

有一种jpegStillImageNSDataRepresentation:imageSampleBuffer方法,但它给出了压缩数据(嗯,因为 JPEG)。

捕获静止图像后如何UIImage使用最原始的非压缩数据创建?

也许,我应该为视频输出指定一些设置?我目前正在使用这些:

captureStillImageOutput = [[AVCaptureStillImageOutput alloc] init];
captureStillImageOutput.outputSettings = @{ (id)kCVPixelBufferPixelFormatTypeKey : @(kCVPixelFormatType_32BGRA) };

我注意到,该输出的默认值为AVVideoCodecKey,即AVVideoCodecJPEG。是否可以以任何方式避免它,或者在捕获静止图像时它是否重要?

我在那里找到了一些东西:来自“645 PRO”之类的相机的原始图像数据,但我只需要一个 UIImage,而不使用 OpenCV 或 OGLES 或其他第 3 方。

4

2 回答 2

6

该方法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);

}

我想这对你没有帮助,对不起。我知道的不够多,无法为您的问题考虑其他根源。

于 2013-03-27T12:36:29.887 回答
1

这是一种更有效的方法:

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;
}
于 2016-08-20T07:47:58.723 回答