Está en la página 1de 6

“Evaluación de proyecto final”,

Laboratorio de Fotografía y Video


Computacional

Martín Lazaroff
Ingeniería Audiovisual, Fac. de Ingeniería y Tecnologías, Universidad
Católica del Uruguay
martinglazaroff@gmail.com

Visión del proyecto:


El objetivo y desafío fundamental era montar un sistema integrado
por varias tecnologías conocidas (nodos del sistema, si se quiere)
comunicándose entre sí. De manera adicional, nos interesaba que
dicho sistema tuviera una “justificación audiovisual”.
Dentro de ese objetivo global, las prioridades fueron en el siguiente
orden:
1) Establecer conexión entre los diferentes nodos del sistema
(lenguajes de programación, hardware, étc).
2) Manejo (envío y recepción) e interpretación de datos en tiempo
real fruto de dicha conexión
3) Búsqueda de resultados audiovisuales a través de la
interpretación de los datos recibidos.
A partir de los objetivos planteados en la propuesta, se elaboró un
sistema que a través de una entrada única –una cámara-, provee de
datos en simultáneo a varias interfaces de programación orientadas
a distintas áreas (gráficos digitales, control de luces, generación de
sonido).
Fig 1, Esquema de montaje del sistema.

Interpretación del esquema:


1) PC1 corre Python. Captura la imagen de cámara –webcam en
nuestro prototipo- usando biblioteca OpenCV. Utilizando la
biblioteca de Machine Learning “Keras” y disponiendo de un
modelo pre-entrenado, deduce “esqueletos” virtuales
(conformados por líneas que indican el largo de cada “hueso”)
al detectar una o más personas en cámara. Este proceso se
realiza para cada frame que levanta de la cámara.
A cada parte del cuerpo (aka, “huesos”) le corresponde una línea,
de la que podemos saber: su largo, las coordenadas de los
extremos del segmento, las coordenadas de su punto medio y su
“score” (cuán acertada es la deducción), entre otros.
En nuestro sistema se eligieron como datos relevantes: las
coordenadas de su punto medio y el score.

2) PC1 se encarga (a través de Python) de empaquetar los datos


relevantes como un String (cadena de caracteres) y enviarlos al
resto de los nodos del sistema para luego ser reinterpretados
(es decir, que se logre algo con ellos). Los envíos se realizan a
través de Sockets TCP (para Processing, que también corre en
PC1 y para la instancia de Python que corre en PC2) y puerto
Serial (Arduino, conectado por USB a la PC1)
Era importante establecer un “código” a la hora de empaquetar los
datos para indicar: a qué persona y a qué parte del cuerpo
correspondían los datos enviados (coordenadas x,y del punto medio
del hueso y score). Dicha información era relevante para la
reinterpretación de los datos por parte de los nodos receptores. Para
ello, se designaron “caracteres de escape” que precisaban, en orden,
a) índice de la parte del cuerpo b) coordenada x del punto medio de
esa parte c) coordenada y del punto medio de esa parte d) score de
la predicción. Cada parte o hueso, a su vez, debía ser separado por
otro caracter de escape. El conjunto de huesos integraba una
persona, también delimitado a través de un carácter de escape.
3) Los nodos reciben el String enviado por Python de la PC1 y se
ocupan de seccionar los datos y guardarlos en variables según
corresponda. En función de los datos recibidos, generan
resultados audiovisuales.
Entrando más en detalle:
Processing genera visuales simples en un espacio 2D. Crea
cuadrados que, según los datos recibidos, cambian de tamaño,
color y transparencia.
Arduino activa patrones de luces para una tira LED. Vale la pena
mencionar que es el único de los nodos que no precisa
seccionar el string de datos relevantes, dado que se pretende
enviar únicamente como dato el número de personas en
pantalla para activar los patrones de luces.
Python de la PC2, apoyado en la biblioteca Keras y respectivos
modelos de entrenamiento pre-existentes, genera una melodía
que cambia, entre otros parámetros, la altura de las notas, en
función de los datos recibidos. Para la generación de audio
digital hace uso del protocolo MIDI y bibliotecas relacionadas
con dicho protocolo.

Componente a mi cargo:

En principio, se me asignó como tarea lograr la conexión vía Socket


