将 CVImageBufferRef 转换为 PNG
我想使用 QTKit.framework 将所有帧写入磁盘以进行相机输入。但我得到的所有图像都是半透明的并且没有一些颜色,也许是色彩空间问题? ;( 它们在预览视图中看起来不错,但是当我编写它们时,“某些事情”发生了。 我想知道那是什么。
-(void)savePNGImage:(CGImageRef)imageRef path:(NSString *)path {
NSURL *outURL = [[NSURL alloc] initFileURLWithPath:path];
CGImageDestinationRef dr = CGImageDestinationCreateWithURL ((CFURLRef)outURL, (CFStringRef)@"public.png" , 1, NULL);
CGImageDestinationAddImage(dr, imageRef, NULL);
CGImageDestinationFinalize(dr);
[outURL release];
}
-(void)saveJPEGImage:(CGImageRef)imageRef path:(NSString *)path {
CFMutableDictionaryRef mSaveMetaAndOpts = CFDictionaryCreateMutable(nil, 0,
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(mSaveMetaAndOpts, kCGImageDestinationLossyCompressionQuality,
[NSNumber numberWithFloat:1.0]); // set the compression quality here
NSURL *outURL = [[NSURL alloc] initFileURLWithPath:path];
CGImageDestinationRef dr = CGImageDestinationCreateWithURL ((CFURLRef)outURL, (CFStringRef)@"public.jpeg" , 1, NULL);
CGImageDestinationAddImage(dr, imageRef, mSaveMetaAndOpts);
CGImageDestinationFinalize(dr);
[outURL release];
}
- (void)captureOutput:(QTCaptureOutput *)captureOutput
didOutputVideoFrame:(CVImageBufferRef)videoFrame
withSampleBuffer:(QTSampleBuffer *)sampleBuffer
fromConnection:(QTCaptureConnection *)connection{
CVPixelBufferLockBaseAddress(videoFrame,0);
uint8_t *baseAddress = (uint8_t *)CVPixelBufferGetBaseAddress(videoFrame);
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(videoFrame);
size_t width = CVPixelBufferGetWidth(videoFrame);
size_t height = CVPixelBufferGetHeight(videoFrame);
CVPixelBufferUnlockBaseAddress(videoFrame,0);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef newContext = CGBitmapContextCreate(baseAddress,
width, height, 8,
bytesPerRow,
colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
CGImageRef frame = CGBitmapContextCreateImage(newContext);
CGContextRelease(newContext);
CGColorSpaceRelease(colorSpace);
[self savePNGImage:frame path:[NSString stringWithFormat:@"/Users/nacho4d/Desktop/framesCam/frame%003d.png", frameNum++]];
[self saveJPEGImage:frame path:[NSString stringWithFormat:@"/Users/nacho4d/Desktop/framesCam/frame%003d.jpeg", frameNum++]];
CGImageRelease(frame);
}
捕获器属性只是帧大小和像素格式,如下所示: [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32ARGB], (id)kCVPixelBufferPixelFormatTypeKey
更新:
我也尝试过使用 JPEG,并且得到了相同类型的图像,就像图像中缺少一些通道,并且所有写入的帧都有一个白色背景。 (因为JPEG不允许透明??)
原始和书面(JPEG)之一:
(我不显示 PNG,因为它是透明的,很难在浏览器中看到)
提前致谢。
I want to write all frames to disk using QTKit.framework for camera input. But all the images I get are half transparent and without some colors, maybe colorspace problem? ;(
They seem good in the preview View but when I write them "something" happens.
I wonder what it that.
-(void)savePNGImage:(CGImageRef)imageRef path:(NSString *)path {
NSURL *outURL = [[NSURL alloc] initFileURLWithPath:path];
CGImageDestinationRef dr = CGImageDestinationCreateWithURL ((CFURLRef)outURL, (CFStringRef)@"public.png" , 1, NULL);
CGImageDestinationAddImage(dr, imageRef, NULL);
CGImageDestinationFinalize(dr);
[outURL release];
}
-(void)saveJPEGImage:(CGImageRef)imageRef path:(NSString *)path {
CFMutableDictionaryRef mSaveMetaAndOpts = CFDictionaryCreateMutable(nil, 0,
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(mSaveMetaAndOpts, kCGImageDestinationLossyCompressionQuality,
[NSNumber numberWithFloat:1.0]); // set the compression quality here
NSURL *outURL = [[NSURL alloc] initFileURLWithPath:path];
CGImageDestinationRef dr = CGImageDestinationCreateWithURL ((CFURLRef)outURL, (CFStringRef)@"public.jpeg" , 1, NULL);
CGImageDestinationAddImage(dr, imageRef, mSaveMetaAndOpts);
CGImageDestinationFinalize(dr);
[outURL release];
}
- (void)captureOutput:(QTCaptureOutput *)captureOutput
didOutputVideoFrame:(CVImageBufferRef)videoFrame
withSampleBuffer:(QTSampleBuffer *)sampleBuffer
fromConnection:(QTCaptureConnection *)connection{
CVPixelBufferLockBaseAddress(videoFrame,0);
uint8_t *baseAddress = (uint8_t *)CVPixelBufferGetBaseAddress(videoFrame);
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(videoFrame);
size_t width = CVPixelBufferGetWidth(videoFrame);
size_t height = CVPixelBufferGetHeight(videoFrame);
CVPixelBufferUnlockBaseAddress(videoFrame,0);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef newContext = CGBitmapContextCreate(baseAddress,
width, height, 8,
bytesPerRow,
colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
CGImageRef frame = CGBitmapContextCreateImage(newContext);
CGContextRelease(newContext);
CGColorSpaceRelease(colorSpace);
[self savePNGImage:frame path:[NSString stringWithFormat:@"/Users/nacho4d/Desktop/framesCam/frame%003d.png", frameNum++]];
[self saveJPEGImage:frame path:[NSString stringWithFormat:@"/Users/nacho4d/Desktop/framesCam/frame%003d.jpeg", frameNum++]];
CGImageRelease(frame);
}
Capturer attributes are just frame size and pixel format like so:[NSNumber numberWithUnsignedInt:kCVPixelFormatType_32ARGB], (id)kCVPixelBufferPixelFormatTypeKey
Update:
I have tried with JPEG also and I get the same kind of image, like there are some channels lacking in the image and all written frames have a white background. (since JPEG does not allow transparence ??)
The original and the written (JPEG) one:
(I don't show the PNG since is transparent and is difficult to see in a browser)
Thanks in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我不确定你的问题是什么,但这是我将图像保存到磁盘的方法。只需传递您从委托方法中获得的 CVImageBufferRef,当然还有您自己的 URL,它应该可以正常工作。至少对我来说是这样。祝你好运!
I'm not sure what your problem is, but here's how I'm saving images to disk. Just pass in the CVImageBufferRef you get from your delegate method, and of course your own URL and it should work fine. At least it does for me. Good luck!
您在实际处理图像缓冲区之前就解锁了它。尝试移动这一行:
到最后
You're unlocking the image buffer before you've actually processed it. Try moving this line:
to the end
我正在做一些类似的事情,并看到同样的问题。我稍微修改了您的代码,并将
kCGImageAlphaPremultipliedFirst
更改为kCGImageAlphaNoneSkipFirst
。大概是因为该帧不包含 Alpha,即使它是每像素 32 位,这也解决了我的问题。I'm doing something somewhat similar, and seeing the same problem. I modified your code ever so slightly, and changed
kCGImageAlphaPremultipliedFirst
tokCGImageAlphaNoneSkipFirst
. Presumably because the frame doesn't contain alpha even though it's 32 bits per pixel this fixed the problem for me.