martes, 17 de diciembre de 2019

2006

Back then.
Si me dieran la oportunidad de regresar a 2006 pero sin saber lo que se ahora (en todos los aspectos), no lo aceptaría. El futuro (presente) sería diferente pero no necesariamente mejor ni habría disfrutado del tiempo mejor (dónde aplicaba). Este es mi argumento. Imaginen que se les da la tarea de organizar una biblioteca completa que tiene inicialmente todos los libros en desorden. Supongan que esto les toma dos años enteros. Al final, deciden crear un catálogo en donde aparece la posición correcta de cada libro en los estantes. Si enviaran ese catálogo a su yo de dos años del pasado justo antes de empezar, les tomaría quizá solo un mes ordenar todos los libros en vez de dos años. ¿Ven la idea? La información cuesta esfuerzo (sino de ustedes, de alguien más). Si amaneciéramos mañana en 2006 por una fallo en la matrix (como en la imágen que circula), estamos condenados a repetirlo todo (repetir en categorías, sería distinto por las pequeñas diferencias acumuladas [efecto mariposa] ). Suena un poco desalentador pero creo hay algo muy bueno en todo esto. Si no supimos aprovechar los buenos tiempos o no hicimos las cosas que nos hubieran hecho más felices, entonces no podemos culparnos porque la experiencia no puede crearse de la nada. Si tuvieron antes o tienen ahora las guías correctas, siéntense afortunados porque no existen los oráculos en la vida real.

nota: pueden encontrar aquí la versión formal de esta idea.

viernes, 6 de diciembre de 2019

Juego del gato (tic-tac-toe) vía algoritmo minimax.

Me dejaron el ejercicio de hacer un juego de gato y escogí el camino de la inteligencia artificial de la vieja escuela. Pensé que era algo trivial pero si me costó varios días. Planeo hacer en vacaciones un video sobre el algoritmo minimax en mi canal porque los que hay tienen códigos que ahora me parecen innecesariamente complejos. La verdad es que, aunque mis amigos creen que lo digo sólo por modestia, soy muy pendejo para entender las cosas a la primera y más aún si no me explican paso a paso. Ya que vi claro todo el proceso recursivo me acordé del final de la película War Games. Les debo el video pero por ahora pueden consultar mi reporte aquí. La implementación que hice hace uso de la siguiente clase para instanciar los estados posibles del juego:

Contiene un método que verifica si el tablero ya esta lleno y otro que verifica si es el turno del jugador X. El pseudocódigo es el siguiente:
[click para agrandar]


La función evaluación() retorna +10 si 'X' gana la partida, -10 si 'O' gana y 0 si hay empate o si aún no hay ganador en ese estado. El código completo en Python lo pueden encontrar aquí. Este programa sólo tiene el fin de ayudar a entender el algoritmo minimax. No es una implementación eficiente ya que resuelve el problema por fuerza bruta repitiendo incluso el paso por varios estados ya visitados. Pueden mejorarlo añadiendo estrategias como poda alfa-beta o memorizando estados ya visitados. 

jueves, 10 de octubre de 2019

Escrito sobre la salud mental: mi experiencia

Me parece que estamos entrando poco a poco a una buena época para la salud mental. Aún hay mucho por hacer, pero creo que para al menos mi generación, el estigma de la terapia psicológica está desapareciendo. Creo también que se está gestando una cultura de empatía, más allá del optimismo vacío tradicional. No soy un especialista pero tengo mucho que aportar con mi experiencia. Me incomoda ponerme al titulo pretencioso como "sobreviviente del desorden de ansiedad". Solo haré énfasis en que si pude salir de ese hoyo infernal y que si sé lo que se siente desear la muerte para apagar el miedo insoportable. Dicho eso también me he puesto en una posición de mucha responsabilidad. Confieso en que suelo sentirme mal  por llevar en mi saber lo necesario para cambiar la vida de tantas personas que están sufriendo pero no saber ni tener el poder para comunicarlo instantáneamente. Entiendo que es una responsabilidad distribuida porque la atención profesional es estrictamente necesaria. Pero el acompañamiento en el proceso para facilitarle las cosas a las personas es igual de necesario. Creo decir que tengo claro el método también puede dar las personas la expectativa de que daré un discurso de hombre sabio, que tendré la frase matadora que acabará de un golpe con el sufrimiento pero, por supuesto, las cosas no así. Y eso de hecho es parte central de lo que he aprendido. Esto me ha tomado varios años. Lo menciono no porque crea que este proceso debe ser necesariamente largo sino porque fui dando tumbos por la vida a prueba y error, pero juntando poco a poco los insights que terminé uniendo al final. Si pudiera enviarle una carta al pasado me habría ahorrado muchas cosas, ciertamente.

