Introduction à OpenCV avec Java

1. Introduction

Dans ce didacticiel, nous allons apprendre à installer et utiliser la bibliothèque de vision par ordinateur OpenCV et à l'appliquer à la détection des visages en temps réel.

2. Installation

Pour utiliser la bibliothèque OpenCV dans notre projet, nous devons ajouter la dépendance opencv Maven à notre pom.xml :

 org.openpnp opencv 3.4.2-0 

Pour les utilisateurs de Gradle, nous devrons ajouter la dépendance à notre fichier build.gradle :

compile group: 'org.openpnp', name: 'opencv', version: '3.4.2-0'

Après avoir ajouté la bibliothèque à nos dépendances, nous pouvons utiliser les fonctionnalités fournies par OpenCV.

3. Utilisation de la bibliothèque

Pour commencer à utiliser OpenCV, nous devons initialiser la bibliothèque , ce que nous pouvons faire dans notre méthode principale :

OpenCV.loadShared();

OpenCV est une classe qui contient des méthodes liées au chargement des packages natifs requis par la bibliothèque OpenCV pour diverses plates-formes et architectures.

Il convient de noter que la documentation fait les choses légèrement différemment:

System.loadLibrary(Core.NATIVE_LIBRARY_NAME)

Ces deux appels de méthode chargeront en fait les bibliothèques natives requises.

La différence ici est que ce dernier nécessite l'installation des bibliothèques natives . Le premier, cependant, peut installer les bibliothèques dans un dossier temporaire si elles ne sont pas disponibles sur une machine donnée. En raison de cette différence, la méthode loadShared est généralement la meilleure solution .

Maintenant que nous avons initialisé la bibliothèque, voyons ce que nous pouvons en faire.

4. Chargement des images

Pour commencer, chargeons l'exemple d'image à partir du disque en utilisant OpenCV :

public static Mat loadImage(String imagePath) { Imgcodecs imageCodecs = new Imgcodecs(); return imageCodecs.imread(imagePath); }

Cette méthode chargera l'image donnée en tant qu'objet Mat , qui est une représentation matricielle.

Pour enregistrer l'image précédemment chargée, nous pouvons utiliser la méthode imwrite () de la classe Imgcodecs :

public static void saveImage(Mat imageMatrix, String targetPath) { Imgcodecs imgcodecs = new Imgcodecs(); imgcodecs.imwrite(targetPath, imageMatrix); }

5. Classificateur Haar Cascade

Avant de plonger dans la reconnaissance faciale, comprenons les concepts de base qui rendent cela possible.

En termes simples, un classificateur est un programme qui cherche à placer une nouvelle observation dans un groupe dépendant de l'expérience passée. Les classificateurs en cascade cherchent à faire cela en utilisant une concaténation de plusieurs classificateurs. Chaque classificateur suivant utilise la sortie du précédent comme information supplémentaire, améliorant considérablement la classification.

5.1. Caractéristiques de Haar

La détection de visage dans OpenCV est effectuée par des classificateurs en cascade basés sur des fonctionnalités Haar.

Les fonctionnalités Haar sont des filtres utilisés pour détecter les contours et les lignes sur l'image. Les filtres sont vus comme des carrés avec des couleurs noir et blanc:

Ces filtres sont appliqués plusieurs fois à une image, pixel par pixel, et le résultat est collecté sous la forme d'une valeur unique. Cette valeur est la différence entre la somme des pixels sous le carré noir et la somme des pixels sous le carré blanc.

6. Détection de visage

Généralement, le classificateur en cascade doit être pré-formé pour pouvoir détecter quoi que ce soit.

Étant donné que le processus de formation peut être long et nécessiterait un grand ensemble de données, nous allons utiliser l'un des modèles pré-formés proposés par OpenCV. Nous placerons ce fichier XML dans notre dossier de ressources pour un accès facile.

Passons en revue le processus de détection d'un visage:

Nous tenterons de détecter le visage en le délimitant avec un rectangle rouge.

Pour commencer, nous devons charger l'image au format Mat à partir de notre chemin source:

