lunes, 4 de agosto de 2014

El diablo con peor vista del mundo

Qué encontrarás en esta entrada?
  • Reconocimiento (AMATEUR) de imágenes por MATLAB.
  • Integración con BASH de Linux.

Siguiendo en la línea de mis últimas entradas, estoy mejorando mi sistema de comunicación con mi ordenador a través del móvil. Los que seáis lectores habituales de la página, recordaréis la reciente entrada "Comunicación ordenada", en la que hablaba de cómo redirigir CenterIM (un programa de mensajería instantánea en línea de comandos) para que respondiera un "contestador automático", que realmente era un script en shell de Linux. De esta manera, y según lo que le mandases a tu ordenador vía Hangouts, él "te respondía" atendiendo a las directrices de dicho script.

Comentaba entonces que esto abría infinitas posibilidades. Por ejemplo, podemos colocar una webcam, instalarnos Motion para la detección del movimiento, y poder controlarlo desde nuestro móvil y que nos mande avisos si alguien entra en nuestra casa.

Una de las cosas que más me gusta de programar en shell es la facilidad que hay para integrarlo con otros programas que corran desde Linux. Se me ocurrió hacer un sistema de detección de imágenes basado en octave (la versión libre análoga a MATLAB), y eso es lo que os voy a contar hoy.

Antes de nada: no os hagáis muchas ilusiones. Esto es un juego en vías de desarrollo basado en ideas muy simples que sólo pretende ilustrar las posibilidades que se abren para la gente con interés en el tema.

En primer lugar, os muestro cómo ve mi ordenador.


De lujo, ¿verdad? Estáis viendo mi habitación con la luz apagada... bueno, dicho así suena un poco estúpido, pero desarrollaré la idea a continuación.

Maravillosa y nítida imagen de mi habitación a oscuras

Tengo una webcam situada en una posición fija de mi cuarto. El objetivo es que sepa diferenciar distintas situaciones y, para ello, no me importa si cambian sutilmente un número determinado de píxeles. Lo que quiero es que reconozca patrones de una manera fácil.

En una primera fase me he centrado en las condiciones de luz y en la apertura de mi puerta. Al cambiar las condiciones de luz, varían las sombras, y al abrir o cerrar la puerta, interfiere la luz que proviene del exterior. En teoría esto debería dejar unos patrones más o menos estándar.

¿Qué hago para crear el patrón? "Repixelado e indexado". Como he comentado antes, no me interesa la variación pixel por pixel, sino por zonas. Mi primera idea ha sido unir varios píxeles en lo que podríamos llamar "macro-píxeles", los cuales tendrían la luminosidad media de los píxeles que se encuentran en su interior. La segunda idea, ha sido normalizar el color a tres estados: negro (para las zonas con luminosidad baja), blanco (para las de luminosidad alta) y gris (para las de luminosidad media). Con esto mi intención es facilitar el análisis de coincidencias por comparación directa con una imagen modelo.

celda=32;    % Tamaño de la celda.
[I,J,K]=size(IMG);
% Valores límite:
media=mean(mean(mean(IMG)));
maxim=max(max(max(IMG)));
minim=min(min(min(IMG)));
% Indexando y repixelado:
i=1;
for ni=1:(I/celda)
    j=1;
    for nj=1:(J/celda)
        IMGrp(ni,nj)=mean(mean(mean(IMG(i:i+(celda-1),j:j+(celda-1),1:3))));
        % Indexado:
        if IMGrp(ni,nj) < mean([minim,media])
            IMGrp(ni,nj)=0;
        else
            if IMGrp(ni,nj) > mean([media,maxim])
                IMGrp(ni,nj)=255;
            else
                IMGrp(ni,nj)=127;
            end
        end
        j=j+celda;
    end
    i=i+celda;
end

La siguiente parte es la toma de imágenes modelo. Una vez tomadas, se capta la imagen "muestra" y se la somete al mismo tratamiento (monocromatizado + repixelado + indexado), comparándola a continuación, "macro-pixel" a "macro-pixel", hasta obtener unos "coeficientes de similaridad" según coincidan con las imágenes modelo.


