lunes, 22 de septiembre de 2014

OpenCV en java

OpenCV es una serie de librerias desarrolladas en un principio por intel para demostrar el poder de sus procesadores. Esto implicaba que solo funcionaba en procesadores de intel. Hoy en dia estas librerias son opensources y soportan diversos tipos de procesadores.


 OpenCV esta desarrolladpo en C/C++, pero afortunadamente existen wrappers (puentes o envoltorios) para diversos lenguajes. Por ello se pueden usar las librerias de OpenCV en Pyton, C#, o Java.

Setup

Para poder usar OpenCV en Java necesitamos bajar el paquete de librerias de OpenCV . En el sitio de OpenCV solo tenemos que bajar el pequete que corresponda a nuestro sistema. Este paquete pesa unos cuantos cientos de megas, así que necesitamos espacio en la computadora. En mi caso bajo un ejecutable para windows, que solo descomprime el contenido del archivo en una carpeta dada.

  Una vez que se extrajo el contenido, hay que ir a la carpeta donde se descomprimieron los datos.

  De la carpeta se requiere buscar los dll's y el jar que sirve de wrapper(usa JNI para hacer el enlace). Para poder saber que dll's son los que van a funcionar en windows, se necesita saber si nuestro sistema es de 32 o 64 bits. Esto se puede ver siguiendo estas indicaciones.

  Ya sabiendo el tipo de sistema elegimos la carpetas de donde tomaremos los dll's.

  Si es de 32 bits opencv\build\x86\
  Si es de 64 bits opencv\build\x64\


Ahi dentro debemos de ver una serie de carpetas. Estas carpetas contienen cada una los dll's, por lo que debemos de elegir la carpeta adecuada. El nombre de cada carpea se refiere a la version del compilador de C con el cual fueron creadas las librerias. Por ello se debe de elegir aquella carpeta con el compilado que pueda correr en nuestro equipo. Para saber esto, se debe de saber si contamos con algun VisualC runtime (librerias para ejecutar programas de visualC).

 Si no tenemos el runtime o no sabemos si la maquina lo tiene, podemos descargarlo de la pagina de microsoft , en esta pagina esta la ultima version y las anteriores del runtime. La carpeta que contiene los dll's es nombrada usando la siguiente norma: vcXX, donde XX corresponde a la version de las librerias de Visual C, asi de esta manera sabras cuales runtimes puedes instalar para que funcione OpenCV.

Despues de instalar el runtime o verificar la version que tenemos, entramos a la carpeta que corresponde y de ahi a la carpeta bin. En mi caso tengo sistema de 64 bits y tengo instalado el runtime de visualC version 12, Asi que mi ruta de dll's es 

opencv\build\x64\vc12\bin

Dentro vas a encontrar varias dll's, no se necesitan todas. Creo que las que tienen nombre xxxxxd.dll son para realizar debug, y no se necesitan. Ademas hay librerias especializadas en ciertas acciones que no se suelen usar y esas pueden omitirse. Pero si tenemos espacio, es preferible usar lo mas que podamos, por si en dado caso usamos alguna funcionalidad extra de OpenCV.

  Para instalar los dll's en nuestro equipo, basta con copiar los dll dentro de la carpeta Window\System32  o copiar los dll a donde va a correr el programa. Yo prefiero hacer la primera acción para evitar copiar dll's en todo proyecto que use OpenCV.

 Aparte de estos dll's, hay un dll adicional que se debe de copiar, este lo encuentras en 

opencv\build\java\x64  si tienes sistema de 64 bits
opencv\build\java\x86  si tienes sistema de 32 bits

Dentro esta un solo dll, este dll se copia en el mismo sitio donde se copiaron las otras dll's

una vez realizado esto, solo falta usar el jar que sirve de wrapper, este se encuentra en \opencv\build\java.

Netbeans setup

Para realizar el setup en netbeans se hace un proceso similar al que se realizo para registrar OpenGL, solo que el nombre de la libreria seria bueno cambiarlo a algo como OpenCV y solo usamos el jar que encontramos en \opencv\build\java.


