miércoles, 13 de junio de 2012

JavaCV Project: Building the JAR

¿Cómo  generar el JAR para poder distribuir la aplicación? 

Tras codificar la aplicación Java + openCV + JavaCV surge esta cuestión muy importante. Lo normal para cualquier aplicación Java creada en Netbeans es hacer Run > Clean and Build Project, pero ésto no es todo lo necesario para que todo funcione bien.
En artículos anteriores se explicó cómo utilizar openCV agregando los wrappers de JavaCV para referenciar a sus funciones. Y en modo debug funciona, porque nuestra computadora tiene instalado OpenCV, pero no se ha agregado OpenCV de alguna manera directa al proyecto, sólo un modo de acceso a él.

Aquí es donde hay que rebuscárselas:

1) Copiamos los siguientes archivos en una carpeta dentro de nuestro proyecto. La llamaremos OPENCV e incluiremos los siguientes archivos en ella:

  • libopencv_calib3d.so.2.3.1
  • libopencv_contrib.so.2.3.1
  • libopencv_core.so.2.3.1
  • libopencv_features2d.so.2.3.1
  • libopencv_flann.so.2.3.1
  • libopencv_gpu.so.2.3.1
  • libopencv_highgui.so.2.3.1
  • libopencv_imgproc.so.2.3.1
  • libopencv_legacy.so.2.3.1
  • libopencv_ml.so.2.3.1
  • libopencv_objdetect.so.2.3.1
  • libopencv_video.so.2.3.1
Estos archivos, en mi caso, los encontré en /usr/lib.

2) De esta manera, al generar los JAR se incluirá esa carpeta con las Shared Libraries (.so). Pero para hacerlas funcionar, se deben extraer durante el runtime y cargarlas mediante System.load(). Para ello, primero se crea un string con las librerías a cargar. El órden debe ser el especificado, caso contrario, no funcionará:

private final static String[] libs = {
        "libopencv_core.so.2.4.1","libopencv_imgproc.so.2.4.1",
        "libopencv_flann.so.2.4.1","libopencv_features2d.so.2.4.1",
        "libopencv_calib3d.so.2.4.1","libopencv_highgui.so.2.4.1",
        "libopencv_ml.so.2.4.1","libopencv_video.so.2.4.1",
        "libopencv_objdetect.so.2.4.1","libopencv_contrib.so.2.4.1",
        "libopencv_gpu.so.2.4.1","libopencv_legacy.so.2.4.1",
        "libopencv_nonfree.so.2.4.1","libopencv_photo.so.2.4.1",
        "libopencv_stitching.so.2.4.1","libopencv_ts.so.2.4.1",
        "libopencv_videostab.so.2.4.1"};

3) Luego, se crea un constructor de clase (static initialisation block), donde se cargan por única vez las librerías nativas necesarias en un directorio temporal:

static {
        String path = "OCV_" + new Date().getTime();

        for (int i = 0; i < libs.length; i++) {
                loadLibFromJar(libs[i],path);
        }
    }

4) Por último, la función:


private static void loadLibFromJar(
        String libreriaEspecifica, String path) {
    try {

        InputStream in = frmEditor.class.getResourceAsStream(
                LIB_BIN + libreriaEspecifica);
        File fileOut = new File(System.getProperty("java.io.tmpdir") +
                "/" + path + LIB_BIN + libreriaEspecifica);
       
        OutputStream out = FileUtils.openOutputStream(fileOut);
        IOUtils.copy(in, out);
        in.close();
        out.close();
        System.load(fileOut.toString());     
       
    } catch (Exception e) {
        System.out.println("Error al cargar librería nativa: " + libreriaEspecifica +" " + e);
    }
}


6) Abrimos una terminal y escribimos:

  • cd /UbicacionElegida
  • java -jar ./TuProyecto.jar
That's all!