|
|
Line 8: |
Line 8: |
| == OpenCV == | | == OpenCV == |
| | | |
− | Si se desea profundizar en OpenCV hay varias fuentes de donde obtener información. Una de ellas es el libro [http://www.amazon.com/Learning-OpenCV-Computer-Vision-Library/dp/0596516134/ref=sr_1_1?ie=UTF8&qid=1299591736&sr=8-1 ''Learning OpenCV: Computer Vision with the OpenCV Library''] escrito por Gary Bradski y Adrian Kaehler y publicado por la editorial O'Really. En la página web de OpenCV, [http://opencv.willowgarage.com/wiki/ WillowGarage], también existe abundante información para quienes no dispongan del libro en cuestión. Y en la Red hay numerosa información relacionada con el uso de la biblioteca, que si bien puede estar más o menos desperdigada, también supone una buena fuente de consulta. Por último, los ejemplos que se incluyen en la biblioteca también son una fuente de informacación utilísima. En el desarrollo de este trabajo se han utilizado todas estas fuentes en mayor o menor medida. | + | Si se desea profundizar en OpenCV hay varias fuentes de donde obtener información. Una de ellas es el libro [http://www.amazon.com/Learning-OpenCV-Computer-Vision-Library/dp/0596516134/ref=sr_1_1?ie=UTF8&qid=1299591736&sr=8-1 ''Learning OpenCV: Computer Vision with the OpenCV Library''] escrito por Gary Bradski y Adrian Kaehler y publicado por la editorial O'Really. En la página web de OpenCV, [http://opencv.willowgarage.com/wiki/ WillowGarage], también existe abundante información para quienes no dispongan del libro en cuestión. Y en la Red hay numerosa información relacionada con el uso de la biblioteca, que si bien puede estar más o menos desperdigada, también supone una buena fuente de consulta. Por último, los ejemplos que se incluyen en la biblioteca también son una fuente de informacación utilísima. En el desarrollo de este trabajo se han utilizado todas estas fuentes en mayor o menor medida [[más]]. |
− | | |
− | === Instalación de la biblioteca ===
| |
− | | |
− | Para realizar la instalación de cualquier aplicación o biblioteca en GNU/Linux lo más cómodo suele ser utilizar los paquetes correspondientes. Los usuarios de Ubuntu pueden usar '''Synaptic''' (''Sistema/Administración/Gestor de paquetes Synaptic'') que es la interfaz gráfica por defecto en estos momentos para gestionar los paquetes, aunque también se puede instalar desde la línea de comandos de un terminal:
| |
− | | |
− | <geshi lang=Bash lines=0>~$ sudo aptitude install libcv4 libhighgui4 libcvaux4 libcv-dev libhighgui-dev libcvaux-dev opencv-doc</geshi>
| |
− | | |
− | Los tres primeros paquetes corresponden a la biblioteca propiamente dicha, por tanto son imprescindibles. Los tres siguientes con el sufijo ''-dev'' son los ficheros de desarrollo que también los necesitaremos si queremos desarrollar aplicaciones con esta biblioteca. El último paquete contiene programas de ejemplo y documentación sobre OpenCV y aunque no es imprescindible para trabajar, sí que es recomendable como fuente de consulta. Si se quiere contar con la última versión de las bibliotecas se puede realizar una instalación manual de las mismas a partir de sus fuentes siguiendo el proceso descrito para tal fin en [http://opencv.willowgarage.com/wiki/InstallGuide WillowGarage].
| |
− | | |
− | === Operaciones básicas ===
| |
− | | |
− | Una vez que tenemos preparado el sistema con todo el software necesario, es el momento de la primera toma de contacto con OpenCV. Este apartado no pretende ser un tutorial completo y exhaustivo sobre cada una de las funciones que posee OpenCV si no más bien un sendero abierto que conduce directamente hacia el objetivo principal de este trabajo. Y lo mejor es comenzar poco a poco de manera que nuestra primera incursión sea lo menos traumática posible. Por tanto, los primeros programas que vamos a desarrollar consistirán en una serie de operaciones básicas que conviene aprender bien al principio pues serán imprescindibles para el desarrollo de la aplicación.
| |
− | | |
− | Las primeras operaciones que se realizarán serán mostrar una imagen y un vídeo que están guardados en el disco duro e interceptar el flujo de vídeo de una cámara para mostrarlo en pantalla.
| |
− | | |
− | ==== Mostrar una imagen en pantalla ====
| |
− | | |
− | El siguiente código nos muestra en pantalla la imagen que recibe como argumento en la línea de comandos.
| |
− | | |
− | <geshi lang=C lines=0>#include "highgui.h"
| |
− |
| |
− | int main(int argc, char* argv[])
| |
− | {
| |
− | | |
− | IplImage *img = cvLoadImage(argv[1]); // Carga la imagen en memoria.
| |
− | | |
− | cvNamedWindow("imagen", CV_WINDOW_AUTOSIZE); // Crea la ventana donde mostrar la imagen
| |
− | cvShowImage("imagen", img); // Muestra la imagen en la ventana.
| |
− | | |
− | cvWaitKey(0); // Espera que se pulse una tecla.
| |
− | | |
− | cvReleaseImage( &img ); // Retira la imagen de la ventana.
| |
− | cvDestroyWindow("imagen"); // Libera la memoria.
| |
− | | |
− | return 0;
| |
− | }</geshi>
| |
− | | |
− | Si guardamos este código con el nombre ''ejemplo_01.c'' y lo compilamos con g++ de la forma:
| |
− | | |
− | <geshi lang=Bash lines=0>~$ g++ -o ejemplo_01 ejemplo_01.c -Wall -I /usr/include/opencv -L /usr/lib -lm -lhighgui</geshi>
| |
− | | |
− | deberíamos poder obtener un fichero que ejecutaríamos mediante la orden
| |
− | | |
− | <geshi lang=Bash lines=0>~$./ejemplo_01 mi-imagen.xxx</geshi>
| |
− | | |
− | siendo ''mi-imagen.xxx'' el nombre del fichero con la imagen que queremos mostrar. OpenCV soporta formatos de imagen del tipo JPEG, BMP, PNG, PGM y TIFF entre otros. Si todo ha ido bien, se debería ver la ventana creada con la imagen en su interior. Si pulsamos una tecla, la ventana se cierra y finaliza el programa.
| |
− | | |
− | El código del ejemplo está bien comentado y apenas necesita explicación. Cada vez que se necesite mostrar una imagen en pantalla con OpenCV, el procedimiento será siempre el mismo, tal y como se ve en el ejemplo:
| |
− | | |
− | *Se creará una variable de tipo ''IplImage'' que guardará la imagen en forma de matriz de puntos y se indicará a la biblioteca que la cargue en memoria mediante la orden ''cvLoadImage''.
| |
− | *Se creará la ventana donde se va a visualizar la imagen. Esto siempre es necesario, siempre hará falta un soporte sobre el que colocar las imágenes. En todo lenguaje de programación que incluya interfaces gráficas es necesario un contenedor donde se ponen o colocan los demás componentes de la interfaz y OpenCV no es una excepción.
| |
− | *Se pedirá a la librería que muestre la imagen dentro de la ventana correspondiente mediante la orden ''cvShowImage''.
| |
− | | |
− | Una vez que ya no se necesite la imagen, será necesario liberar el espacio de memoria que ocupó la imagen para evitar saturarla. Esta operación se realiza mediante las órdenes ''cvReleaseImage'' que elimina la imagen de la ventana que la soporta y ''cvDestroyWindow'' que elimina de la memoria del equipo la ventana que contenía a la imagen mostrada.
| |
− | | |
− | En el ejemplo anterior se podría comprobar que se ha dado el nombre/ruta de una imagen como argumento en la línea de comandos antes de cargar la imagen para no producir un error en tiempo de ejecución. También se podría comprobar que la operación de carga de la imagen ha tenido éxito --o no-- mediante la adición de código extra, pero se ha preferido evitar esto para mantener el ejemplo lo más simple y claro posible para su mejor entendimiento.
| |
− | | |
− | ==== Abrir un archivo de vídeo ====
| |
− | | |
− | En el siguiente ejemplo se tratará de abrir un archivo de vídeo almacenado en el disco duro del ordenador para que pueda ser visualizado en pantalla.
| |
− | | |
− | <geshi lang=C lines=0>#include "highgui.h"
| |
− |
| |
− | int main(int argc, char* argv[])
| |
− | {
| |
− | cvNamedWindow("ventana_video", CV_WINDOW_AUTOSIZE);
| |
− | CvCapture* flujo_video = cvCreateFileCapture(argv[1]);
| |
− | IplImage *fotograma;
| |
− | | |
− | while(1){
| |
− | fotograma = cvQueryFrame(flujo_video);
| |
− | if (!fotograma) break;
| |
− | cvShowImage("ventana_video", fotograma);
| |
− | | |
− | char c = cvWaitKey(33);
| |
− | if(c == 27) break;
| |
− | }
| |
− | | |
− | cvReleaseCapture( &flujo_video );
| |
− | cvReleaseImage( &fotograma );
| |
− | cvDestroyWindow("ventana_video");
| |
− | | |
− | return 0;
| |
− | }</geshi>
| |
− | | |
− | En este ejemplo las cosas se hacen de forma ligeramente diferente a como se hacen en el anterior, por lo que merece la pena comentar estas diferencias. Una vez se ha creado la ventana contenedor para el vídeo con la orden ''cvNamedWindow'', se crea una estructura que almacenará el fichero mediante la orden ''cvCreateFileCapture''. Puesto que el vídeo es una sucesión de imágenes mostradas de forma contínua, necesitaremos acceder a cada una de esas imágenes para poder ir mostrándolas en pantalla. Para esto necesitamos crear otra variable, que llamaremos ''fotograma'', que será la encargada de ir tomando de una en una las imágenes contenidas en el fichero de vídeo.
| |
− | | |
− | En el bucle infinito creado con la orden ''while(1)'' se realizan las siguientes operaciones:
| |
− | | |
− | * Se toma un fotograma del fichero de vídeo mediante la orden ''cvQueryFrame'', que permite un acceso secuencial a cualquier flujo de vídeo tanto si está almacenado en un fichero como si proviene de una cámara.
| |
− | | |
− | * Se comprueba si se ha podido tomar el fotograma, en caso contrario se abandona el bucle --se ha producido un error debido, por ejemplo, a un fichero corrupto--.
| |
− | | |
− | * Se muestra el fotograma en la ventana creada al principio del programa de forma similar a como se hizo en el ejemplo anterior.
| |
− | | |
− | * Se esperan 33 milisegundos para comprobar la pulsación de una tecla y si esta tecla corresponde a la de ''ESC'' se abandona el bucle. En caso contrario se vuelve al comienzo del bucle.
| |
− | | |
− | * El programa finaliza liberando la memoria ocupada por las variables creadas al principio para la gestión del fichero de vídeo.
| |
− | | |
− | Dos cosas hacen diferente a este ejemplo del anterior: el bucle que permite ir tomando una tras otra las imágenes almacenadas en el fichero de vídeo y que es necesario para mostrar todas las imágenes del vídeo, y el valor de 33 milisegundos que recibe la orden ''cvWaitKey''. Si este valor es cero, el programa esperará a que se pulse una tecla para mostrar el siguiente fotograma. Valores diferentes de cero hacen que el sistema espere esa cantidad de tiempo especificada antes de continuar con la siguiente instrucción.
| |
− | | |
− | Un apunte más sobre el manejo de ficheros de vídeo con OpenCV. Si bien el formato de vídeo por defecto que maneja OpenCV es el AVI, también se pueden abrir ficheros de otro tipo siempre que el sistema tenga instalados los codec adecuados. En caso contrario, el programa lanzará un error relacionado con el tipo de fichero que intenta abrir.
| |
− | | |
− | ==== Capturar vídeo de una cámara ====
| |
− | | |
− | En el ejemplo que sigue se muestra en pantalla el flujo de vídeo proviniente de una cámara de vídeo o de un fichero dependiendo de si en la línea de comandos del terminal se llama al programa con un argumento o no --el argumento será el nombre del fichero de vídeo a mostrar--.
| |
− | | |
− | <geshi lang=C lines=0>#include "highgui.h"
| |
− |
| |
− | int main(int argc, char* argv[])
| |
− | {
| |
− | CvCapture* flujo_video;
| |
− | cvNamedWindow("ventana_video", CV_WINDOW_AUTOSIZE);
| |
− | IplImage *fotograma;
| |
− | | |
− | if(argc == 1){
| |
− | flujo_video = cvCreateCameraCapture(0);
| |
− | }
| |
− | else {
| |
− | flujo_video = cvCreateFileCapture(argv[1]);
| |
− | }
| |
− | assert(flujo_video != NULL);
| |
− | | |
− | while(1){
| |
− | fotograma = cvQueryFrame(flujo_video);
| |
− | if (!fotograma) break;
| |
− | cvShowImage("ventana_video", fotograma);
| |
− | | |
− | char c = cvWaitKey(33);
| |
− | if(c == 27) break;
| |
− | }
| |
− | | |
− | cvReleaseCapture( &flujo_video );
| |
− | cvReleaseImage( &fotograma );
| |
− | cvDestroyWindow("ventana_video");
| |
− | | |
− | return 0;
| |
− | }</geshi>
| |
− | | |
− | Como comentarios al ejemplo se mencionará que el código es similar al anterior excepto por la condición en la que se toma como fuente del flujo o bien la salida de la cámara conectada al sistema o bien el fichero de argumento. Esto es muy bueno para el programador porque le da libertad absoluta para decidir cuál será la entrada de vídeo que quiere usar sin complicar el resto del código, ya que es la propia biblioteca la que se encarga de todo el ''trabajo sucio'' relacionado con la gestión del fichero o la cámara.
| |
− | | |
− | El valor cero que recibe la orden o función ''cvCrateCameraCapture'' como argumento corresponde a la fuente u origen del flujo de vídeo. Normalmente cuando sólo se tiene una cámara en el sistema es suficiente con dar el valor cero que corresponde a la constante CV_CAP_ANY de los ficheros de cabecera de OpenCV. De esta manera se consigue que el programa realice una autodetección del driver necesario para la captura. Otros valores interesantes podrían ser CV_CAP_V4L y CAP_VAL_V4L2 que corresponden al controlador de vídeo compatible con sistemas ''Video for Linux'' --vídeo nativo de GNU/Linux-- y que equivalen ambas al valor numérico 200, o el valor CV_CAP_FIREWIRE --valor numérico 300-- que correspondería a una cámara de tipo firewire. En el fichero de cabecera ''highgui.h'' se relacionan todos los valores de drivers soportados. Según el libro ''Learning OpenCV'' si queremos que el programa nos pregunte qué tipo de cámara vamos a utilizar bastará con poner un -1 como argumento de la función de captura, aunque esto sólo estaría disponible para usuarios de Windows ya que no se ha conseguido durante las pruebas del código en Ubuntu.
| |
− | | |
− | Como comentario final sólo se añadirá que la línea ''assert(flujo_video != NULL)'' es una simple comprobación de que se ha podido o abrir el fichero o enlazar con la cámara. Es una comprobación útil y muy recomendable pues se podría dar el caso de que un determinado driver de cámara o códec de vídeo no estuviesen instalados en el sistema lo que produciría un error en la ejecución de nuestro programa.
| |
− | | |
− | ==== Guardar vídeo en un fichero ====
| |
− | | |
− | Si lo que se necesita es guardar el flujo de vídeo procedente de una cámara en el disco duro, lo mejor es utilizar un código similar al que se muestra a continuación.
| |
− | | |
− | <geshi lang=C lines=0># include "cv.h"
| |
− | # include "highgui.h"
| |
− | # include "stdio.h"
| |
− | | |
− | int main(int argc, char* argv[]) {
| |
− | CvCapture* flujo_video_entrada = cvCreateCameraCapture(0);
| |
− | | |
− | if (!flujo_video_entrada) {
| |
− | printf("No puedo acceder a la cámara");
| |
− | return 0;
| |
− | }
| |
− | IplImage* fotograma = cvQueryFrame(flujo_video_entrada);
| |
− | | |
− | CvSize imgSize = cvSize(
| |
− | (int)cvGetCaptureProperty(flujo_video_entrada, CV_CAP_PROP_FRAME_WIDTH),
| |
− | (int)cvGetCaptureProperty(flujo_video_entrada, CV_CAP_PROP_FRAME_HEIGHT)
| |
− | ); // Dimensiones del fotograma
| |
− | | |
− | CvVideoWriter *flujo_video_salida = cvCreateVideoWriter(
| |
− | "flujo_salida.avi", CV_FOURCC('M','J','P','G'), 24, imgSize);
| |
− | | |
− | for (;;) {
| |
− | //Get a frame from the input video.
| |
− | fotograma = cvQueryFrame(flujo_video_entrada);
| |
− | cvWriteFrame(flujo_video_salida, fotograma);
| |
− | }
| |
− | cvReleaseVideoWriter(&flujo_video_salida);
| |
− | cvReleaseCapture(&flujo_video_entrada);
| |
− |
| |
− | return 0;
| |
− | }</geshi>
| |
− | | |
− | Las partes más importantes de este código son la correspondiente a la función ''cvCreateVideoWriter'' y el interior del bucle ''for''. La función ''cvCreateVideoWriter'' nos permite escribir en el fichero especificado --en este caso ''flujo_salida.avi''-- con la codificación o códec MJPG todas las imágenes recogidas de la cámara detectada en el sistema a una tasa de 24 fotogramas por segundo. Las dimensiones de cada fotograma vienen definidas por el valor de ''imgSize'', que se obtiene mediante los valores ''CV_CAP_PROP_FRAME_WIDTH'' y ''CV_CAP_PROP_FRAME_HEIGHT'' --en el fichero de cabecera highgui.h se pueden ver el resto de las propiedades disponibles del fotograma--.
| |
− | | |
− | Dentro del bucle ''for'' se produce la escritura propiamente dicha del fichero de vídeo mediante la función ''cvWriteFrame''. Esta función escribe en el fichero que se le da como primer argumento la imagen o fotograma a la que se acaba de acceder desde la cámara del sistema. La actuación combinada de ambas funciones, ''cvCreateVideoWriter'' y ''cvWriteFrame'', permiten en primer lugar, reservar espacio en la memoria del sistema para almacenar el vídeo y en segundo lugar, volcarlo al disco duro.
| |
− | | |
− | Si en lugar de utilizar la cámara del sistema como fuente del flujo de vídeo se utilizase otro fichero de vídeo, modificando el código de manera adecuada se podría conseguir un convertidor de formatos de vídeo. Como argumentos de la línea de comandos se podrían utilizar el nombre del fichero fuente y el del fichero destino incluida su extensión. Convendría recordar que el cambio de formato de vídeo depende de los códec que haya instalados en el sistema. Pretender convertir o guardar un fichero en un formato que no tiene los códecs instalados producirá un error de ejecución. Si en el valor del códec se utiliza un -1 --CV_FOURCC(-1)-- el sistema pedirá que se seleccione uno de entre varios mostrados, pero sólo es sistemas Windows.
| |
− | | |
− | Se deja también propuesta la posibilidad de visualizar el vídeo de la cámara mientras se realiza la captura ya que en este ejemplo, como se habrá podido comprobar, se ha omitido esta posibilidad intencionadamente.
| |
− | | |
− | === Eventos de teclado y ratón ===
| |
− | | |
− | Las interacciones del usuario con la aplicación que se jecuta son algo imprescindible en un programa. En este subapartado se mostrará la manera de realizar cambios en el comportamiento del programa a través de la pulsación de teclas o de los botones del ratón. También se verá cómo mostrar información relacionada con el programa sobreimpresa en las ventanas de vídeo. El ejemplo que se muestra a continuación realiza todas las acciones mencionadas.
| |
− | | |
− | <geshi lang=C lines=0>#include "cv.h"
| |
− | #include "highgui.h"
| |
− | #include "stdio.h"
| |
− | #include "string.h"
| |
− | | |
− | CvFont fuente;
| |
− | CvCapture* flujo_video;
| |
− | IplImage* fotograma;
| |
− | char ventana[] = "prueba";
| |
− | int coord_x, coord_y;
| |
− | char boton[100] = "Pulsado Boton ---", tmp[256];
| |
− | | |
− | void mouseHandler(int event, int x, int y, int flags, void *param)
| |
− | {
| |
− | switch(event) {
| |
− | /* boton izquierdo pulsado */
| |
− | case CV_EVENT_LBUTTONDOWN:
| |
− | strcpy(boton, "Pulsado Boton Izquierdo");
| |
− | break;
| |
− | /* boton derecho pulsado */
| |
− | case CV_EVENT_RBUTTONDOWN:
| |
− | strcpy(boton, "Pulsado Boton Derecho");
| |
− | break;
| |
− | /* movimiento del puntero del raton */
| |
− | case CV_EVENT_MOUSEMOVE:
| |
− | coord_x = x;
| |
− | coord_y = y;
| |
− | break;
| |
− | }
| |
− | }
| |
− | | |
− | int main()
| |
− | {
| |
− | char pos_x[256], pos_y[256];
| |
− | flujo_video = cvCaptureFromCAM(CV_CAP_ANY);
| |
− | int color_b = 255, offset = 15, tecla;
| |
− | | |
− | if( !flujo_video )
| |
− | {
| |
− | fprintf(stderr, "ERROR: fallo en la captura\n");
| |
− | getchar();
| |
− | return -1;
| |
− | }
| |
− | cvNamedWindow(ventana, CV_WINDOW_AUTOSIZE);
| |
− | cvInitFont(&fuente, CV_FONT_HERSHEY_SIMPLEX, 1.0, 1.0, 0, 1, CV_AA);
| |
− | | |
− | printf( "Teclas rapidas: \n"
| |
− | "\tESC - sale del programa\n"
| |
− | "\tc - cambia color de cursor de azul a negro\n"
| |
− | "\tt - cambia tamaño de cursor de 15 a 30\n");
| |
− | | |
− | while(1)
| |
− | {
| |
− | strcpy(pos_x, "X = ");
| |
− | strcpy(pos_y, "Y = ");
| |
− | fotograma = cvQueryFrame(flujo_video);
| |
− | if(!fotograma)
| |
− | {
| |
− | fprintf(stderr, "ERROR: no hay fotogramas...\n");
| |
− | getchar();
| |
− | break;
| |
− | }
| |
− | cvSetMouseCallback( ventana, mouseHandler, NULL );
| |
− | cvPutText(fotograma, boton, cvPoint(10, 80), &fuente, cvScalar(0, 255, 0, 0));
| |
− | | |
− | sprintf(tmp, "%d", coord_x);
| |
− | cvPutText(fotograma, strcat(pos_x, tmp), cvPoint(10, 400), &fuente, cvScalar(0, 0, 255, 0));
| |
− | | |
− | sprintf(tmp, "%d", coord_y);
| |
− | cvPutText(fotograma, strcat(pos_y, tmp), cvPoint(10, 440), &fuente, cvScalar(0, 0, 255, 0));
| |
− | | |
− | cvRectangle(fotograma, cvPoint(coord_x - offset, coord_y - offset),
| |
− | cvPoint(coord_x + offset, coord_y + offset), cvScalar(color_b, 0, 0, 0), 2, 5, 0);
| |
− | | |
− | tecla = cvWaitKey(10);
| |
− | if(tecla == 27)
| |
− | break;
| |
− | switch( tecla )
| |
− | {
| |
− | case 't':
| |
− | if (offset == 15)
| |
− | offset = 30;
| |
− | else
| |
− | offset = 15;
| |
− | break;
| |
− | case 'c':
| |
− | if (color_b == 255)
| |
− | color_b = 0;
| |
− | else
| |
− | color_b = 255;
| |
− | break;
| |
− | default:
| |
− | break;
| |
− | }
| |
− | cvShowImage(ventana, fotograma);
| |
− | }
| |
− | cvReleaseCapture(&flujo_video);
| |
− | cvDestroyWindow(ventana);
| |
− | return 0;
| |
− | }</geshi>
| |
− | | |
− | Las partes más interesantes de este ejemplo corresponden al código de la función ''mouseHandler'' y al interior del bucle ''while''. Este ejemplo muestra en pantalla la captura de flujo de vídeo realizada a través de la cámara por defecto del sistema y sobreimpresiona las coordenadas en las que se encuentra el cursor del ratón en la esquina inferior izquierda. En la esquina superior izquierda se imprimirá un mensaje indicando el botón que se ha pulsado del ratón y el puntero del mismo se mostrará como un cuadrado de color azul que cambiará de tamaño si se pulsa la tecla ''t'' o de color si se pulsa la tecla ''c''. La pulsación de ''ESC'' nos permitirá abandonar el programa.
| |
− | | |
− | En la función ''mouseHandler'', invocada mediante la retrollamada ''cvSetMouseCallback'', se realiza la comprobación de la pulsación de los botones de ratón a través de la variable ''event'' que recibe como argumento. El fichero de cabecera ''highgui.h'' contiene la lista de todos los eventos de ratón que pueden ser capturados mediante la retrollamada, por lo que no se describirán en este trabajo.
| |
− | | |
− | Otra de las partes de que consta la función de retrollamada es la correspondiente a los valores de las coordenadas de la ventana activa en las que tiene lugar el evento. Estos valores se recogen y devuelven en las variables argumento ''x'' e ''y'' de la función. Con ellos se puede actualizar la posición del puntero del ratón en todo momento mientras se desplaza por la ventana. El argumento correspondiente al valor ''flags'' permite gestionar la pulsación simultánea de otras teclas del teclado como pueden ser SHIFT, CONTROL, etc..., y el valor ''param'' sirve para pasar argumentos extra a la función que no estén comprendidos en los parámetros anteriores. En este trabajo no se necesitará por lo que no se explicará su uso.
| |
− | | |
− | Dentro del bucle ''while'' tienen lugar una serie de operaciones que merece la pena comentar. La primera está relaccionada con el texto que se sobreimpresiona en la pantalla activa. La función ''cvPutText'' se encarga de ello. Esta función recibe como argumentos la imagen en la que se va a imprimir el texto, que puede ser estática como la de un fichero JPG o puede cambiar de forma contínua como ocurre con las imágenes que provienen del flujo de vídeo en el ejemplo. El segundo argumento corresponde a una cadena de caracteres que es el texto que se desea mostrar en pantalla. El texto a mostrar se puede manipular previamente mediante el uso de las funciones de cadena contenidas en la biblioteca de funciones estandar de C, como es nuestro caso. El tercer argumento que recibe la función es la posición en la que va a ser mostrado el texto. El punto tiene que ser del tipo ''cvPoint'' --no vale simplemente con introducir las coordenadas--. El origen de coordenadas para los puntos es el (0, 0) que corresponde a la esquina superior izquierda de la ventana activa.
| |
− | | |
− | El tipo de fuente que se va a usar en el texto se especifica con el valor ''fuente'', que tiene que ser del tipo ''CvFont''. Este argumento necesita ser inicializado primero antes de ser usado y la forma de realizar esto es mediante la función ''cvInitFont''. Esta función utiliza como primer argumento el tipo de fuente. El listado de todos los tipos de fuente figura en el fichero de cabecera ''highgui.h''. Los argumentos 2 y 3 corresponden a la escala horizontal y vertical de la fuente. Estos argumentos sólo pueden tomar dos valores, ''1.0'' ó ''0.5''. El cuerto argumento permite escribir el texto en itálica para valores mayores de cero y menores de uno --el máximo valor 1 correspondería a una inclinación del texto de 45 grados--. Los dos últimos argumentos ofrecen la posibilidad de especificar el grosor del texto --negrita-- y el tipo de la línea. La cabecera ''cxcore.h'' contiene más información relacionada con las funciones de texto. El color de la fuente se especifica en el último parámetro de la función ''cvPutText'', concretamente con los tres primeros valores que siguen a ''cvScalar'', que corresponden a los valores BGR del color.
| |
− | | |
− | Para dibujar el puntero del ratón se utiliza la función ''cvRectangle''. Esta función recibe como argumentos la imagen sobre la que se va a dibujar el cuadrado, las posiciones de las esquinas superior izquierda e inferior derecha del cuadrado --que gracias al uso de la variable entera ''offset'' podemos cambiar su tamaño desde el teclado--, el color de los lados del cuadrado --especificados por los valores que encierra ''cvScalar'' entre paréntesis-- y el grosor de los lados del cuadrado. Si este valor es cero o negativo, el cuadrado (o rectángulo) dibujado aparecerá relleno. El valor 5 del ejemplo, que figura a continuación del 2 que define el grosor de las líneas, corresponde al tipo de línea a utilizar en el rectángulo. En el fichero de cabecera ''cxcore.h'' se puede encontrar más información relacionada con esta función.
| |
− | | |
− | Para finalizar este apartado se mencionará que la gestión de las pulsaciones de teclas se realiza mediante la función de OpenCV ''cvWaitKey'' ya vista anteriormente, por lo que no se realizará ningún comentario adicional de la misma. El código dentro de la sentencia condicional ''swtich'' es muy claro y no debería necesitar explicación alguna.
| |
| | | |
| == Segmentación de imagen == | | == Segmentación de imagen == |
El trabajo que aquí se va a presentar trata sobre la aplicación del robot ROVIO de la empresa Wowwee Technologies a tareas de vigilancia. Para ello se utilizará la biblioteca de visión artificial OpenCV, que será la encargada de procesar la información proviniente de la cámara wifi de ROVIO en un ordenador portátil. Como sistema operativo de base para el desarrollo de esta aplicación se utilizará GNU/Linux, en concreto la distribución Ubuntu Lucid. La aplicación será desarrollada enteramente en lenguaje C.
Pendiente de redacción...
Si se desea profundizar en OpenCV hay varias fuentes de donde obtener información. Una de ellas es el libro Learning OpenCV: Computer Vision with the OpenCV Library escrito por Gary Bradski y Adrian Kaehler y publicado por la editorial O'Really. En la página web de OpenCV, WillowGarage, también existe abundante información para quienes no dispongan del libro en cuestión. Y en la Red hay numerosa información relacionada con el uso de la biblioteca, que si bien puede estar más o menos desperdigada, también supone una buena fuente de consulta. Por último, los ejemplos que se incluyen en la biblioteca también son una fuente de informacación utilísima. En el desarrollo de este trabajo se han utilizado todas estas fuentes en mayor o menor medida más.
El procesamiento de imagen digital suele comprender varios pasos intermedios antes de tener una imagen útil con la que el robot pueda realizar algún tipo de acción. Este procesamiento es necesario porque la cantidad de información proviniente de una imagen tomada desde una cámara es enorme y significaría una carga en la cpu de nuestro robot innecesaria ( seguir leyendo).
Los datos que se muestran a continuación no están basados en ninguna especificación oficial porque no hay ninguna publicada, si no que están recogidos y ordenados de varios sitios web dedicados a ROVIO o a temas relacionados con él, principalmente de Device Guru y RoboComunity. Se añaden al cuerpo del trabajo como anexo porque se considera que podrían ser interesantes de cara a una potencial y futura modificación o hackeo de ROVIO, de manera que su manejo y configuración se pueda realizar de forma completamente independiente de la plataforma software que se utilice.