OpenCV Hola mundo

Una vez agregada la libreria de opencv en algun proyecto (puede ser nuevo o uno ya existente, en mi caso el mismo que use para opengl).



En una clase nueva TestOpenCV, agregamos el siguiente codigo

import org.opencv.core.*;
import org.opencv.imgproc.*;
import org.opencv.ml.*;
import org.opencv.utils.*;
import org.opencv.highgui.*;
import org.opencv.objdetect.*;
import org.opencv.video.*;

public class TestOpenCV{    
    public static void main(String[] args) {
        //Preguntamos el numero de la version
        System.out.println("Bienvenido a OpenCV " + Core.VERSION);  
        //Cargamos las librerias
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        //Obtenemos mediante OpenCV el numero de cpu's
        System.out.println("Numero de CPU's: " + Core.getNumberOfCPUs());
    }    
}

Esto si realizamos lo anterior adecuadamente, nos dara como salida algo como:

Bienvenido a OpenCV X.X.X.X
Numero de CPU's: X

La X son solo para indicar algun numero. lo mas importante es que no de be de darnos error. Si vemos algo similar, en hora buena, ya esta funcionando lo basico de OpenCV. 
 

sábado, 6 de septiembre de 2014

Pruebas con JOGL-OpenGL


 Crear el Hola Mundo

  No se puede empezar a hacer algo en un nuevo programa o librería sin antes realizar el hola mundo. En caso deJOGL- OpenGL, en realidad no vamos a escribir algo, sino dibujar algo. En las paginas de tutoriales y demos sugieren empezar con el dibujo de un triángulo multicolor.

  JOGL-OpenGL funciona de forma  de una maquina de estados, es decir que es un proceso que pasar por una serie de etapas completando ciclos. Esto no pone una limitante, no podemos dibujar con JOGL-openGL cuando lo deseamos, sino que debemos de esperar al momento en que JOGL-OpenGL llega a la etapa o fase donde escribe en el buffer gráfico.

  Debido a lo anterior debemos de espera el momento oportuno para dar la indicación a JOGL-OpenGL a dibujar nuestro contenido. Para nuestra fortuna, OpenGL-JOGL nos proporciona una implementación de un listener (notificado de eventos) de las etapas que recorre OpenGL-JOGL.

Etapas o fases en JOGL



La primera etapa es inicio (init), en la cual se hace la inicialización de la libraría, realmente no se usa para el ejercicio del hola mundo y probablemente se usa para modificar la manera en como se debe de comportar OpenGL.

Las siguientes etapas son donde realmente se debe de realizar el el dibujado de los gráficos. La primera de ellas es  Display, es cuando OpenGL esta listo para dibujar en el buffer gráfico en la superficie o ventana asignada para este proposito. Le llamo buffer a aquel espacio en memoria destinado a almacenar la información gráfica que se mostrara en pantalla. Por esto, es en esta etapa cuando debemos de dibujar nuestro contenido.

La etapa de reshape (modificar), siguiere que es cuando OpenGL ha detectado alguna modificacion de la ventana o lugar donde imprime el buffer gráfico. Esta modificacion puede ser el cambio de tamaño de la ventana.

No voy entrar en detalles sobre OpenGL, ya que solo necesito que sirva para escribir un contenido grafico.

Setup


  Lo primero que se debe de hacer es ir al sitio de JOGL y descargar la version actual, archivo
(jogamp-all-platforms.7z)
Este archivo se abre con el programa 7-Zip, que se consigue gratuitamente. Dentro están contenidos librerías para diferentes sistemas operativos así como los jar que interactuán con al librerías. También existen una colección de jars que se les conoce como jars nativos. Estos jars contienen en su interior las librerías nativas para usar OpenGL.

En mi caso uso Windows y Netbeans. Después de bajar el archivo extraigo de este los archivos:

  • gluegen-rt-natives-windows-amd64.jar
  • jogl-all-natives-windows-amd64.jar
  • jogl-all.jar
  • gluegen-rt.jar
  • gluegen.jar
