AVFoundation缓冲区与保存的图像比较

3

我是一位长期阅读StackOverflow的读者,第一次在这里发帖。我必须说,它为我提供了很多知识。

我正在尝试了解AVFoundation框架。

我的目标是保存相机所看到的内容,然后检测何时发生变化

以下是将图像保存到UIImage的部分:

if (shouldSetBackgroundImage) {
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    // Create a bitmap graphics context with the sample buffer data
    CGContextRef context = CGBitmapContextCreate(rowBase, bufferWidth,
        bufferHeight, 8, bytesPerRow,
        colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst); 
    // Create a Quartz image from the pixel data in the bitmap graphics context
    CGImageRef quartzImage = CGBitmapContextCreateImage(context); 

    // Free up the context and color space
    CGContextRelease(context); 
    CGColorSpaceRelease(colorSpace);

    // Create an image object from the Quartz image
    UIImage * image = [UIImage imageWithCGImage:quartzImage];
    [self setBackgroundImage:image];
    NSLog(@"reference image actually set");

    // Release the Quartz image
    CGImageRelease(quartzImage);

    //Signal that the image has been saved
    shouldSetBackgroundImage = NO;

}

这里是我检查相机捕捉到的图像是否有任何变化的部分:

else {

    CGImageRef cgImage = [backgroundImage CGImage];
    CGDataProviderRef provider = CGImageGetDataProvider(cgImage);
    CFDataRef bitmapData = CGDataProviderCopyData(provider);
    char* data = CFDataGetBytePtr(bitmapData);

    if (data != NULL)
    {
        int64_t numDiffer = 0, pixelCount = 0;
        NSMutableArray * pointsMutable = [NSMutableArray array];

        for( int row = 0; row < bufferHeight; row += 8 ) {
            for( int column = 0; column < bufferWidth; column += 8 ) {

                //we get one pixel from each source (buffer and saved image)
                unsigned char *pixel = rowBase + (row * bytesPerRow) + (column * BYTES_PER_PIXEL);
                unsigned char *referencePixel = data + (row * bytesPerRow) + (column * BYTES_PER_PIXEL);

                pixelCount++;

                if ( !match(pixel, referencePixel, matchThreshold) ) {
                    numDiffer++;
                    [pointsMutable addObject:[NSValue valueWithCGPoint:CGPointMake(SCREEN_WIDTH - (column/ (float) bufferHeight)* SCREEN_WIDTH - 4.0, (row/ (float) bufferWidth)* SCREEN_HEIGHT- 4.0)]];
                }
            }
        }
        numberOfPixelsThatDiffer = numDiffer;
        points = [pointsMutable copy];
    }

出于某种原因,这不起作用,这意味着iPhone几乎将保存的图像与所有检测到的东西都视为不同,即使我在匹配函数中设置了非常低的检测阈值...

你有什么想法我做错了什么吗?

2个回答

1

人类的眼睛和相机(即使是非常昂贵的相机)在感知微小的光线变化或小的运动变化方面有很大的不同。相机很敏感,但并不聪明!

根据您目前的方法(似乎您正在比较每个像素): 如果帧仅向右移动1个像素,会发生什么?您可以想象出算法的结果,对吧?人类几乎察觉不到任何变化。

还有相机快门问题:这意味着每个帧可能没有相同的光量。因此,逐像素比较方法太容易失败。

您至少要预处理图像并提取一些基本特征。也许是边缘、角落等。OpenCV 对此很容易,但我不确定在 iPhone 上进行这样的处理是否会很快。(这取决于您的图像大小)

或者,您可以尝试使用一个比您的整个视图大小略小的模板大小来进行幼稚的模板匹配算法

图像处理计算成本高,因此不要指望它第一次就能快速完成,特别是在移动设备上,如果您没有图像处理/计算机视觉方面的经验,那么速度会更慢。

希望能有所帮助 ;)

1

我能想到的为什么你几乎每个像素都不同有三种可能性:颜色空间转换、像素位置映射不正确或者你的阈值对iPhone相机实际运动过于敏感。前两种可能性不太可能,所以我认为可能是第三种,但还是值得检查一下。

当你将像素放置在UIImage中并稍后提取它们时,可能会进行一些颜色校正。你可以尝试简单地将它们存储在缓冲区的原始状态中,然后使用该原始缓冲区作为比较点,而不是UIImage的支持数据。

此外,请确保您的行/列算术在两个图像的实际像素位置上起作用。也许生成一个差异图像,即从两个图像中减去的绝对差异,然后使用一个简单的黑/白分割区域作为相机的测试图像。

最有可能的情况是整体图像移动超过一个像素,仅通过人手持它的行为就会导致这些整帧图像移位,这可能导致简单比较中几乎每个像素都不同。您可能需要调整阈值或执行更智能的运动估计,例如视频压缩例程中使用的方法。

最后,当涉及到比较操作时,我建议看一下OpenGL ES 2.0着色器来执行此操作。在我的基准测试中,与在CPU上逐像素比较相比,你应该会看到巨大的加速(14-28倍)。我在this article中展示了如何使用GPU进行基于颜色的阈值处理,其中包含有this iPhone sample application,它可以使用GLSL着色器实时跟踪彩色物体。

谢谢你的回答。在测试时,iPhone 放在底座上,所以没有任何“运动”发生。即使我用手指遮住相机(全黑图像),我也得到了80%到100%的差异...所以可能与存储为UIImage有关。你有什么办法可以将缓冲区“原样”存储吗? - nilsou
@user577552 - 你会得到一个指向CVImageBufferRef原始字节开头的指针,因此你可以动态分配足够的字节数来保存图像数据,然后使用类似memcpy()的函数从缓冲区中复制原始字节以供以后使用。 - Brad Larson
Brad,我刚刚看了你的文章,必须说它太棒了!我准备好去研究一下 :) - nilsou

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