Mat loadedImage = loadImage(sourceImagePath);

Then, we'll declare a MatOfRect object to store the faces we find:

MatOfRect facesDetected = new MatOfRect();

Next, we need to initialize the CascadeClassifier to do the recognition:

CascadeClassifier cascadeClassifier = new CascadeClassifier(); int minFaceSize = Math.round(loadedImage.rows() * 0.1f); cascadeClassifier.load("./src/main/resources/haarcascades/haarcascade_frontalface_alt.xml"); cascadeClassifier.detectMultiScale(loadedImage, facesDetected, 1.1, 3, Objdetect.CASCADE_SCALE_IMAGE, new Size(minFaceSize, minFaceSize), new Size() );

Above, the parameter 1.1 denotes the scale factor we want to use, specifying how much the image size is reduced at each image scale. The next parameter, 3, is minNeighbors. This is the number of neighbors a candidate rectangle should have in order to retain it.

Finally, we'll loop through the faces and save the result:

Rect[] facesArray = facesDetected.toArray(); for(Rect face : facesArray) { Imgproc.rectangle(loadedImage, face.tl(), face.br(), new Scalar(0, 0, 255), 3); } saveImage(loadedImage, targetImagePath);

When we input our source image, we should now receive the output image with all the faces marked with a red rectangle:

7. Accessing the Camera Using OpenCV

So far, we've seen how to perform face detection on loaded images. But most of the time, we want to do it in real-time. To be able to do that, we need to access the camera.

However, to be able to show an image from a camera, we need a few additional things, apart from the obvious — a camera. To show the images, we'll use JavaFX.

Since we'll be using an ImageView to display the pictures our camera has taken, we need a way to translate an OpenCV Mat to a JavaFX Image:

public Image mat2Img(Mat mat) { MatOfByte bytes = new MatOfByte(); Imgcodecs.imencode("img", mat, bytes); InputStream inputStream = new ByteArrayInputStream(bytes.toArray()); return new Image(inputStream); }

Here, we are converting our Mat into bytes, and then converting the bytes into an Image object.

We'll start by streaming the camera view to a JavaFX Stage.

Now, let's initialize the library using the loadShared method:

OpenCV.loadShared();

Next, we'll create the stage with a VideoCapture and an ImageView to display the Image:

VideoCapture capture = new VideoCapture(0); ImageView imageView = new ImageView(); HBox hbox = new HBox(imageView); Scene scene = new Scene(hbox); stage.setScene(scene); stage.show();

Here, 0 is the ID of the camera we want to use. We also need to create an AnimationTimerto handle setting the image:

new AnimationTimer() { @Override public void handle(long l) { imageView.setImage(getCapture()); } }.start();

Finally, our getCapture method handles converting the Mat to an Image:

public Image getCapture() { Mat mat = new Mat(); capture.read(mat); return mat2Img(mat); }

The application should now create a window and then live-stream the view from the camera to the imageView window.

8. Real-Time Face Detection

Finally, we can connect all the dots to create an application that detects a face in real-time.

The code from the previous section is responsible for grabbing the image from the camera and displaying it to the user. Now, all we have to do is to process the grabbed images before showing them on screen by using our CascadeClassifier class.

Let's simply modify our getCapture method to also perform face detection:

public Image getCaptureWithFaceDetection() { Mat mat = new Mat(); capture.read(mat); Mat haarClassifiedImg = detectFace(mat); return mat2Img(haarClassifiedImg); }

Now, if we run our application, the face should be marked with the red rectangle.

We can also see a disadvantage of the cascade classifiers. If we turn our face too much in any direction, then the red rectangle disappears. This is because we've used a specific classifier that was trained only to detect the front of the face.

9. Résumé

Dans ce didacticiel, nous avons appris à utiliser OpenCV en Java.

Nous avons utilisé un classificateur en cascade pré-formé pour détecter les visages sur les images. Avec l'aide de JavaFX, nous avons réussi à faire en sorte que les classificateurs détectent les visages en temps réel avec des images d'une caméra.

Comme toujours, tous les exemples de code peuvent être trouvés sur GitHub.