Páginas

martes, 21 de diciembre de 2010

Un ejemplo curioso

Hoy mientras espero mi vuelo que lleva ya 5 horas de retraso me acabo de encontrar un ejemplo de un sistema parecido a Infant aunque basado en Kinekt lo cual lo diferencia ya que en el caso de Infant tan solo se necesitará una webcam e imagino que el proceso de reconocimiento será totalmente diferente aunque no he indagado demasiado en eso sino que he visto una demo que me ha impresionado y gustado bastante, os lo dejos a continuación:



Eso si sin duda lo mejor es el reconocimiento de voz como interfaz de usuario, que también es algo que tenía pensado y por eso me he encontrado este ejemplo en el blog de Sphinx que es un sistema libre de reconocimiento de voz con el cual espero trastear algo estas vacaciones.

sábado, 18 de diciembre de 2010

Sistema de Coordenadas de Objeto (II)

Aunque era algo ya previsto, a la hora de trabajar con la cámara con OpenCV para el reconocimiento\aprendizaje de objetos existe un problema debido a que rara vez estos se dan en una posición perfecta sino que suelen aparecer rotados o en perspectiva.

Para solventarlo y evitar que el objeto se vuelva irreconocible simplemente debido a una mala orientación se va ha cambiar el método de selección de los vectores que definen el sistema de coordenadas del objeto que hasta ahora se basaba en los vectores que conformaban el rectángulo que envolvía al objeto y que ahora pasará a basarse en el vector de mayor módulo entre todos los puntos que conforman el nivel 0, es decir el contorno más exterior del objeto. Además en caso de que haya más de un vector con un módulo similar (p.e. en objetos simétricos) para seleccionar el vector y que sea seleccionado siempre el mismo se deberá que cumpla una serie de propiedades o condiciones (como menor angulo con respecto a la horizontal, etc.)

Una vez definido este vector se tomara como eje de giro siendo el menor angulo posible para poner dicho vector en perpendicular con respecto a la horizontal con centro en el punto medio del vector. Un vez realizado este giro se seguirá con el procedimiento actual de definir el sistema de coordenadas a partir del nuevo rectángulo que rodea al objeto tal y como se hacia hasta ahora.

viernes, 10 de diciembre de 2010

Sentido de la vista

A parte de la posibilidad de cargar ficheros de imágenes, Infant permitirá obtener información y aprender a partir de lo que vea o se le enseñe si se conecta una webcam al PC.

Para facilitar esta tarea y distinguir entre lo que le enseñamos y lo que es fondo o información no relevante Infant contará con un algoritmo que analizará las zonas invariables de las diferentes capturas de la cámara creando una imagen de fondo que almacenará los valores de los pixeles que permanecen más o menos constantes a lo largo del tiempo.


Después cada una de las imágenes obtenidas se compará con esta imagen de fondo por medio de la comparación de la varianza entre los pixeles próximos de cada pixel de la imagen (con lo que se evitará en gran medida que los cambios de iluminación afecten al resultado). Para realizar esta operación de cada pixel, tanto en la imagen base con en la captura que se trata de obtener se obtendrá una matriz 3 x 3 con los siguientes valores:

donde M n,m representa el valor del pixel de la imagen original.

Finalmente las dos matrices obtenidas se restan y se obtiene una matriz final en la que si ninguna de las celdas exteriores supera un determinado valor absoluto significa que el pixel pertenece al fondo (y se actualiza la imagen de fondo con el valor del pixel de la imagen nueva) o en caso contrario es parte de un nuevo elemento en pantalla con lo que se añade a la imagen a analizar.

A continuación os dejo un video en el que podéis ver los resultados, aunque de momento solo es una prueba del algoritmo en el que en los primeros instantes se crea una imagen de fondo (todavía no he implementado el que se genere con los nuevos valores) y a continuación salgo yo haciendo el tonto y enseñándole cosas:




Por cierto, por si queréis hacer algo parecido la captura y el video han sido realizados con RecordMyDesktop.

miércoles, 8 de diciembre de 2010

Integración SQLite en C++

