1

我使用 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 也无济于事。(对不起,我忘记了它的确切变量。几个月前。)

是什么导致了这个问题?我能做些什么来解决这个问题?

4

2 回答 2

1

查看Apple Docs 中此页面中的将 CMSampleBuffer 转换为 UIImage部分。我还没有尝试过,但它显示了如何获取bytesPerRow- 包括填充 - 缓冲区。

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

于 2012-12-05T18:23:08.227 回答
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
    }
于 2012-12-05T17:30:21.820 回答