Ir al contenido principal

Crear una aplicación de dibujo basada en reconocimiento de manos

 Bienvenidos. En este informe explico algo sobre el video que hice acerca de cómo crear una aplicación de dibujo básica con TensorFlow.js, MediaPipe modelo de reconocimiento de manos y mi librería de WebComponents para simplificar el reconocimiento de objetos y acciones en consecuencia.

El video es el siguiente.



Primero creamos un proyecto web, simple, un documento HTML. Incorporamos en un Script la librería https://gorosito.red/componentes/

Insertamos el webComponent de etiqueta reconocer-manos. Agregamos dos atributos: DER="" e IZQ="", y cada uno apunta al nombre de una función que crearemos en un Script aparte.

Cada función se dedica a reconocer puntos clave de la mano izquierda y de la derecha de la primera persona reconocida. Bueno, simplifiqué a la herramienta para que fuera una sola persona.

Como función de tipo "callback" que son, se les pasa como parámetro un objeto, el mismo generado por TFjs, con tres factores: handedness (tipo de mano, string, si es "Left" o "Right"), keypoints (listado de puntos clave, en 2d) y keypoints3d (listado de puntos clave, en 3D).

En el ejemplo hice algo para reconocer 3 dedos (fingers), la punta (the tip) de cada uno: pulgar (thumb), índice (index) y el dedo medio (middle).

Si no ubicamos el thumb_finger_tip, index_finger_tip y middle_finger_tip entre los 21 ítems de cada lista, podemos filtrar la lista. Tomamos la lista, ejecutamos el método .filter() pasándole una función adecuada, y de los resultados nos quedamos con sólo el primero (ítem [0] de la lista).

La función de filtrado recibe un primer parámetro $item (por ejemplo), que representa a cada keypoint. Si hacen console.log($item) observarán que se tiene disponible una clave ["name"]/.name, indicando el nombre de la articulación o punto de la mano. Filtramos con una expresión regular /thumb/i y /tip/i, mediada por un operador lógico && (and) y obtendremos lo necesitado.

Una vez reconocidos los dedos, tendremos disponibles su ubicación a través de las claves .x y .y.

Si observamos las lecturas, a medida que un objeto baja, la .y crece. Por lo tanto, podemos comparar las alturas .y del índice y del dedo medio; si la de éste es un número más grande, estará más abajo. Con una toma de decisiones podemos "disparar" un evento y ejecutar una función.

La otra posibilidad, con un poco de geometría, podemos reconocer si dos dedos están pegados o muy cercanos, si trigonométricamente su hipotenusa es menor a una proporción respecto de la imagen. Aunque para el ejemplo, un número menor a 20 ó 30 nos basta.

Hacemos un delta horizontal y un delta vertical. No hace falta que hallemos el valor absoluto, ya que por teorema de Pitágoras los elevaremos al cuadrado a cada uno. Al hallar la raíz cuadrada de sus sumas, obtendremos la distancia solicitada.

¡Perfecto! Con un par de tomas de decisiones podemos reconocer la ubicación de los dedos y entonces dibujar en pantalla.

Ahora viene lo complicado, ¿Cómo dibujar? ¿En dónde dibujar? Se puede realizar esto mediante SVG; el webComponent desde el comienzo ya lo tenía agregado. Pero dibujar desde este objeto HTML, sin una librería, reconocí que es algo engorroso. Y yo conocía la API de Canvas HTML. Así que me dediqué a mejorar el webComponent y agregar un Canvas.

Para poder controlarlo, debía esperar un incierto tiempo, aquel por el cual la librería se descarga desde Internet y el navegador requiere generarlo. Así que modifiqué en el momento al WebComponent y le agregué un atributo LISTO="". Este atributo debe apuntar a una función que se ejecutará cuando el WebComponent se renderice.

