仅在UIImageView的非透明像素上检测触摸
image-processing
ios
4
0

您如何有效地仅检测UIImageView非透明像素上的触摸?

考虑下面的图像,该图像随UIImageView显示。目的是使手势识别器仅在图像的非透明(在这种情况下为黑色)区域发生触摸时做出响应。

在此处输入图片说明

主意

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

奖金

  • 最好区分图像的外部透明像素和内部透明像素。在示例中,零内的透明像素也应视为有效。
  • 如果图像进行了变换会怎样?
  • 图像处理可以硬件加速吗?
参考资料:
Stack Overflow
收藏
评论
共 3 个回答
高赞 时间 活跃

在github上,您可以找到Ole Begemann项目,项目扩展了UIButton因此它只能检测按钮图像不透明的触摸。

由于UIButtonUIView的子类,因此使其适应UIImageView应该很简单。

希望这可以帮助。

收藏
评论

好吧,如果您需要非常快地执行此操作,则需要预先计算蒙版。

提取方法如下:

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进行此操作,然后在蒙版中填充该区域,或者保存多边形并使用点对多边形测试。

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

收藏
评论

这是我的快速实现:(基于为UIImage检索像素alpha值

- (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毫秒。它不占用内部空间,并且可能不是最佳选择。

收藏
评论
新手导航
  • 社区规范
  • 提出问题
  • 进行投票
  • 个人资料
  • 优化问题
  • 回答问题

关于我们

常见问题

内容许可

联系我们

@2020 AskGo
京ICP备20001863号