Las dos primeras son jars nativos con las librerías dll para interactuar con OpenGL. El resto son librerías de java que se encargan de la interacción con los jars nativos y crean la estructura de objetos java para poder trabajar con los gráficos.
Ahora se debe de registrar las librerías en Netbeans. Se da click derecho al proyecto y se selecciona Properties.

Se selecciona la sección de Libraries, y se presiona Add Library 


Aqui se presiona Create



Se le da un nombre se presiona OK

En la siguiente ventana se añaden los jars antes mencionados

Presionamos OK en las siguientes ventanas y ya tenemos registrado JOGL-OpenCV en nuestro proyecto.


Se añade un jframe al proyecto, se puede usar el nombre  y el paquete que se quiera


Añadimos un Panel y un botón

En el código, depués de la clase principal añadimos la siguiente clase interna (no es buena practica, pero, esto es solo un demo). Se deben de arreglas los import o dependencias

  
 class SimpleScene implements GLEventListener {    
   private double theta = 0.0f; // rotational angle    
   @Override   
   public void init(GLAutoDrawable drawable) {    
   }   
   @Override   
   public void dispose(GLAutoDrawable drawable) {   
   }   
 //Este metodo se ejecuta cuando OpenGL esta listo para dibujar  
   @Override   
   public void display(GLAutoDrawable drawable) {   
    update(); //Se actualiza el angulo de dibujo del triangulo  
   render(drawable); // Se dibuja el triangulo  
   }   
 //Este metodo modifica el angulo del seno y coseno, que hacen que gire el triangulo  
   private void update() {   
   theta += 0.01;   
  }   
  private void render(GLAutoDrawable drawable) {   
 // El parametro drawable que recibimos, representa el espacio de dibujo listo para usarse  
 // de drawable se obtiene GL que la representacion de OpenGL, para despues indicar la version   
 //de OpenGL que se quiere usar, esto al usar un objeto especifico a la version.   
 //Se usa la dos por tratar de abarcar una version soportada por  
 //la mayoria de las tarjetas graficas, pero si se desea se puede usar alguna otra version  
   GL2 gl = drawable.getGL().getGL2();   
   gl.glClear(GL.GL_COLOR_BUFFER_BIT); // Se limpia el espacio de dibujo   
   gl.glLoadIdentity();     // Se resetea la matriz usada para la vista de los gráficos     
   // Calculo del seno y coseno para la animacion del triangulo   
    float sine = (float)Math.sin(theta);   
    float cosine = (float)Math.cos(theta);    
   // SE empieza a dibujar el triangulo   
   gl.glBegin(GL.GL_TRIANGLES);   
   gl.glColor3f(1, 0, 0); //Esto representa el color en estilo RGB, en esta caso rojo  
   gl.glVertex2d(-cosine, -cosine); //Esta es la coordenada de una orilla de triangulo  
   gl.glColor3f(0, 1, 0); //Esto representa el color en estilo RGB, en esta caso verde  
   gl.glVertex2f(0, cosine); //segunda orilla del triangulo  
   gl.glColor3f(0, 0, 1); //Esto representa el color en estilo RGB, en esta caso azul  
   gl.glVertex2f(sine, -sine); //tercera orilla del triangulo  
   gl.glEnd(); // se termina la animacion  
  }   
   @Override   
   public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {     
   }   
  }   

La clase anterior esta preparada para interactuar con las etapas de la máquina de estado de OpenGL, por eso se usa la interface GLEventListener.  Dentro del código hay documentación sobre lo que sucede en el código.

Se crea un método para la acción de pulsado del botón.



