26

您将如何有效地检测仅对 a 的非透明像素的触摸UIImageView

考虑如下图所示的图像,显​​示为UIImageView。目标是使手势识别器仅在触摸发生在图像的非透明(本例中为黑色)区域时做出响应。

在此处输入图像描述

想法

  • 覆盖hitTest:withEvent:or pointInside:withEvent:,尽管这种方法可能非常低效,因为这些方法在触摸事件期间被多次调用。
  • 检查单个像素是否透明可能会产生意想不到的结果,因为手指大于一个像素。检查命中点周围的圆形像素区域,或尝试找到通向边缘的透明路径可能会更好。

奖金

  • 区分图像的外部和内部透明像素会很好。在示例中,零内的透明像素也应该被认为是有效的。
  • 如果图像有变换会发生什么?
  • 图像处理可以硬件加速吗?
4

3 回答 3

19

这是我的快速实现:(基于Retrieving a pixel alpha value for a UIImage

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    //Using code from https://stackoverflow.com/questions/1042830/retrieving-a-pixel-alpha-value-for-a-uiimage

    unsigned char pixel[1] = {0};
    CGContextRef context = CGBitmapContextCreate(pixel,
                                                 1, 1, 8, 1, NULL,
                                                 kCGImageAlphaOnly);
    UIGraphicsPushContext(context);
    [image drawAtPoint:CGPointMake(-point.x, -point.y)];
    UIGraphicsPopContext();
    CGContextRelease(context);
    CGFloat alpha = pixel[0]/255.0f;
    BOOL transparent = alpha < 0.01f;

    return !transparent;
}

这假设图像与point. 如果继续缩放,您可能必须point在检查像素数据之前进行转换。

对我来说似乎工作得很快。我正在测量大约。此方法调用需要 0.1-0.4 毫秒。它不做内部空间,并且可能不是最佳的。

于 2012-11-08T17:42:55.857 回答
6

在 github 上,您可以找到Ole Begemann 的一个项目,该项目进行了扩展UIButton,以便仅检测按钮图像不透明的触摸。

由于UIButton是 的子类UIView,因此对其进行调整UIImageView应该很简单。

希望这可以帮助。

于 2012-11-08T15:26:25.760 回答
3

好吧,如果你需要非常快地完成它,你需要预先计算掩码。

以下是如何提取它:

UIImage *image = [UIImage imageNamed:@"some_image.png"];
NSData *data = (NSData *) CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage));
unsigned char *pixels = (unsigned char *)[data bytes];
BOOL *mask = (BOOL *)malloc(data.length);
for (int i = 0; i < data.length; i += 4) {
  mask[i >> 2] = pixels[i + 3] == 0xFF; // alpha, I hope
}
// TODO: save mask somewhere

或者您可以使用 1x1 位图上下文解决方案来预先计算掩码。拥有一个掩码意味着您可以使用一次索引内存访问的成本检查任何点。

至于检查大于一个像素的区域 - 我会检查以触摸点为中心的圆圈上的像素。圆圈上大约 16 个点应该足够了。

还检测内部像素:另一个预计算步骤 - 您需要找到掩码的凸包。您可以使用“格雷厄姆扫描”算法http://softsurfer.com/Archive/algorithm_0109/algorithm_0109.htm来做到这一点, 然后在掩码中填充该区域,或保存多边形并改用多边形点测试。

最后,如果图像有变换,则需要将点坐标从屏幕空间转换为图像空间,然后只需检查预先计算的蒙版即可。

于 2012-11-08T19:16:44.633 回答