仅在UIImageView的非透明像素上有效检测触摸

如何有效地检测UIImageView的不透明像素?

考虑下面的图像,用UIImageView显示。 目标是使手势识别器只有在图像的非透明(在这种情况下是黑色)区域发生触摸时才作出响应。

在这里输入图像说明

思路

  • 重写hitTest:withEvent:pointInside:withEvent:虽然这种方法可能非常低效,因为这些方法在触摸事件中被调用了很多次。
  • 检查单个像素是否透明可能会产生意想不到的结果,因为手指大于一个像素。 检查命中点周围像素的圆形区域,或尝试find朝向边缘的透明path可能效果更好。

奖金

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

这是我的快速实现:(基于检索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毫秒。 它没有做内部空间,可能不是最佳的。

在github上,你可以findOle Begemann的一个项目,它扩展了UIButton ,使它只检测button图像不透明的地方。

由于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 

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

至于检查比一个像素更大的面积 – 我会检查在触摸点中心的圆上的像素。 圆上大概16点就够了。

检测内部像素:另一个预计算步骤 – 您需要find面罩的凸包。 您可以使用“格雷厄姆扫描”algorithmhttp://softsurfer.com/Archive/algorithm_0109/algorithm_0109.htm来做到这一点。然后,要么在面具中填写该区域,要么保存多边形,而是使用多边形点testing。

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