Les cuento uno. Era otoño del 2014, estaba esperado el camión una tarde en una esquina cerca del universidad en Puebla. Tenía un paraguas en medio de una llovía muy densa. No había una sola persona más en la calle. No iba ningún lugar en especial, solo trataba de despejar mi mente. Acaba de terminar una relación con una chica que había querido mucho. Me sentía terrible (esto fue dos años antes de que desorden de ansiedad me reventara en la cara). Pero de repente tuve una epifanía. Sentí de pronto que todo tenía sentido: mi dolor, la causa, el escenario. De repente me vi a mi mismo como el personaje de mi propia historia. No sentí felicidad pero era una sensación que podría llamar disfrutable. Sentía que aunque no era feliz en el sentido tradicional, mi queja no era la ausencia de contenido en mi vida. Lo que me parece interesante es que no sentí que fuera un cambio de "percepción" o una subjetiva manera diferente de tomar las cosas. Sentí como si acabara de descubrir una verdad metafísica de la realidad, algo fuera de mi de lo que había estado ciego [sidenote: quizá desde aquí me empezó a gustar el realismo literario].

Esta fue una de las muchas lecciones aisladas que años más tarde me ayudarían a sanar. 2016 fue el año en que me quebré. Si los que me leen saben el proceso entonces no aportaría demasiado en los detalles: insomnio, ataques de pánico y náuseas, etc. Dónde si lo haré es en las premisas más efectivas que encontré para salir del problema. Otra de ellas fue el entender que lo que llamamos sentirse bien es una habilidad, como saber bailar o dibujar bien. Esto no es nada evidente. Parecería que ser feliz es algo que simplemente ocurre sin mayor esfuerzo para unos pocos afortunados. La realidad es que si se tuvo la mala suerte de haber desarrollado esa habilidad (no haber tenido el ambiente correcto, la familia y amigos correctos, tenido malas experiencias, etc) se debe pasar por un proceso de desaprendizaje-aprendizaje. Creo que el error más grande que cometen los que se atascan en la terapia es suponer (en el fondo y sin hacerlo consciente) que su terapeuta un día les dirá las palabras mágicas que necesitan. Eso jamás pasará. Si entiendes verdaderamente que salir de un desorden es como aprender un nuevo idioma, ya estas del otro lado. Tercera cosa, el progreso no es una linea recta. Las recaídas son lo más normal del mundo. Vas bien. Esto me lleva a uno de los insights que más impacto tuvo en mi. Es una combinación de las tres últimas ideas más una observación extra. Durante una recaída intensa pero breve lo descubrí. Sentía de nuevo un malestar terrible, casi inmanejable por ratos. Lo mantuve a raya teniendo claro que no era nada anormal ni un retroceso y recordando que el sufrimiento es parte del contenido de mi historia personal. Pero lo que terminó destruyendo ese sentimiento de perdición fue una idea muy simple. Me dije una mañana al despertar a modo de broma. ¿Podría hoy sentirme sólo un poco menos miserable que ayer? Me di cuenta sin querer que si era posible. Sólo un poco menos que ayer, soportando el malestar sólo un poco más que ayer. Eso si era un objetivo alcanzable, nada de mierda de optimismo irracional. No diré el tiempo que tomó para no sesgar a nadie (cada quien es diferente), pero de poco en poco, así ha pasado ya mucho tiempo desde lo que fue mi última recaída y heme aquí intentando ser un profeta. No se si yo mismo hubiera seguido esta receta en mi época más oscura. Quizá sólo pude entenderlo después de todo lo que he vivido. Hay cosas que son incomunicables. Dicen los koanes del budismo que no se le puede enseñar a nadie el camino a la iluminación. Es un camino que las personas deben encontrar por su cuenta. Pero si con esto lo señalo aunque sea un poco, me doy por satisfecho.  