entre Python-Python y Python-Processing. El desafío en sí no era
difícil, lo importante era designar en nuestro esquema qué entidades
serían servidores y cuáles serían clientes.
Tanto el código de Processing (PC1) como el código de Python de la
PC2 son de naturaleza pasiva. Es decir, no pretenden enviar datos
sino recibir (“escuchar”) y hacer algo con ellos. Por este motivo,
parecía lógico tratar como servidores dichos nodos y como cliente
(activo, una vez que empieza a levantar datos, establece conexión
con el servidor que escucha y envía) a la instancia de Python en PC1.
Quizás sea importante mencionar que se eligieron Sockets TCP, dado
que la velocidad con la que los datos se envían –que ya de por sí, son
sumamente livianos por ser sólo un string- no era relevante.
Una vez probadas funcionales ambas conexiones –a nivel local, no
interconectándome con otra computadora en la red- me tocó ver
cómo se iba a reflejar la reinterpretación de los datos recibidos por
Processing.
En origen, empecé utilizando códigos como base (es decir, códigos
no-propios) con propuestas audiovisuales sencillas pero atractivas.
Esto resultó ser sumamente complejo. Reinterpretar códigos ajenos
es una tarea que incluso puede resultar más difícil que armar uno
desde cero, ya que probablemente haya elementos que no entienda
y/o no sepa que función cumplen en el código ajeno.
Por lo tanto, a pesar de un cierto progreso, abandoné dicho
acercamiento inicial y derivé en un código propio, sin pretensiones de
lograr resultados particularmente bonitos, pero pretendiendo que sea
funcional al proyecto. En este acercamiento, fui exitoso.
Como adelanté anteriormente, el código definitivo de Processing
consistía en recibir el string con todos los datos relevantes enviados
por Python y seccionarlo para poder almacenar datos en variables
según correspondiese. Para seccionarlo, se utiliza la función Split() –
nativa de processing- que almacena en una lista los elementos
cortados en función de un caracter de escape. Dichas listas debían
ser recorridas por loops “for” para continuar el “spliteo” (ya que había
que diferenciar primero personas y luego partes del cuerpo) hasta
tener una lista para cada parte del cuerpo de una persona. Esta lista
contendría 4 elementos: índice de parte del cuerpo (ejemplo, pierna
derecha), coordenada x del punto medio, coordenada y del punto
medio y score. A estos elementos, se los podía almacenar en
variables o llamar especificando su lugar en la lista.
Con esos datos, se generan cuadrados que se trasladan en un espacio
2D (se centran en los datos (x,y) de cada parte), cambian de color –
modificando canales rgb- (según el pixel donde estuviera el centro) y
cambian su transparencia –modificando canal alpha- (en función del
score recibido).
Como resultado visual no es demasiado interesante. Sin embargo,
siempre es agradable ver algún visual “reactivo”, por más simple que
sea. Se podría decir que asemeja un poco la idea original que había
traído Yves de generar manchas de colores en el espacio en función
de la posición de la persona captada por una cámara.
Mejoras a nivel estético se pueden hacer muchas. Va en la creatividad
del programador a la hora de reinterpretar los datos y del tiempo que
puede disponer para ello. A nivel lógico (generación a partir de datos
por interconexión), el código hace lo que tiene que hacer sin
problema alguno. Agrego que su estructura “limpia” y simple (a
diferencia del primer acercamiento) lo vuelve muy maleable a la hora
de seguir implementado sobre el mismo.
Retomando lo de las conexiones por Socket, nos queda pendiente
lograr una conexión desde Python con Processing en dos máquinas
distintas (es decir, una máquina corre un software, la otra el otro). No
se pudo lograr, por lo que se resolvió correr el código de Processing
en la PC1 en simultáneo al de Python (Socket a través de interfaz de
Loopback, IP 127.0.0.1). La conexión Python-Python en computadoras
diferentes fue exitosa.

Autoevaluación del aprendizaje:


Como instancia de aprendizaje el proyecto fue sumamente valioso. El
manejo de conexión vía Socket era justamente algo que me
interesaba adquirir cuanto antes, dada su utilidad y futuro uso en la
carrera (véase, Proyecto Multimedia).
También se probó una vez más lo importante que es el diagrama de
bloques a la hora de prototipar. Es importante “tildar” todos los
mojones estructurales para después empezar a construir en base a
ellos (ej, primero lograr enviar datos de prueba entre todos los nodos,
si funciona, empezar a pensar en los datos que realmente quiero
enviar, étc).
Pese a la asignación de componentes a cargo de cada uno de los
estudiantes, traté de mantenerme lo más cercano posible a las
implementaciones de los demás compañeros. Principalmente estuve
presente en el tracker en su versión 1.0 (el detector de caras y
emociones) –viendo como Yves se iba apropiando del código,
entendiéndolo y construyendo a partir de él- y en el código de
Arduino –haciendo mis propios intentos para confirmar conexión
serial, recepción correcta de datos, confirmación de “entrada” a los
distintos voids()-. Sin duda me hubiese gustado haber estado al tanto
del código de Python de la PC2 (Federico) para introducirme más en
el Machine Learning y sus capacidades en lo que respecta a
generación de música. Lamentablemente por limitantes de tiempo no
fue posible.
También viví en primera mano lo abrumador que puede ser
reinterpretar un código ajeno, habiendo lógicas por detrás que
desconozco al no haber hecho yo mismo la infraestructura. Para
poder hacer esto de manera efectiva, considero que debería tener un
mejor manejo de la herramienta (en este caso Processing, lenguaje
que no usaba desde el año pasado y que tengo un conocimiento
superficial) y de la programación en general. Hacer un código desde
cero tiene una maleabilidad indiscutida. Uno lo escribe, uno sabe lo
que hace.
En conclusión, el proyecto sirvió, entre cosas, para mejorar mi
capacidad de programación –esto incluye conocer más a fondo
lenguajes ya introducidos previamente en la carrera como adquirir
conocimiento de programación en general-, familiarizarme con
campos de la tecnología muy interesantes que no he explorado (o
muy poco) como el Machine Learning y para vivir el armado de un
proyecto audiovisual con eje en lo informático (punto que me interesa
especialmente de Ing. Audiovisual) desde cero –y todo lo que esto
conlleva a nivel de equipo humano, recursos tecnológicos, etc-.

También podría gustarte