en el método que se creo se añade el siguiente código


 private void jButton1MouseClicked(java.awt.event.MouseEvent evt) {  
 //Se obtiene el tipo de OpenGL del equipo  
 GLProfile glp = GLProfile.getDefault();  
 //Se ven las caracteristicas del openGL del equipo  
 GLCapabilities caps = new GLCapabilities(glp);  
 //Se crea un espacio para que se pueda dibujar  
 javax.media.opengl.awt.GLCanvas canvas = new javax.media.opengl.awt.GLCanvas(caps);  
 //Se añade un listener para tener interaccion con lase tapas de la máquina de estado de OpenGL  
 canvas.addGLEventListener(new SimpleScene());  
 //Se crea una rutina o animador, que hace que el espacio de dibujo se integre en la máquina de estados de OpenGL  
 //Se puede especificar con este animador cada cuando se va a dibujar algo en el espacio, de esta manera se pueden realizar animaciones  
 //canvas –lugar de dibujo, 60- son los cuadros por segundo, true – ajustar temporizador  
 FPSAnimator animator = new FPSAnimator(canvas, 60, true);  
 //Se añade el espacio de dibujo OpenGL al panel  
 this.jPanel1.add(canvas);  
 //Se ajusta el espacio al tamaño del frame  
 canvas.setBounds(0,0,this.jPanel1.getWidth(),this.jPanel1.getHeight());  
 //Se inicia la rutina de animacion  
 animator.start();  
 }  


Cuando se copia el código Netbeans nos debe de ayudar a solucionar los problemas de referencias o imports.

Despues de solucionar los problemas, solo se debe de presionar shift+F6 y debemos de ver algo como lo siguiente, donde el triangulo esta girando:


viernes, 5 de septiembre de 2014

OpenCV conce a OpenGL mediante Java

OpenCV


 Opencv en un conjunto de librerías para el manejo y procesamiento de gráficos. Esta librería esta desarrollada originalmente en C/C++, pero hay implementaciones de estas para varios lenguajes, incluyendo Java. Aunque ciertamente no es una implementación como tal, es mas bien un wraper al compilado resultante del código  de C/C++. Este wraper  en java es realizado por medio de JNI (Java Native interface)

  Enlace: OpenCv


OpenGL

  OpenGL es un conjunto de librerías que permiten una interacción con mejor desempeño hacia los dispositivos gráficos, así como manejo de entornos tridimensionales. Esto al igual que OpenCV cuanta con wrapers para diversos lenguajes. a diferencia de OpenCV, los encargados de mantener los wrapers, no son las mismas gente que desarrollan las librerías, así que no se debe de esperar una compatibilidad del 100% en esta librería. El wraper mas usado de java es JOGL, este tiene soporte hasta el momento para la versión 4.1 de openGL.

Enlaces: OpenGl

               JOGL


Trabajando con OpenCV
 
  La unidad principal de trabajo de OpenCV es la estructura llamada Mat, la cual encapsula la representación de una imagen. Cuando se maneja OpenCV en C/C++, se puede recurrir a unas ventanas existentes dentro de las librearías de OpenCV. Esta ventanas no estan presentes dentro del wraper de Java.

  La manera en que se puede visualizar la imagen contenida dentro de una estructura Mat, se debe de recurrir a la oferta gráfica dentro de Java. En esta oferta esta AWT y Swing.

  Aunque en las ultimas versiones de java se ha mejorado el rendimiento de las implementaciones de las librerías gráficas, esto aun queda algo abajo de las implementaciones hechas en C/C++. Parte del problema es la cantidad y tipo de objetos que se deben de crear y manipular. Esto hace trabajar bastante al Garbage Collector de java y por ende cause un deterioro en el desempeño.

  Una solución ideal seria extraer directamente el contenido de la imagen como un arreglo de bytes e inyectarlo directamente al buffer de video. Esto teóricamente mejoraría el desempeño de la representación gráfica de la estructura Mat dentro de java.

  El problema anterior puede ser resuelta si se aprovecha el refinamiento del manejo gráfico conseguido por las librerías de OpenGL. Lo anterior es posible debido al wraper existente para java. Próximamente estaré reportando los hallazgos realizados al integrar ambos wrapers dentro de Java.