AVCaptureSession“输出样本缓冲区”读取像素坐标给出错误的颜色

时间:2012-12-05 17:30:22

标签: ios pixel avcapturesession

我使用AVCaptureSession启动视频捕获会话并从视频帧中读取像素颜色。视频设置是这样的。

NSDictionary* videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:
                               [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA],
                               kCVPixelBufferPixelFormatTypeKey,
                               nil];

使用下面的委托方法获取样本缓冲区,稍后我会读取像素颜色。

- (void)captureOutput:(AVCaptureOutput *)captureOutput // captureOutput is only the AVCaptureVideoDataOutput
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer 
       fromConnection:(AVCaptureConnection *)connection 
{ 

    NSAutoreleasePool * pool = [NSAutoreleasePool new]; // instrument tells it leaks

    /*******  START CALCULATION  *******/

    imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); 
    CVPixelBufferLockBaseAddress(imageBuffer,0); // lock image buffer
    buffer_baseAddress = (uint8_t *)CVPixelBufferGetBaseAddress(imageBuffer); // raw buffer data BGRA

...

变量buffer_baseAddress是一个存储像素颜色的数组,在kCVPixelFormatType_32BGRA设置下,数组会像 [B] [G] [R] [A] [B] [G] [R] [A] [B] ... [B] [G] [R] [A]。因此,要在某个坐标处获得像素颜色,我必须在缓冲区中找出3个索引。所以在(x,y)=(10,0)处,BGR将在索引40,41和42处。

这是问题所在。样本缓冲区的第一行(y == 0)似乎始终提供正确的颜色。但是当我向前移动到第二行(y> 0)时,我在某些预设上或使用前/后相机时出现错误的颜色。 就像缓冲区在某一特定设置中每行末尾都附加了一些未知的额外数据。幸运的是,在我的实验中,我发现每个样本缓冲区在每一行都被移动了一些在背面摄像头上使用 AVCaptureSessionPresetHigh,在前/后摄像头上使用AVCaptureSessionPresetMedium 。我记得在一个AVCaptureSession类中设置一些rowPadding = 0也没有帮助。 (对不起,我忘记了它的确切变量。几个月前。)

是什么导致了这个问题?我该怎么做才能解决这个问题?

2 个答案:

答案 0 :(得分:1)

从Apple文档中查看此页面中的Converting a CMSampleBuffer to a UIImage部分。我没有尝试过,但它显示了如何获取缓冲区的bytesPerRow - 包括填充。

将图像缓冲区填充到最佳值是正常的,无论您使用的是CoreVideo,CoreImage,Quartz,Quicktime等等。总有办法找出它是什么。

答案 1 :(得分:0)

这是我目前的解决方案。不是最好的,但它可以帮助我克服它。我只测试每个AVCaptureSessionPreset中的每一个,看看哪个像素读取错误。然后我尝试猜测额外填充的大小,并在计算样本缓冲区索引时使用它。 这个神奇的数字是8 ,花了我几天才发现这个。所以希望这对某人有帮助,至少作为一种解决方法。 : - )

    // Look like this magic padding is affected by AVCaptureSessionPreset and front/back camera
    if ([[self currentPresetSetting] isEqualToString:AVCaptureSessionPresetHigh] && ![self isUsingFrontFacingCamera]) {
        buffer_rowPixelPadding = 8;
    }
    else if ([[self currentPresetSetting] isEqualToString:AVCaptureSessionPresetMedium]) {
        buffer_rowPixelPadding = 8;
    }
    else {
        buffer_rowPixelPadding = 0; // default
    }