Ahí se puede exponer el objeto Canvas que se ubicará en la misma posición que el objeto Video de la WebCam. Para ello creamos una variable global, $dibujo. En la función de LISTO deberemos igualarlo al .canvas del objeto de reconocer. Por ello, antes identifiqué al objeto mediante el atributo ID="", como idReconocer (id="idReconocer"). El navegador nos crea una variable con el mismo identificador para controlar al objeto. Por lo tanto, $dibujo = idReconocer.canvas.

Pero para la posibilidad de dibujar en él, tenemos que extraer el contexto 2D. Así que directamente $dibujo = idReconocer.canvas.getContext("2d");

Con $dibujo.beginPath(); podemos comenzar a dibujar. Si vamos a dibujar líneas contínuas (equivalente al objeto PATH de SVG), debemos jugar con $dibujar.moveTo() y $dibujar.lineTo(). Todo esto en la función fnDibujar(), a la cual se le pasa las coordenadas $x e $y de algún punto de la mano (por ejemplo, la punta del dedo índice o el pulgar). Cuando debamos efectuar el dibujo, se aplica $dibujar.stroke();

Finalmente, deberíamos hacer algo para cambiar de colores. Así que diseñé en el SVG algo para generar bloques de colores superpuestos sobre el Canvas. Ancho y alto 50 pixeles, en el medio de la imagen. Me confundí al principio porque el método que hice para que la webCam trabajara en espejo requiere dar vuelta el dibujo resultante (regla CSS de transform:translateX()).

Ahora, con la otra mano (función fnDer), hice algo para que al ubicar los dedos clave en el recuadro del color, el stroke se pintara de dicho color. No obstante, el dibujo se arruina debido a que como no reinicié el path (no hice $dibujo.beginPath()) todo lo anterior dibujado también cambiaba al nuevo color. Así que lo último del video es realizar ese cambio.

Muy buen comienzo de ilustraciones con Inteligencia Artificial.


Comentarios

Entradas populares de este blog

Probando ChatGPT - Mapa conceptual con Mermaid

 Había conversado con ChatGPT acerca de cuidado de las plantas e hidroponía. Luego de unos días me di cuenta que quizás también podría saber acerca de crear Mapas conceptuales. Salió lo siguiente; le falta un concepto para crear correctamente mapas conceptuales (la relación entre los conceptos), pero podría ser algo para ayudarnos a corregir mejor. El texto original era el que cito a continuación, pero le agregué explícitamente que me armara un "mapa conceptual" utilizando el lenguaje Mermaid, un lenguaje descriptivo que permite construir gráficos diversos, entre ellos Mapas conceptuales, generando un archivo SVG. ``` Hacé un mapa conceptual en lenguaje Mermaid con el siguiente texto, redactado anteriormente: "La hidroponía es un método de cultivo que se utiliza para cultivar plantas sin suelo utilizando una solución nutriente y agua. Algunas plantas pueden cultivarse con éxito mediante hidroponía, mientras que otras necesitan el suelo para crecer y prosperar. De las pl...

Conectar a Servidor Node.JS desde VB6 o VBA

El presente código sirve tanto para Visual Basic 6.0 (sí, todavía sirve, todavía sirve!) como para Visual Basic para Aplicaciones (Excel o VBA). ' Si estamos en Visual Basic para Aplicaciones agregar la referencia ' WinHTTP, en el menú Herramientas, Referencias, Microsoft WinHTTP Services Function Solicitar( _ ByVal URLBase As String _ , Optional ByVal Puerto As Integer = 80 _ , Optional ByVal Seccion As String = "" _ , Optional ByVal Metodo As String = "GET" _ ) As String On Error GoTo solucion #If VBA6 Then Dim objXML As New WinHttpRequest #ElseIf Win32 Then Dim objXML As Object Set objXML = CreateObject("MSXML2.ServerXMLHTTP") #End If objXML.Open Metodo, URLBase & ":" & Puerto & "/" & Seccion, False objXML.send If (objXML.Status = 404) Then Solicitar = "404 Error" Else Solicitar = objXML.responseText End If Se...