En principio, la que mayor coeficiente de similaridad tenga, representa la respuesta correcta.

Patrón que da la puerta de mi cuarto abierta con la habitación apagada

Una vez programado en octave, desde bash sólo habría que llamarlo de la siguiente forma:

echo "comando_de_matlab" | octave

De esta manera hemos unido octave con shell. A través de CenterIM, unimos shell con nuestro móvil y... voilà! Podemos recibir en nuestro móvil información procesada con octave y, en mi caso, retransmitida por el siempre carismático Diablo Fumado.


Como en otras tantas ocasiones, las posibilidades son infinitas. ¿Cuál es la vuestra?


ACTUALIZACIÓN (05/08/2014)

Creo que en la entrada que escribí ayer me quedé un poco corto de ejemplos y me gustaría que vierais de forma más dinámica cómo funciona el programa. Los siguientes ejemplos son muestras reales del amanecer de esta mañana en mi casa. Las fotos, y su posterior análisis, se han realizado mediante una orden que he dado yo desde mi móvil mientras estaba de camino al trabajo.

Caso #1: Habitación en oscuridad total (6:19am).

La imagen real y la simplificada fueron las siguientes:


Se ve que, pese a la oscuridad casi total, la cámara presenta un efecto parecido al viñeteo, pero a la inversa: los bordes son más claros que el centro. En la imagen original yo diría que es imperceptible, pero al transformarla en un patrón, tomando como referencia los máximos y mínimos de una imagen en la cuál ambos son casi iguales (e iguales a cero), se acentúa el contraste apareciendo este efecto.

Y a 30 km de distancia, en mi móvil (además de la foto), pudo leerse:


Caso #2: Habitación en penumbra (7:16am).

Las imágenes:


Ahora, la imagen simplificada no muestra una tendencia a la simetría radial como en el caso anterior. Con mayor cantidad de luz, los defectos en la captura homogénea de la cámara se hacen más irrelevantes y aparecen las primeras áreas de sombra y penumbra, definiendo zonas diferenciadas entre sí. Nótese que la caja blanca es con mucha diferencia el objeto que más luz está reflejando de la habitación a estas horas, y por tanto es también la única zona que queda clasificada como "luces altas" (color blanco).

La respuesta que recibo es la siguiente:


Caso #3: Habitación iluminada (7:35am).

Las imágenes:


Las paredes blancas, en contacto con la luz del sol entrante, empiezan a reflejar y a adquirir relevancia en la imagen. Las zonas negras se reducen y el patrón obtenido es más luminoso.

La respuesta que me llega:


Bueno, tres de tres, no ha estado mal, aunque aún necesita un poco de entrenamiento.


ACTUALIZACIÓN (07/08/2014)

Sigo entrenando al Diablo Fumado para que vea correctamente y me comunique sus conclusiones por Hangouts y correo electrónico. Para ello, he aumentado la resolución (reducido el tamaño de la celda del repixelado) y completado la paleta de colores (ahora uso un blanco, un negro, y dos grises medios). Pero sobre todo, lo que estoy aumentando es el número de imágenes (o "situaciones") con las que estoy comparando. Actualmente tengo definidos 14 escenarios posibles. Con todo ello, ya se empiezan a ver algunos resultados interesantes.


Parece que distingue correctamente entre los distintos estados de iluminación, diferenciando la luz natural de la artificial, y empieza a acertar también en lo que respecta a la situación de la puerta (cosa que desde el principio le ha costado). Seguiré trabajando en ello...

No hay comentarios:

Publicar un comentario

Querido astarothista!,

Si te ha gustado la entrada y quieres dejar constancia de ello, tienes alguna sugerencia para completarla o corregirla, quieres mostrar tu opinión respecto a algo de lo que se haya hablado en esta entrada (con respeto) o simplemente quieres dejarme un mensaje a mi o a la comunidad, no dudes en comentar ;)!

Recuerda que también estamos en Facebook y en Google+.