识别绘制图像的最佳方法

时间:2012-11-01 23:14:39

标签: iphone objective-c xcode image-processing cocos2d-iphone

今天我正在寻求关于识别绘制图像的最佳方法的建议。例如,如果您使用中文/日文键盘,您可以用手指绘制特殊符号,它将被识别,右侧符号将放置在文本区域中。我怎么能这样做?我在考虑使用cocos2d,Core Image可以帮忙吗?

我还想问另一个问题:假设你的屏幕装有雾纹,你必须用手指轻扫以清洁窗户。怎么做到呢?作为一个很好的例子,游戏Where's my Water使用类似这样的东西,你必须用手指滑动去除一些地面并为水腾出空间。

我希望听起来很清楚,我会很感激任何答案:)

1 个答案:

答案 0 :(得分:2)

有一些关于图像识别的SO帖子浮动。 This one可能是你想要的最接近的匹配,汤姆古伦的答案是非常全面的。您可能还想查看redmoskito对this question的回答。

我见过的一个相当基本的方法在以下任一帖子中都没有提到:

(我不能相信这一点 - 如果其他人可以找到来自的SO帖子,请告诉我!)

  1. 将您想要比较的图像缩小为小尺寸(例如4x4像素)
  2. 将用户的手绘图像缩小为相同尺寸
  3. 迭代像素并将它们(例如RGB)数据与收缩的参考图像像素进行比较。
  4. ((此处插入比较阈值))如果各个像素足够相似'到原始图像的像素 - 你有一个匹配。
  5. 如果您有一组封闭的比较图像并且您知道其中一个图像将是绘制的图像(这个想法是每个图像将具有唯一的4x4px'指纹' )。

    它的整体效果基于您用来确定什么定义了类似像素的算法" (例如,类似的RGB值,最近邻居相似性等),并且,收缩图像越大,过程就越精确。我已经使用这个通用程序合理地成功识别基本形状和字符。您需要一个非常好(并经过全面测试)的逻辑算法来提高这种生产质量。

    关于你的第二个问题,我认为你的意思是如何消除你的手指上的雾(就像在现实生活中发生的那样)。实现这一目标的一种方法是检测手指的位置并且"绘制alpha通道"然后它作为你的雾图像的掩码。或者,您可以直接绘制图像并设置相关像素' alpha值为0.

    这些只是一些想法,图像比较和操作的领域是巨大的。但希望这将为进一步探索提供一个起点。

    修改

    Apple提供两个不错的(iOS兼容)功能来提取像素数据。如果将它们包装在函数中:

    + (NSMutableData *)pixelDataFromImage:(UIImage *)image {
    
        NSMutableData *pixelData = (__bridge_transfer NSMutableData *)
        CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage));
        return pixelData;
        // Return data is of the form [RGBA RGBA RGBA ....]
        //                             ^^^^ ^^^^ ^^^^
        //               Byte Index:   0123 4567 89..
        //                             ^    ^    ^
        //             Pixel Number:   px1  px2  px3
    }
    

    所以基于上述4个步骤将它组合成一个(最小)算法:

    //...
    NSMutableData *imagePixelData = [self pixelDataFromImage:image];
    NSMutableData *referencePixelData = [self pixelDataFromImage:reference];
    // Both image and reference are UIImages
    
    if ([imagePixelData length] != [referencePixelData length]) {
        return 0.0f; // Can't compare, different number of pixels
    }
    
    Byte *imagePixelBytes = [imagePixelData mutableBytes];
    Byte *referencePixelBytes = [referencePixelData mutableBytes];
    
    int totalDifference = 0;
    float averageDifference = 0;
    int bytesCompared = 0;
    
    for (int i = 0; i < [imagePixelData length]; i++) {
    
        if ((i+1) % 4 == 0) { // Compare only alpha values in this example
                              // (compares images ignoring colour)
    
            int difference = (int)fabs(imagePixelBytes[i] - referencePixelBytes[i]];
            totalDifference += difference;
            bytesCompared += 1;
        }
    }
    
    averageDifference = totalDifference/bytesCompared;
    float similarity = 1.0f - (averageDifference/255);
    return similarity;
    // 1.0 => Exact match
    // Now you need to determine a threshold for "how similar means 'the same'".
    

    正如我所说,这只是极少,但它是实施上述程序的一种方式。当然,两个核心图形功能使生活变得更加容易,一旦掌握了数据,您最终只能比较两个字节数组。请注意,您仍然需要首先缩小图像(使用Core Graphics) - 有一些教程(e.g. here)。