objective animatedimage iphone ios image-processing uiimageview hittest

iphone - animatedimage - Detectar los toques solo en píxeles no transparentes de UIImageView, de manera eficiente



objective c uiimage (3)

Aquí está mi implementación rápida: (basado en Recuperar un valor alfa de píxel para un 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; }

Esto supone que la imagen está en el mismo espacio de coordenadas que el point . Si la escala continúa, puede que tenga que convertir el point antes de verificar los datos de píxeles.

Parece que funciona muy rápido para mí. Estaba midiendo aprox. 0.1-0.4 ms para esta llamada de método. No hace el espacio interior, y probablemente no sea óptimo.

¿Cómo detectaría los toques solo en píxeles no transparentes de un UIImageView eficiente?

Considera una imagen como la siguiente, que se muestra con UIImageView . El objetivo es hacer que los reconocedores de gestos respondan solo cuando el toque ocurre en el área no transparente (negro en este caso) de la imagen.

Ideas

  • Reemplazar hitTest:withEvent: o pointInside:withEvent: aunque este enfoque puede ser terriblemente ineficiente, ya que estos métodos reciben muchas llamadas durante un evento táctil.
  • Comprobar si un solo píxel es transparente podría generar resultados inesperados, ya que los dedos son más grandes que un píxel. Verificar un área circular de píxeles alrededor del punto de golpe o intentar encontrar un camino transparente hacia un borde podría funcionar mejor.

Prima

  • Sería bueno diferenciar entre píxeles transparentes externos e internos de una imagen. En el ejemplo, los píxeles transparentes dentro del cero también deben considerarse válidos.
  • ¿Qué sucede si la imagen tiene una transformación?
  • ¿Se puede acelerar el proceso de imagen?

Bueno, si necesitas hacerlo realmente rápido, necesitas precalcular la máscara.

He aquí cómo extraerlo:

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

O puede usar la solución de contexto de mapa de bits 1x1 para precalcular la máscara. Tener una máscara significa que puede verificar cualquier punto con el costo de un acceso a la memoria indexada.

En cuanto a comprobar un área mayor que un píxel, verificaría los píxeles en un círculo con el centro en el punto de contacto. Alrededor de 16 puntos en el círculo deberían ser suficientes.

Detección de píxeles internos: otro paso de precalculación: debe encontrar el casco convexo de la máscara. Puede hacerlo utilizando el algoritmo "Graham scan" http://softsurfer.com/Archive/algorithm_0109/algorithm_0109.htm Luego, rellene ese área en la máscara o guarde el polígono y use una prueba de punto en el polígono.

Y finalmente, si la imagen tiene una transformación, necesita convertir las coordenadas del punto del espacio de la pantalla al espacio de la imagen, y luego puede simplemente verificar la máscara precalculada.


En github, puede encontrar un proyecto de Ole Begemann que extiende UIButton para que solo detecte los toques donde la imagen del botón no es transparente.

Como UIButton es una subclase de UIView , adaptarla a UIImageView debería ser sencillo.

Espero que esto ayude.