Como sabéis Infant, para almacenar los objetos aprendidos utilizará SQLite y siguiendo con los últimos posts de tutoriales hoy le toca el turno a la integración de SQLite en aplicaciones C\C++.

Abrir y cerrar la base de datos

En C\C++ una base de datos SQLite es manejada por el objeto sqlite3, que no es otra cosa que un puntero a la base de datos. Para abrir una base de datos cuya ruta es ruta_bd tan solo tenemos que llamar a la función sqlite3_open tal y como en el ejemplo siguiente:

sqlite3* MemoryDb;
...
if (sqlite3_open(ruta_bd, MemoryDb) != SQLITE_OK)
return -1;
} else {
return 0;
}

Por otro lado analogamente para cerrar una base de datos tan solo hay que llamar a la función sqlite3_close como por ejemplo en:

if (sqlite3_close(this->MemoryDb) == SQLITE_OK)
return 0;
else
return -1;

Consultas de lectura

Una vez abierta la base de datos si queremos realizar una consulta deberemos trabajar con un puntero al objeto sqlite3_stmt y con las funciones sqlite3_prepare_v2 para preparar la consulta que se desea realizar y sqlite3_step para ejecutarla sobre la base de datos. Además y una vez terminadas las operaciones deberemos utilizar sqlite3_finalize que libera los recursos utilizados por sqlite3_stmt.
Por otro lado si queremos obtener los datos que obtenemos de una consulta debermos utilizar las siguentes funciones según el tipo de dato leido:

  • sqlite3_column_blob
  • sqlite3_column_bytes
  • sqlite3_column_bytes16
  • sqlite3_column_double
  • sqlite3_column_int
  • sqlite3_column_int64
  • sqlite3_column_text
  • sqlite3_column_text16

Un ejemplo con con todo ello es el siguinete:


sqlite3_stmt* stmt;
if (sqlite3_prepare_v2(this->MemoryDb,"SELECT * FROM things;",-1,&stmt,NULL) == SQLITE_OK)
{
while (sqlite3_step(stmt) == SQLITE_ROW) // Mientras que se reciban filas...
{
int ID = sqlite3_column_int(stmt, 0);
string Name = string(reinterpret_cast(sqlite3_column_text(stmt, 1)));
// Convertir desde unsigned const char* a string
double AvAng = sqlite3_column_double(stmt, 2);
cout ....
}
sqlite3_finalize(stmt);
return 0;
} else {
return -1;
}

Consultas de escritura y paso de parámetros

En el caso de querer insertar o actualizar datos en una tabla SQLite desde nuestra aplicación es que ahora a la consulta en SQL (con el signo ? donde irá el parametro) deberemos pasarle parámetros con los datos que queremos insertar o modificar. Para ello la API de SQLite dispone de una serie de funciones según el tipo de dato del parámetro:
  • sqlite3_bind_blob
  • sqlite3_bind_double
  • sqlite3_bind_int
  • sqlite3_bind_int64
  • sqlite3_bind_null
  • sqlite3_bind_text
  • sqlite3_bind_text16
  • sqlite3_bind_zeroblob
Un ejemplo básico, en el que se pasan dos parametros en una consulta de insercción en una base de datos abierta es el siguiente:

sqlite3_stmt* stmt;
int id = 999;
string name = "Infant"

if (sqlite3_prepare_v2(MemoryDb, "INSERT INTO tags VALUES (?, ?);", -1,&stmt,NULL) == SQLITE_OK)
{
sqlite3_bind_int(stmt, 1, id); // Se añaden los parámetros.
sqlite3_bind_text(name.c_str(),-1,SQLITE_STATIC);
sqlite3_step(stmt); // se ejecuta
sqlite3_finalize(stmt); // y finaliza.
return 0;
}
else
{
return -1;
}

Para más información no dudeis en conslutar la API de SQLite y los tutoriales de la página web.

lunes, 6 de diciembre de 2010

Paso parámetros entre Lua y C++ : Tablas

