miércoles, 31 de marzo de 2010

Debugging en Visual Studio

Después de integrar ambas librerías en nuestro IDE, se producen complicaciones cuando se intenta depurar partes de código. Al añadir breakpoints en determinadas zonas del programa, el IDE no pausa la ejecución.

Se han intentado varias opciones para conseguir que el sistema de debuging funcione correctamente, y finalmente, tras muchas vuelas he conseguido que se comporte como debe.

Como sabemos en este IDE, se configura de manera independiente las compilaciones para Release y para Debug, es decir, los directorios de inclusión, librerías y opciones de configuración son diferentes para cada una de las opciones.

Las partes importantes para que el modo debug funcionen correctamente según mi experiencia personal son:

- Es necesario que se genere el archivo de debug Microsoft Debug File (.pdb). Para ello hay que asegurarse que esta seteada la opcion de Generar Informacion de Depuracion, en la parte del Vinculador.

- Es necesario que se carguen los simbolos antes de comenzar la depuración. Para conseguirlo finalmente he incluido el servidor de Microsoft, para que el IDE descargue los simbolos a los que no tenga acceso.

- Finalmente, para conseguir que se detuviera en los breakpoints, fue necesario setear el tipo de información de depuración a la opción Base de datos de programa para Editar y continuar , y deshabilitar la parte de Optimización.

Todo esto son conclusiones a las que se llegan después de mucho googlear, leer y probar varias opciones, pero puede haber más variables que afecten al proceso de debuging.


Problemas con los 'sizers' de WxWidgets

Para definir los layouts en las interfaces creadas con Wxwidgets, se usa un concepto llamado Sizer. La idea de los sizers es de un contenedor con dimensiones y habilidades de alineamiento y expansión definidas por el usuario. Es una filosofía parecida a otros toolkits como el AWT de Java o la librería QT, que controla la disposición de los elementos de forma independiente de la plataforma.

Existen varios tipos de sizers que nos ofrece wxWidgets para darnos más libertad de movimiento, pero todos ellos heredan de la clase base wxSizer.



El problema es que al progamar la GUI a mano, como es mi caso, el tema se hace algo engorroso y lioso, ya que hay que anidar varios tipos de sizers por cada componente que añades, inicializarlos y comprobar como se comportan en operaciones de redimensión de la pantalla.

En nuestro caso, después de hacer muchas pruebas, la estrategia decidida ha sido, en primer lugar crear una estructura básica de la ventana, con los sizers correspondientes asociados a cada uno de los componentes en el constructor, y cuando seleccionamos un archivo de video, redimensionamos la ventana para que se adapte a las dimensiones originales del video, actualizamos los datos del video (alto, ancho, codec, fps ...) y reorganizamos todos los elementos de la ventana. Al final para este sencillo GUI tuve que utilizar en torno a 10 sizers
anidados ... La verdad que esta parte se ha llevado bastante tiempo.

Adjunto un video del aspecto de la aplicación en este momento:


martes, 30 de marzo de 2010

Compatibilidad Wxwidgets y OpenCV

Como primera propuesta en la linea del proyecto, sería utilizar las librerias de GUI elegidas (Wxwidgets), para desarrollar un interfaz, donde podamos mostrar un archivo de video manejado por las librerias de manejo de videos (OpenCV).

La primera aproximación del interfaz se tratara de un selector de archivo, una area para mostrar los frames del video reproducido, un conjunto de campos descriptores del video y un botón para reproducirlo. A continuación adjunto una captura de esta primera aproximación.



Para conseguir un funcionamiento correcto nos enfrentamos al primer problema. La incompatibilidad de estructuras de datos de ambas librerías.

Respecto a OpenCV y la reproducción del fichero de video, el algoritmo básico para reproducir un video sería inicializar la estructura CvCapture asociandole el fichero, recoger las propiedades del video que nos sean de utilidad, mediante la función cvGetCaptureProperty , especialmente los FPS, para mostrar los frames a una velocidad adecuada, y después ir recuperando los frames en orden (mediante cvQueryFrame()), hacer las tranformaciones necesarias si fuera necesario y mostrarlos en el lugar deseado. De forma sencilla sería algo como esto:

  1. int main( int argc, char** argv )
  2. {
  3. IplImage *frame;
  4. int key;

  5. /* supply the AVI file to play */
  6. assert( argc == 2 );

  7. /* load the AVI file */
  8. CvCapture *capture = cvCaptureFromAVI( argv[1] );

  9. /* always check */
  10. if( !capture ) return 1;

  11. /* get fps, needed to set the delay */
  12. int fps = ( int )cvGetCaptureProperty( capture,); CV_CAP_PROP_FPS

  13. /* display video */
  14. cvNamedWindow( "video", 0 );

  15. while( key != 'q' ) {
  16. /* get a frame */
  17. frame = cvQueryFrame( capture );

  18. /* always check */
  19. if( !frame ) break;

  20. /* display frame */
  21. cvShowImage( "video", frame );

  22. /* quit if user press 'q' */
  23. key = cvWaitKey( 1000 / fps );
  24. }

  25. /* free memory */
  26. cvReleaseCapture( &capture );
  27. cvDestroyWindow( "video" );

  28. return 0;
  29. }

Nuestro problema radica en que los frames se recogen en estructuras matriciales del tipo IplImage . Opencv brinda al usuario funciones básicas para la generación de GUI's básicas para hacer pruebas, recogidas en el módulo highgui , como por ejemplo cvShowImage(), que muestra un frame en una ventana básica.
En nuestro caso queremos mostrar frames en la GUI generada por wxwidgets. Las estructuras para mostrar imagenes mediante estas librerias son estructuras como wxImage o wxBitmap.

La solución consiste en recuperar la información de la estructura IplImage, en un array básico de bytes, mediante la función cvGetRawData
, y a partir de ahí crear una estructura de imagen genérica , independiente de plataforma, mediante el constructor de wxImage, a partir del array de bytes, para después convertirlo a un wxBitmap, que es representable en nuestra GUI.