OpenCV & JavaFX

Ya conocemos la biblioteca OpenCV y también hemos visto la API JavaFX por lo que en este tutorial aprenderemos a utilizar ambas tecnologías en conjunto, Java hace uso de la tecnología JNI (Java Native Interface) para acceder a las funciones nativas almacenadas en la librería dinámica opencv.dll.

Al descargar el instalador OpenCV 3.0 pre-construido este contiene en la carpeta opencv/build/java/ las librerías dinámicas x86/opencv_java300.dll para sistemas de 32 bits y x64/opencv_java300.dll para sistemas de 64 bits, además del archivo opencv-300.jar que contiene las interface Java necesarias para acceder a la librería.

Para los que usan su propia compilación de la librería deben asegurarse de tener activado la opción para generar el modulo java, además se requiere tener instalado: Apache Ant y Java Developer Kit (JDK), puedes conocer más sobre el proceso de compilación en el tutorial: Compilar OpenCV para Windows.

Instalación de OpenCV 3.0 en NetBeans 8.0


Lo primero que haremos será crear la aplicación JavaFX, creamos un nuevo proyecto en la categoría JavaFX elegimos JavaFX Application, de este modo:

Proyecto JavaFX OpenCV
Activamos la opción: Use Dedicated Folder for Storing Libraries, esto nos permite crear una carpeta, por defecto llamada lib, donde se almacenar los archivos de librerías, luego de presionar Finish, abrimos el proyecto y copiamos la carpeta opencv/build/java dentro de la carpeta lib. 

Create JavaFX-OpenCV Project
El siguiente paso es agregar el archivo opencv-300.jar al proyecto, lo buscamos en la carpeta que acabamos de copiar, para buscar el archivo .jar damos clic derecho sobre Libraries | Add JAR/Folder esto se encuentra en la pestaña Project de NetBeans expandiendo nuestro proyecto JavaFX.

Añadir OpenCV.jar
Para que todo funcione correctamente debemos agregar las .dll, damos clic derecho sobre el proyecto y presionamos la opción Properties, no vamos a la categoría Run, allí debemos cambiar la opción VM Options: -Djava.library.path=lib\opencv\build\java\x86 estableciendo la carpeta donde se encuentra el archivo: opencv_java300.dll seleccionamos la carpeta x86 o x64 según corresponda.

Agregar opencv.dll a java
Llego la hora de escribir código, lo primero que debemos hacer es cargar la librería nativa, usamos el código: System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

Cuando haya problemas se produce la excepción UnsatisfiedLinkError normalmente se produce por dos razones, no se encuentra el archivo opencv_java300.dll en la ruta indicada en el paso anterior o la versión del archivo no es correcta.

Si todo es correcto procedemos ha crear la GUI  JavaFX, usaremos un control ImageView para mostrar la captura de la webcam que procesaremos con el algoritmo canny para detección de bordes.

Creamos la clase CameraTask la cual crea un Task<Image>, una tarea en segundo plano que usaremos para obtener la captura de la cámara, sobre escribimos el método call para agregar esta funcionalidad.

@Override
protected Image call() throws Exception {

        // omitir si la camara no esta abierta
        if (!capture.isOpened()) {
            return null;
        }

        // obtiene la captura de la camara, lo almacena el frame
        Mat frame = new Mat();
        capture.read(frame);

        // verificar si es una captura valida
        if (!frame.empty()) {
            // procesar y convertir la imagen
            Mat dst = imgproc.apply(frame);
            return createImageFromMat(dst);
        }

        return null;
}

El objeto capture nos permite obtener el cv::Mat proveniente de la cámara, usamos el método VideoCapture.read(cv::Mat) para hacerlo, debemos indicar donde guardaremos la imagen obtenida.

Antes de mostrar la imagen en el control ImageView debemos convertir el objeto Mat a Image requerido por este control, hacemos esto con el siguiente método:

private Image createImageFromMat(Mat src) {
    MatOfByte dst = new MatOfByte();
    Imgcodecs.imencode(".bmp", src, dst);
    return new Image(new ByteArrayInputStream(dst.toArray()));
}

Para poder mostrar la secuencia de capturas de la cámara como un video fluido crearemos un ScheduledService<Image> que se encargará de ejecutar la tarea captura “CameraTask” periódicamente,  usaremos el método setPeriod(Duration) para establecer el tiempo entre cada ejecución y setOnReady() para establecer la acción que se ejecutara el finalizar cada ejecución.

// servicio que ejecutar la captura periodicamente
service = new ScheduledService<Image>() {
    @Override
    protected Task<Image> createTask() {
        // crear un CameraTask usando el VideoCapture y 
        // el metodo para procesar la imagen idicado JavaFXOpenCV.this::procesarImagen
        return new CameraTask(capture, JavaFXOpenCV.this::procesarImagen);
    }
};

// ejecutar el servicio cada 33.3 ms
service.setPeriod(Duration.millis(33.333333));

// al finalizar cada ejecucion ejecutar el metodo this::ready
service.setOnReady(this::ready);

Al crear el CameraTask debemos indicar el VideoCapture que usaremos para obtener la imagen de la cámara además de el método que procesara la misma.

private Mat procesarImagen(Mat src) {
    Mat dst = new Mat();

    Imgproc.cvtColor(src, dst, Imgproc.COLOR_BGR2GRAY);
    Imgproc.GaussianBlur(dst, dst, new Size(7, 7), 1.5, 1.5);
    Imgproc.Canny(dst, dst, 0, 30, 3, false);

    return dst;
}

Con esto terminamos nuestro tutorial OpenCV en JavaFX, es código es bastante simple pero muestra como pueden interactuar estas dos tecnologías, el resultado de esta aplicación se muestra en la siguiente captura de pantalla.  

detección de bordes opencv javafx

GitHub: Interacción entre OpenCV y JavaFX, *el repositorio Git del proyecto no incluye la librería OpenCV.

Comentarios

Temas relacionados

Entradas populares de este blog

tkinter Grid

tkinter Canvas

Controles y Contenedores JavaFX 8 - I

Conectar SQL Server con Java