martes, 24 de septiembre de 2019

Luces atmosféricas

Se nombra atmosferic ghost light a un conjunto de fenómenos luminosos (la mayoría aún no explicados) que se reportan en muchas partes del mundo. Son tan relativamente comunes y la evidencia fotográfica y relatos anecdóticos son tan similares que tengo la sospecha de que se trata de procesos geofísicos que valen la pena investigar. En el caso de México, he escuchado en varios pueblos de Morelos, Guerrero y Puebla historias sobre "brujas", fantasmas de fusilados de la revolución y, por supuesto, ovnis que se aparecen volando en las cumbres de los cerros o en las entradas de las cuevas. Por un lado, mi hipótesis del origen natural de estas luces es algo que no les gusta oir a los aficionados a los ovnis o lo paranormal, y por el otro, es una propuesta de investigación que sería difícil de tomar en serio en la academia. Así que cazar estos objetos sería una aventura científica personal si lo llegara a llevar a cabo. Existen algunos vídeos en Youtube que me parecen reales, aunque me dan gracia algunos de sus títulos:
Algo muy recurrente es las historias de estos avistamientos, especialmente en los comentarios de personas que los han visto de cerca, es un ruido similar al de la estática en el radio y un olor a "estéreo quemado" [ozono]. Estas son dos características de fenómenos eléctricos de alto voltaje. Podrían tratarse de alguna forma de rayo esférico aunque no he escuchado ningún reporte durante la lluvia. Incluso en algún foro de buscadores de tesoros leí una historia de quemaduras internas [aunque la palabras que en realidad usaron fueron "hechizo de bruja"], lo que me haría sospechar de ondas estacionarias de microondas, que en principio serían requeridas para confinar un plasma esférico. Comparen el vídeo anterior con este otro:
El cerro de la Silla es mucho más alto, pero la posición relativa de las luces es similar. Si lo comparan ahora con este video de un rayo globular, comenzaran a notar también que aquí hay un patrón. La geografía de los 3 videos es muy similar. Otro lugar famoso muy similar es el Punto Marconi o "Cerro del Ovni" en Atlixco, Puebla donde también se reportan luces en las cumbres de los cerros de la zona. Probar mi hipótesis de los rayos globulares no sería sencillo. Estos fenómenos están muy ampliamente diseminados y no ocurren con tanta frecuencia. Sería muy útil tener un mapa con las etiquetas geográficas de todos los lugares en México dónde se reportan este tipo de fenómenos. Luego compararlos con los mapas de suelos y encontrar alguna correlación con las características físicas del terreno (si es zona sísmica o la abundancia de ciertos minerales en el suelo). Teniendo ese mapa, el siguiente paso sería construir una estación de instrumentación electrónica autónoma. Podría ser un módulo de bajo costo con cámara, estación meteorológica básica, con una Raspberry Pi alimentada por un banco de baterías recargadas con celdas solares y un enlace de comunicación LoRa. Con más presupuesto, un espectroscopio para tener más información sobre el proceso que genera la luz.

Si tienen curiosidad, aquí hay otras luces atmosféricas reportadas en otras partes del mundo:

domingo, 22 de septiembre de 2019

Registro de imágenes con SIFT en OpenCV

Se le llama registro al proceso de trasformación entre varios conjuntos de datos que permiten "encajar" o superponer patrones similares. Quizá el proceso más conocido sea la creación automática de fotos panorámicas a partir de varias fotos independientes. En esta entrada haremos un ejemplo más sencillo. Observen estas dos fotografías de un mismo objeto (uno de mis libros favoritos) tomadas en ángulos diferentes:
Lo que haremos sera colocar la imagen de la izquierda con la misma orientación y escala que la imagen de la derecha. Tomaremos de referencia las características comunes entre ambas imágenes (el libro principalmente). ¿Cómo encontramos estos puntos? En 2004 David Lowe publicó un algoritmo llamado SIFT (Scale-Invariant Feature Transform)  que permite encontrar puntos clave invariantes a las rotaciones y, en buena medida, a los cambios de iluminación. Los puntos clave con mejor correspondencia entre ambas imágenes se ven así:
Este algoritmo está patentado y no aparece en la instalación estándar de OpenCV. Deben seguir las instrucciones que puse en mi entrada anterior para poderlo utilizar. El código que escribí es una modificación para SIFT del código que pueden encontrar acá. Lo he reducido y comentado para mejor claridad:
La imagen final registrada es esta:

