如何从iPhone相机创建灰度CGImage?

5
我想从iPhone相机数据中创建灰度CGImage。 我正在使用AVFoundation并将像素格式类型设置为
kCVPixelFormatType_420YpCbCr8BiPlanarFullRange

如果我理解正确,我应该能够从Y分量创建灰度图像,因此我已经实现了以下委托方法:
func captureOutput(captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, fromConnection connection: AVCaptureConnection!) {
        let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)

        CVPixelBufferLockBaseAddress(imageBuffer, 0)
        let yPlanBufferAddress = CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0)

        let width = CVPixelBufferGetWidth(imageBuffer)
        let height = CVPixelBufferGetHeight(imageBuffer)        

        let data = NSData(bytes: yPlanBufferAddress, length: width * height)
        let colorSpace = CGColorSpaceCreateDeviceGray()
        let dataProvider = CGDataProviderCreateWithCFData(data)
        let imageRef = CGImageCreate(width, height, 8, 8, width * 8, colorSpace, CGBitmapInfo.ByteOrderDefault, dataProvider, nil, false, kCGRenderingIntentDefault)
        let img = UIImage(CGImage: imageRef)

        CVPixelBufferUnlockBaseAddress(imageBuffer, 0)
        delegate?.cameraController(self, didCreateImage: img)
    }

但我得到了像这样的奇怪图像: 在此输入图片描述

有什么想法吗?

我发现了一个错误 - 在函数CGImageCreate中,bytesForRow的参数不应该是width * 8,而应该只是width。但即使修复了这个问题,我的图像看起来仍然像这样:http://zapodaj.net/409d6abaaecd5.png.html - MichalMoskala
3个回答

3
你需要获取Y平面的“bytesPerRow”,并将其提供给CGImageCreate函数。
let bytesPerRow = CVPixelBufferGetBytesPerRowOfPlane( w, 0 );

let imageRef = CGImageCreate(
    width
,   height
,   8
,   8
,   bytesPerRow

-1
创建灰度图像的最简单方法是使用类似于CIFliter的东西,只需调整值以获得所需的效果级别。您还可以将多个滤镜串联起来,以更好地控制对比度、曝光、颜色等方面的影响。
+ (UIImage *)makeBW:(UIImage *)imageToConvert
{
    CIImage *beginImage = [CIImage imageWithCGImage:[imageToConvert CGImage]];

    CIImage *blackAndWhite = [CIFilter filterWithName:@"CIColorControls"
                                        keysAndValues:
                              kCIInputImageKey, beginImage,
                              @"inputBrightness", [NSNumber numberWithFloat:0.0],
                              @"inputContrast", [NSNumber numberWithFloat:1.12],
                              @"inputSaturation", [NSNumber numberWithFloat:0.0], nil].outputImage;

    CIContext *context = [CIContext contextWithOptions:nil];

    CGImageRef cgiimage = [context createCGImage:output fromRect:output.extent];
    UIImage *newImg = [UIImage imageWithCGImage:cgiimage];

    CGImageRelease(cgiimage);

    return newImg;
}

但是灰度值应该与Y分量相同,对吧?所以我不需要进行任何过滤,只需从这些值创建图像即可。此外,您确定过滤器的结果将是灰度-每像素8位吗? - MichalMoskala
我对此并不确定,我不是一个视频专家,我只是一直使用CIFilter来获得这种效果。 - rmp
1
发现这个信息:YCbCr是用于表示数字组件视频的两个主要色彩空间之一(另一个是RGB)。 YCbCr和RGB之间的区别在于,YCbCr将颜色表示为亮度和两个颜色差信号,而RGB将颜色表示为红色,绿色和蓝色。 在YCbCr中,Y是亮度(亮度),Cb是蓝色减去亮度(B-Y),Cr是红色减去亮度(R-Y)。 请参见组件视频。 - rmp
是的,这就是为什么我将像素格式设置为kCVPixelFormatType_420YpCbCr8BiPlanarFullRange。灰度仅代表亮度,所以我应该能够只使用Y分量创建图像,但不知道出了什么问题。 - MichalMoskala

-1

之前我使用过一款名为 GPU Image by BradLarson 的框架,非常惊人,可以用来制作自定义滤镜。它们还有一些预定义的滤镜可供使用。速度非常快。

试试看吧!


谢谢您的评论,但我想了解我做错了什么 :) - MichalMoskala

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接