OpenCV4Android Detección de Objetos

Luego de haber creado nuestra primera aplicación Android OpenCV vamos a introducir conceptos un poco más avanzados y funcionales, en este tutorial aprenderemos a usar los clasificadores en cascada XML para detectar un objeto de nuestro interés, en este caso utilizaremos uno los clasificadores pre-entrenados que se incluyen en el SDK pero puedes entrenar tu propio clasificador que que detecte cualquier objeto que desees.

OpenCV4Android-Detector-Objetos

El primer paso será crear nuestro proyecto y añadirle el SDK de OpenCV tal como lo hicimos en el tutorial anterior, puedes verlo en: Creación de proyecto OpenCV Android.

Una vez tengamos preparado nuestro proyecto añadiremos un componente JavaCameraView que nos permitirá visualizar la captura de la cámara, a diferencia del ejemplo anterior esta vez lo añadiremos directamente a nuestra Activity, veamos el código:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    
    // solicitar permisos para utilizar la camara
    requestPermissions(new String[]{ Manifest.permission.CAMERA }, 1);

    // crear el componente que muestra la captura de la camara
    cameraView = new JavaCameraView(this, CameraBridgeViewBase.CAMERA_ID_FRONT);
    cameraView.setVisibility(SurfaceView.VISIBLE);
    cameraView.setCvCameraViewListener(this);
    cameraView.enableFpsMeter();

    // añadir el componente a la actividad
    setContentView(cameraView);
}

El siguiente cambio que haremos con respecto a la versión anterior será el método usado para cargar la librería, esta vez utilizaremos la clase OpenCVLoader diseñada para tal propósito.

@Override
protected void onResume() {
    super.onResume();

    Log.i(TAG, "Cargando librería .so incluida en proyecto...");
    if (!OpenCVLoader.initDebug()) {

        Log.i(TAG, "Cargando librería con OpenCV Manager...");
        OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_0_0, this, ocvLoaderCallback);

    } else {
        ocvLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);
    }
}

Usando el método initDebug() inicializamos la librería de manera estática, esto es similar a lo que hicimos anteriormente recordemos que debemos tener la carpeta jniLibs con los archivos .so correspondientes a la arquitectura de CPU para la cual destinamos la aplicación.

añadir opencv lib .so

Debemos saber que este método esta diseñado solo para propósitos de desarrollo y pruebas, cuando nuestra app este lista debemos usar initAsync() la cual inicializa la librería de manera asíncrona, además no requiere que incluyamos los archivos .so en nuestra app lo que reduce su tamaño.

Este método hace uso de una aplicación externa llamada OpenCV Manager para administrar la librería nativa, si no la tienes instalada al momento de ejecutar se te pedirá hacerlo, puedes instalarla desde la tienda o desde los archivos .apk incluidos en el OpenCV4Android SDK se encuentran en la carpeta apk, recuerda instalar el adecuado a tu arquitectura.

Instalar OpenCV Manager

Al utilizar OpenCVLoader.initAsync() debemos indicar un callback, este recibirá la notificación de si se ha podido o no cargar la librería nativa, si todo está correcto aprovechamos para inicializar nuestro clasificador en cascada y habilitar la vista, de este modo:

private BaseLoaderCallback ocvLoaderCallback = new BaseLoaderCallback(this) {
        @Override
        public void onManagerConnected(int status) {
            switch (status) {
                case LoaderCallbackInterface.SUCCESS:

                    Log.i(TAG, "Carga de OpenCV correcta...");
                    cameraView.enableView();

                    String path = CascadeHelper.generateXmlPath(this.mAppContext, R.raw.haarcascade_frontalface_alt2);

                    if (path != null) {
                        detector = new CascadeClassifier(path);

                        if (!detector.empty()) {
                            Log.i(TAG, "Cargar clasificador .xml, archivo: " + path);
                        }
                    }

                    break;
                default:
                    super.onManagerConnected(status);
                    break;
            }
        }
};

Antes que nada debemos tener el archivo XML del clasificador en la carpeta /res/raw/ de nuestro proyecto, para este ejemplo vamos a probar con el clasificado HAAR entrenado para detectar rostros o caras frontales, puedes probar con cualquier otro.

Agregar clasificador en cascada .xml

Para cargar y utilizar el clasificador usamos la clase CascadeClassifier debemos indicarle la ruta en donde se encuentra el respectivo archivo *.xml para este propósito usamos la clase CascadeHelper y su método generateXmlPath(), este se encarga de tomar el archivo indicado y copiarlo en un archivo temporal, luego se devuelve la ruta a este archivo.

Con esto tenemos todo preparado, ahora podemos agregar nuestro código OpenCV para detectar y mostrar los resultados en la pantalla, vemos como se hace:

@Override
public Mat onCameraFrame(Mat src) {

        // convertir a escala de grices y luego ecualizar histograma
        Imgproc.cvtColor(src, gray, Imgproc.COLOR_BGR2GRAY);
        Imgproc.equalizeHist(gray, gray);

        // detectar los objetos presentes en la imagen de entrada
        MatOfRect faces = new MatOfRect();
        if (detector != null && !detector.empty()) {
            detector.detectMultiScale(gray, faces, 1.1, 2, 2, new Size(200, 200), new Size());
        }

        // dibujar un rectangulo sobre los objetos encontrado en el paso anterior
        for (Rect rc : faces.toList()) {
            Imgproc.rectangle(src, rc.tl(), rc.br(), new Scalar(0, 255, 0));
        }
 
        return src;
}

Puedes tener más detalles sobre la detección de rostros con OpenCV en el presente enlace, el lenguaje de programación no es Java pero la teoría es la misma, también puede ver como entrenar un clasificador en cascada para crear tu propio clasificador XML.

Recordemos que nuestra actividad debe implementar la interface CvCameraViewListener, el método mostrado arriba proviene de esta interface, el mismo recibe el objeto Mat que representa la imagen capturada por la cámara, la procesa y devuelve el resultado.

También debemos recordar que nuestro manifiesto debe contener los permisos para poder utilizar la cámara del dispositivo.

Descargar código: OpenCV4Android-Detector-Objetos.zip

Comentarios

Publicar un comentario

Temas relacionados

Entradas populares de este blog

tkinter Grid

tkinter Canvas

Histogramas OpenCV Python

Conectar SQL Server con Java