sábado, 21 de septiembre de 2019

Instalar OpenCV-Python con SIFT y SURF habilitados

Quiero ahorrarles algunas horas y frustración con esto. Estas notas están hechas para Linux (uso Debian) pero posiblemente funcione también en Windows (no lo garantizo). Voy asumir que ya tienen instalado Anaconda... Primero tienen que crear un nuevo entorno virtual (esto es por seguridad y no dañar su entorno principal de Python por si algo malo ocurre). Para crear un nuevo entorno:

$ conda create --name mi_entorno_OpenCV -y

Pueden nombrar su entrono como quieran pero es buena idea ponerle un nombre que haga referencia a su modulo. Si trabajan con IA seguramente necesitarán un nuevo para Tensorflow. Ahora, si es la primera vez que crean un entorno virtual tendrán que configurar su terminal para permitir que conda administre los entornos virtuales:

$ conda init bash

Si no usan bash debe poner la shell que utilicen. Bien, una vez que hayan hecho esto pueden activar su entorno con:

$ conda activate mi_entorno_OpenCV

Notarán que habra cambiado la etiqueta antes del promp y deberá aparecer el nombre de su entorno. Deberán instalar ahora matplotlib (su nuevo entorno solo tendrá numpy y scipy [si no, deberán instalarlos también]):

$ conda install -c conda-forge matplotlib

Spyder tampoco estará instalado en su nuevo entorno así que deberan instalarlo también:

$ conda install -c anaconda spyder

Recomiendo leer Managing enviroments de la documentación de conda. Ahora si, para instalar una versión de OpenCV que permita utilizar los algoritmos SIFT y SURF deberán instalar específicamente esta:

$ pip install opencv-contrib-python==3.4.2.16 

Listo. Terminada la instalación pueden hacer una prueba con los códigos de ejemplo de la documentación de OpenCV. Recuerden que deben mandar a llamar a Spyder desde la terminal con el entorno virtual que crearon para OpenCV. para salir del entorno utilicen:

$ conda deactivate

 En la próxima entrada pondré un ejemplo utilizando el algoritmo SIFT.

sábado, 14 de septiembre de 2019

Messidor

Si me preguntan a mí, The Durutti Column inventaron el Post-Rock en 1981 con la canción Messidor. Aparece en su segundo álbum: LC. Esta canción se adelanta casi 20 años a su época e incorpora mucha de la estructura y el estilo en las guitarras que le podemos escuchar a The Explosions in The Sky.


lunes, 15 de julio de 2019

Gráficas de Maplotlib en Tkinter

He estado aprendiendo usar el módulo TKinter para hacer interfaces gráficas en Python y me está encantando. A pesar de no tener un asistente gráfico como pyQT, se me ha hecho bastante fácil de usar. Para incrustar gráficos de Matplotlib en un GUI de Tkinter pongo el siguiente ejemplo en donde cada botón manda a graficar una función diferente:

  

martes, 9 de julio de 2019

martes, 2 de julio de 2019

Áreas, perímetros y centroides de imágenes binarias con scikit-image

Utilizando las funciones label() y regionprops() del submódulo measure de scikit-image podemos obtener varios parámetros muy útiles de regiones binarias contiguas (blobs binarios). En este ejemplo construiremos una imagen binaria con dos círculos de diferente tamaño de los cuales obtendremos sus propiedades.

Las salidas del programa son:

Región 1:
Area (pixeles): 15361
Perimetro (pixeles): 458.2741699796952
Centroide: (80.0, 100.0)


Región 2:
Area (pixeles): 7825
Perimetro (pixeles): 326.3919189857866
Centroide: (220.0, 220.0)

Es posible  construir un dataframe de pandas a partir del diccionario de propiedades generado con la función regionprops_table(). Si están comenzando con scikit-image pueden revisar mis notas de mi curso introductorio aquí.