Este pequeño ejemplo está basado en OpenCV 3.1, es sencillo y requiere, además de descargar la biblioteca, una webcam conectada a tu equipo. Es necesario señalar que la detección de rostros o de cualquier objeto no es cien por ciento preciso, tampoco debes esperar que te permita diferenciar entre distintos tipos de rostros. Lo que se logra con este ejercicio es mostrar sobre una imagen tomada de una webcam el area en la cual se ha detectado un rostro humano. Es un ejemplo interesante que seguro disfrutarás.
OpenCV
OpenCV es una biblioteca fabulosa que te facilita el trabajo si estás interesado en crear aplicaciones que requieren de reconocimiento y rastreo de objetos o rostros sobre imágenes o video en tiempo real. En Windows su instalación es sencilla y para ello debes dirigirte a la página de descarga del proyecto.Desde luego, necesitas Java y en esta ocasión usaremos Eclipse para editar y hacer funcionar el ejemplo.
- JDK 1.8 - http://www.oracle.com/technetwork/java/javase/downloads/index.html
- Eclipse NEON - https://www.eclipse.org/downloads/
- OpenCV 3.1 - http://opencv.org/downloads.html

Después de descargar y dar click en el archivo opencv-3.1.0.exe, una ventana de diálogo te preguntará donde deseas extraer OpenCV, elige la ruta que desees y recuérdala, más tarde las usaremos.

Configurar Eclipse
Suponiendo que ya conoces y tienes instalado Eclipse, debes ir al menú principal y seleccionar la opción: Window > Preferences.

A continuación vamos a crear una librería de usuario nueva. Buscamos la opción Java>Build Path>User Libraries>New.

Creamos una nueva librería de usuario y la llamamos opencv3.1 y damos enter, después seleccionamos la nueva librería y damos click en "Add External JARs...",

En la carpeta de OpenCV busca el archivo opencv\build\java\opencv-310.jar y selecciónalo.

Una vez seleccionado el archivo correcto, podrás ver que opciones nuevas aparecen. Selecciona "Native library location".

Da click en "Edit" y selecciona la carpeta "...opencv/build/java/x64". Da click en OK y terminamos.
Crear el proyecto en Eclipse
Al crear un nuevo proyecto en eclipse seleccionaremos la librería recién creada.

Puedes nombrar a tu proyecto como desees.

Antes de dar click en Finish, agregaremos la librería que creamos, dando click en Next y en la pestaña "Libraries" damos click nuevamente en la opción "Add Library...".

Elegimos la opción "User Library".

Y seleccionamos el check box de "opencv3.1".

Veremos nuestra nueva librería agregada en lista del nuevo proyecto.

El resultado será como se muestra a continuación:

