Introducción

Este es el segundo proyecto que he llegado a publicar. Es una aplicación de deportes para practicar la puntería desde casa. Sin duda este proyecto fué mucho más difícil e interesante de desarrollar que Flying Poo, el anterior que hice. Lo publiqué en 2021 y tardé unos dos meses para desarrollarlo.

Tráiler:

El desarrollo

Exceptuando unas cinco líneas de código que hicieron falta para hacer que la cámara funcionase correctamente en IOS, todo está programado en Python usando un framework multiplataforma llamado Kivy. Lo hice así por dos razones: la primera es para acostumbrarme más a programar en Python, y la segunda es para no tener que reimplementar el mismo código para cada plataforma.

A primera vista, el principal reto para crear este programa es conseguir detectar la posición del láser. De hecho, esta fué una parte bastante divertida. Al principio pensé que usar redes neuronales podría ser una buena solución, pero acabé teniendo una mejor idea. Primero hice una gravación de prueba, donde aparecen diferentes disparos del láser, y luego usé la librería de OpenCV (aunque más tarde tuve que cambiarla por Numpy, porque no hay una receta que lo compile para IOS) para experimentar con varias ideas.

Tras muchos experimentos y pruebas se me ocurrió calcular la diferencia entre los píxeles del fotograma actual y el anterior, y funcionó sorprendentemente bien. Aparecía algo de ruido, pero se solucionó al filtrar los píxeles que variaban menos. Luego solo fué jugar un poco con los parámetros para mejorar los resultados. Aunque en condiciones de alta luminosidad el láser apenas destaca entre el ruido causado por la luz ambiental, por lo que tuve que implementar una función que detecta si este es el caso y avise al usuario. Decidí usar solo una de las capas RGB para ahorrar recursos y descubrí que el canal verde es el que detecta el láser más limpiamente (algo que me pareció curioso, ya que el láser que usé para las pruebas es rojo). Para calcular la puntuación, apliqué una máscara para saber dentro de qué anillo impactó el láser.

Los problemas

Después vino la parte algo menos entretenida: llevarlo a una aplicación real. Esta parte no tiene mucho misterio, y como la mayoría de proyectos de desarrollo de software se podría resumir en tres pasos: decidir cuál será el siguiente paso; googlear cómo hacer X; buscar porqué no funciona Z; y repetir. Este método funciona siempre y cuando alguien haya tenido un problema parecido antes o exista algún tipo de documentación. Dada la reducida comunidad que tiene Kivy, es de esperar que aparezcan problemas nunca planteados, pero cuando ni siquiera hay documentación que esté relacionada, esto se vuelve un verdadero problema.

Al intentar migrar el código a IOS, resultó que ya no podía acceder al buffer de la cámara para poder manipular la imágen. Como nada de esto está documentado, mi única opción era leer el código fuente de Kivy, y resulta que en la implementación de Kivy para IOS el código que usaba para acceder al buffer era inexistente, y no tengo conocimientos suficientes sobre IOS como para poder implementarlo por mí mismo. Mientras leía el código me daba cuenta de que mis opciones se reducían cada vez más, y empecé a entrar en desesperación. Pedir ayuda podría no ser una opción, ya que nadie ha sido capaz de capturar el buffer de la cámara en IOS… ¿o tal vez sí? Ahí es donde entra mi salvación: zbarcam, un escáner de códigos de barra y QRs.

Al parecer los desarrolladores de este paquete fueron los únicos que, usando Kivy, han sido capaces de acceder al buffer de la cámara desde IOS. Para facilitar el proceso y no tener que modificar el código fuente directamente, opté por importarlo y usar la magia de la POO para heredar las características de cualquier clase y poder modificar sus funciones a gusto.

Resultados

Gracias a este proyecto, pulí mis habilidades con Python y tuve una primera degustación de cómo es la investigación en el área de la computación, y resultó ser bastante divertido. Eso sí, me he saltado muchos problemas que tuve en este resumen, como usar las APIs de Android e IOS desde Python para poder imprimir la diana, o corregir la orientación de la cámara en IOS accediendo a la API del giroscopio y medir la inclinación (porque por algún motivo IOS gira por defecto la imágen en función de la orientación del teléfono, y no pude encontrar ninguna forma de desactivarlo con Kivy).

Dejo por aquí los enlaces a Google Play y a la App Store por si le interesa a alguien.