Otra forma de pasar valores entre nuestra aplicación y un script Lua es mediante el uso de tablas. En Lua las tablas son una de las estructuras principales que define el lenguaje, de echo yo creo que todo son tablas y estas no son otra cosa que un array de pares clave - valor.
Para trabajar con tablas desde C\C++ en primer lugar hay que definir la tabla (por su nombre) y a continuación irle añadiendo los valores con los que valla a trabajar el script sobre dicha tabla. Un ejemplo de estos dos pasos serían las siguientes líneas:

lua_State *L = lua_open();
luaL_openlibs(L);

// Se crea una tabla nueva.
lua_newtable(L);

// Se establece el elemento cuya clave es 1 el valor 45.56
lua_pushnumber( L, 1 );
lua_pushnumber( L, 45.56 );
lua_rawset( L, -3 ); // Escribe el valor

// Se establece el elemento "2" cuyo valor el 99.99
lua_pushnumber( L, 2 );
lua_pushnumber( L, 99.99 );
lua_rawset( L, -3 );


// Se añade a las variable globales (que por cierto es la tabla G_) la nueva tabla llamada "infant"
lua_setglobal( L, "infant" );

// ... aqui llamada al script y otras operaciones...

// Se cierra Lua.
lua_close(L);

Como veis no es nada complicado y es por ello que va ha ser la forma de pasar argumentos entre Infant y Lua contenido en nuestro caso dicha tabla la definición de los diferentes niveles y vectores que componen cada nivel.
Un ejemplo de script que podría hacer uso de estos valores pasados a Lua es el siguiente en el que se escriben todos los valores que contiene la tabla "infant"


for i=0,table.getn(infant) do
print(i,infnat[i])
end

viernes, 3 de diciembre de 2010

Paso parámetros entre Lua y C++ : Variables globales

Como os prometí hace unos días os he preparado un pequeño tutorial de como integrar Lua en C\C++ y pasar argumentos entre ambos.

Bien lo primero que tenéis que hacer el instalar Lua en vuestro sistema. Una vez hecho esto y si habeis configurado vuestro entorno de desarrollo lo mejor es probar si lo habies hecho bien y para ello os recomiendo que hagais una prueba compilando el siguiente codigo:

extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}


int main()
{
lua_State *LS = lua_open();
luaL_dofile(LS,"hello_name.lua");
lua_close(LS);
}



En el que como podeis ver importamos todas las cabeceras de la API de Lua y a continuación se crea un puntero a una estructura lua_State que sirve como base para cuaquier otra función con la que queramos trabajar. Después se abre el interprete, ejecutamos un script (que tan solo sacara por pantalla un hola mundo) y cerramos nuevamente el interprete.

Como podeís ver es un proces bastante simple, pero, ¿y si queremos que los scripts que tenemos en Lua se comuniquen con la aplicación y\o viceversa? Para ello la API dispone de varias funciones que agilizan estas tareas. En primer lugar y la forma más rapida y sencilla es por medio de variables globales que generamos en nuestra aplicación y que luego utiliza el script en Lua y cuyo contenido puede ser accedido tanto en el script como en la aplicación. Un ejemplo de ello sería el siguiente:

int main()
{
lua_State *L = lua_open();
// Establecemos la variable global "name" y le asiganmos un valor
lua_setglobal(L, "name");
lua_pushstring(L, "Project Infnat");
luaL_dofile(L,"hello_name.lua");
lua_close(L);
}


Para usar esta variable en el script deberemos saber que el script requiere de ella ya que para su utilización se accede a una variable con el mismo nombre que la que se a creado en el codigfo en C. Un sript en Lua que hace uso de esta sería:

io.write("Hello ", name,"\n")

Si, solo esta linea. En caso de querer modificar esta variable en el script y obtener los resultado suponiendo que se alamacenaran en esa variable tan solo tenemos que hacer una llamada a la función lua_getglobal como en el ejemplo:

lua_getglobal(L, "name");
string ret_name = "";
if (lua_isstring(L, -1)) {
ret_name = lua_tostring(L, -1));
printf(ret_name.c_str());
}


Donde -1 es el orden de llamada a la variable con la funcion lua_getglobal(...) y tal y como podeis ver en la API en el caso de los diferentes tipos de variables llamariamos a diferentes funciones segun el tipo.