Ahora el código
Debes crear una clase llamada Principal y usar el siguiente código como contenido.
import java.awt.BorderLayout; import java.awt.Color; import java.awt.Graphics; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.IOException; import javax.imageio.ImageIO; import javax.swing.JFrame; import javax.swing.JPanel; import org.opencv.core.Core; import org.opencv.core.Mat; import org.opencv.core.MatOfByte; import org.opencv.core.MatOfRect; import org.opencv.core.Point; import org.opencv.core.Rect; import org.opencv.core.Scalar; import org.opencv.imgcodecs.Imgcodecs; import org.opencv.imgproc.Imgproc; import org.opencv.objdetect.CascadeClassifier; import org.opencv.videoio.VideoCapture; class PanelDeRostros extends JPanel { private static final long serialVersionUID = 1L; private BufferedImage imagen; public PanelDeRostros() { super(); } /* * Convierte y escribe una Matriz en un objeto BufferedImage */ public boolean convierteMatABufferedImage(Mat matriz) { MatOfByte mb = new MatOfByte(); Imgcodecs.imencode("ima.jpg", matriz, mb); try { this.imagen = ImageIO.read(new ByteArrayInputStream(mb.toArray())); } catch (IOException e) { e.printStackTrace(); return false; // error } return true; // éxito } public void paintComponent(Graphics g) { super.paintComponent(g); if (this.imagen == null) return; g.drawImage(this.imagen, 10, 10, this.imagen.getWidth(), this.imagen.getHeight(), null); } } class DetectorRostros { private CascadeClassifier clasificador; public DetectorRostros() { //Se lee el archivo Haar que le permite a OpenCV detectar rostros frontales en una imagen clasificador = new CascadeClassifier("C:/Users/decodigo/Documents/opencv/sources/data/haarcascades/haarcascade_frontalface_alt.xml"); if (clasificador.empty()) { System.out.println("Error de lectura."); return; } else { System.out.println("Detector de rostros leido."); } } public Mat detecta(Mat frameDeEntrada) { Mat mRgba = new Mat(); Mat mGrey = new Mat(); MatOfRect rostros = new MatOfRect(); frameDeEntrada.copyTo(mRgba); frameDeEntrada.copyTo(mGrey); Imgproc.cvtColor(mRgba, mGrey, Imgproc.COLOR_BGR2GRAY); Imgproc.equalizeHist(mGrey, mGrey); clasificador.detectMultiScale(mGrey, rostros); System.out.println(String.format("Detectando %s rostros", rostros.toArray().length)); for (Rect rect : rostros.toArray()) { //Se dibuja un rectángulo donde se ha encontrado el rostro Imgproc.rectangle(mRgba, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height), new Scalar(255, 0, 0)); } return mRgba; } } public class Principal { public static void main(String arg[]) throws InterruptedException { // Leyendo librería nativa System.loadLibrary(Core.NATIVE_LIBRARY_NAME); // Se crea el JFrame JFrame frame = new JFrame("Detección de rostros"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); DetectorRostros detectorRostros = new DetectorRostros(); PanelDeRostros panel = new PanelDeRostros(); frame.setSize(400, 400); frame.setBackground(Color.BLUE); frame.add(panel, BorderLayout.CENTER); frame.setVisible(true); // Se crea una matriz que contendrá la imagen Mat imagenDeWebCam = new Mat(); VideoCapture webCam = new VideoCapture(0); if (webCam.isOpened()) { Thread.sleep(500); // Se interrumpe el thread para permitir que la webcam se inicialice while (true) { webCam.read(imagenDeWebCam); if (!imagenDeWebCam.empty()) { Thread.sleep(200); // Permite que la lectura se complete frame.setSize(imagenDeWebCam.width() + 40, imagenDeWebCam.height() + 60); // Invocamos la rutina de opencv que detecta rostros sobre la imagen obtenida por la webcam imagenDeWebCam = detectorRostros.detecta(imagenDeWebCam); // Muestra la imagen panel.convierteMatABufferedImage(imagenDeWebCam); panel.repaint(); } else { System.out.println("No se capturó nada"); break; } } } webCam.release(); // Se libera el recurso de la webcam } }
En este ejemplo hay varias cosas importantes que debes notar.
La primera de ellas es cuando leemos el archivo HAAR que contiene la información que usará OpenCV para detectar los rostros en la imagen. Es quizá el único cambio que tendrás que hacer en tu código, buscando el mismo archivo en tu instalación de OpenCV.
clasificador = new CascadeClassifier("C:/Users/decodigo/Documents/opencv/sources/data/haarcascades/haarcascade_frontalface_alt.xml");
En estas líneas tomamos el control de la webcam:
VideoCapture webCam = new VideoCapture(0);
El argumento que pasamos es el índice con el que está registrada la webcam internamente. Si no te funciona a la primera prueba con 1.
Después, depositamos una sola imagen en el objeto imagenDeWebCam.
webCam.read(imagenDeWebCam);
El cual leemos constantemente en un ciclo while.
Lo interesante viene en las siguientes líneas de código:
// Invocamos la rutina de opencv que detecta rostros sobre la imagen obtenida por la webcam imagenDeWebCam = detectorRostros.detecta(imagenDeWebCam); // Muestra la imagen panel.convierteMatABufferedImage(imagenDeWebCam); panel.repaint();
En la función detecta ocurren varias cosas.
public Mat detecta(Mat frameDeEntrada) { Mat mRgba = new Mat(); Mat mGrey = new Mat(); MatOfRect rostros = new MatOfRect(); frameDeEntrada.copyTo(mRgba); frameDeEntrada.copyTo(mGrey); Imgproc.cvtColor(mRgba, mGrey, Imgproc.COLOR_BGR2GRAY); Imgproc.equalizeHist(mGrey, mGrey); clasificador.detectMultiScale(mGrey, rostros); System.out.println(String.format("Detectando %s rostros", rostros.toArray().length)); for (Rect rect : rostros.toArray()) { //Se dibuja un rectángulo donde se ha encontrado el rostro Imgproc.rectangle(mRgba, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height), new Scalar(255, 0, 0)); } return mRgba; } }
Se recibe el contenido de un solo frame de la webcam, se genera una copia del mismo en RGB y en escala de grises y se deposita en las variables mRgba y mGrey. La función detectMultiScale obtiene un arreglo de posibles rostros detectados (En una sola imagen puede haber más de uno) y con la función Imgproc.rectangle(..) se dibuja un rectángulo de color azul.
Para ver lo que hace el código sólo tienes ejecutar la clase Principal.

He usado una imagen cualquiera para mostrar el resultado en pantalla.

También puedes notar que la salida de la consola muestra todos los resultados exitosos de detección.
Este método no es cien por ciento fiable, pero ahorra una gran cantidad de trabajo. Si exploras la carpeta de los archivos HAAR notarás que hay diversos archivos para detectar ojos, nariz y otras cosas más que pueden ser de utilidad para tus proyectos.
Espero que disfrutes haciendo este ejemplo.
la camara se bloque despues de un rato
Hola me podrias compartir tu archivo, ya que me sale este error
utilice opencv 3.0.0
Error: no se ha encontrado o cargado la clase principal C:\Program
Bonita explicacion…te estaria agradecido si me pudieras apoyar con ese tema
Hola, el código usado es el mismo que el del primer bloque de este post. Saludos!
Muchas gracias por compartir, queria pedirte una pequeña ayuda, que puedo agregar para recortar el rostro y guardarlo.
Hola muy buen post. Quiero saber como puedo registrarme en el sitio.
Tienes el codigo para la deteccion de ojos, nariz y boca?
este ejemplo «detecta» rostros pero no los identifica !!
Buenas Tardes, yo ejecuto este programa y siempre me sale este error.
Error de lectura.
OpenCV Error: Assertion failed (!empty()) in cv::CascadeClassifier::detectMultiScale, file C:\builds\master_PackSlaveAddon-win64-vc12-static\opencv\modules\objdetect\src\cascadedetect.cpp, line 1639
Exception in thread «main» CvException [org.opencv.core.CvException: cv::Exception: C:\builds\master_PackSlaveAddon-win64-vc12-static\opencv\modules\objdetect\src\cascadedetect.cpp:1639: error: (-215) !empty() in function cv::CascadeClassifier::detectMultiScale
]
at org.opencv.objdetect.CascadeClassifier.detectMultiScale_1(Native Method)
at org.opencv.objdetect.CascadeClassifier.detectMultiScale(CascadeClassifier.java:159)
at Principal.java.DetectorRostros.detecta(Principal.java:78)
at Principal.java.Principal.main(Principal.java:118)
Hola amigo, tengo una duda, que tipo de entrenamiento realiza tu programa, entiendo que todo algoritmo debe realizar un entrenamiento antes para proceder a realizar la detección, exactamente en que punto se realiza el entrenamiento.
Excelente post me ha servido de mucho. Gracias por el aporte.
buenas noches, de antemano gracias una pregunta ¿como podria implementar machine learning a este proyecto?
Hola muchas gracias el codigo funciono muy bien