Traitement des images

Traitement des images

Ce tutoriel vous explique comment manipuler des BufferedImage, en appliquant des modifications sur les pixels, des convolutions, des filtres. Certains exemples sont fournis à la fin du tutoriel.

Charger une image

/* Chemin vers l'image à charger */
String pathImage = "D:\\image.jpg";

BufferedImage image;
try {
 image = ImageIO.read(new File(pathImage));
} 
catch (IOException e) {
 e.printStackTrace();
}

Enregistrer une image

try {
 ImageIO.write(image, "JPG", new File("image.jpg"));
} 
catch (IOException e) {
 e.printStackTrace();
}

Parcourir une image pixel par pixel

/* L'image à parcourir */
BufferedImage image = ImageIO.read(new File("D:\\image.jpg"))

int w = image.getWidth();
int h = image.getHeight();
for(int i=0; i<w; i++){
 for(int j=0; j<h; j++){
  /* Accéder au rgb pixel (i, j) */
  int rgb = image.getRGB(i,j);
 }
}

Récupérer la couleur d'un pixel

/* abscisse du pixel à récupérer */
int i=45;
/* ordonnée du pixel à récupérer */
int j=20;
/* L'image sur laquelle on travaille */
BufferedImage image = ImageIO.read(new File("D:\\image.jpg"))

/* Accéder au rgb pixel (i, j) */
int rgb = image.getRGB(i,j);
/* Création de la couleur associée au rgb */
Color couleur = new Color(rgb);

Modifier la couleur d'un pixel

/* abscisse du pixel à récupérer */
int i=45;
/* ordonnée du pixel à récupérer */
int j=20;
/* La couleur à affecter au pixel */
Color couleur = Color.BLUE;
/* L'image sur laquelle on travaille */
BufferedImage image = ImageIO.read(new File("D:\\image.jpg"))

/* Modification du pixel */
image.setRGB(i, j, couleur.getRGB());

Transformation affine des pixels

La classe RescaleOp permet d'appliquer une transformation affine sur les pixels d'une image.
RescaleOp(float scaleFactor, float offset, RenderingHints hints)

  • red=scaleFactor*red+offset
  • green=scaleFactor*green+offset
  • blue=scaleFactor*blue+offset

RescaleOp(float[] scaleFactor, float[] offset, RenderingHints hints)

  • red=scaleFactor[0]*red+offset[0]
  • green=scaleFactor[1]*green+offset[1]
  • blue=scaleFactor[2]*blue+offset[2]
  • alpha=scaleFactor[3]*alpha+offset[3]

Pour l'utiliser :

/* L'image sur laquelle on travaille */
BufferedImage image = ImageIO.read(new File("D:\\image.jpg"))

/* Création de la transformation */
RescaleOp rop = new RescaleOp(1.0f, 5.0f, null);

/* Application de la transformation */
BufferedImage resultat=op.filter(image, null)

Appliquer un filtre (convolution)

Qu'est ce qu'une convolution

La convolution consiste à recalculer la valeur d'un pixel donné d'une image de départ en se basant sur la valeur du pixel lui-même et sur la valeur des pixels environnants le pixel à recalculer.

Une convolutions est associée à un noyau (kernel qui est une matrice qui définit les pondérations à prendre en compte pour calculer le produit de convolution).

Le schéma suivant illustre la façon dont la valeur d'un pixel est calculée lorsqu'on applique une convolution.

  • La matrice de gauche est l'image source
  • La matrice au centre est le noyau
  • Le résultat est la valeur du pixel central

Définir une convolution

Pour définir une convolution, nous allons instancier la classe ConvoleOp en lui précisant le noyau de notre convolution : la classe Kernel nous permet de définir le noyau.

Définir le noyau

Pour définir le noyau, nous utilisons le constructeur : Kernel(int width, int height, float[] data)

  • width est le nombre de colonnes du noyau
  • height est le nombre de lignes du noyau
  • data est le tableau contenant les pondérations listées en ligne.

Par exemple, pour définir le noyau suivant :
On utilise :

new Kernel(3, 2, new float[]{1, 2, 3, 4, 5, 6})

Définition et application de la convolution

/* L'image sur laquelle on travaille */
BufferedImage image = ImageIO.read(new File("D:\\image.jpg"))

/* Définition du noyau */
Kernel kernel = new Kernel(3, 2, new float[]{1, 2, 3, 4, 5, 6};

/* Création de la convolution associée */
ConvolveOp convolution = new ConvolveOp(kernel);

/* Application de la convolution à l'image */
BufferedImage resultat=convolution.filter(image, null);

Détection du contour (Convolution de Sobel)

Le Filtre de sobel consiste à appliquer deux convolutions consécutives qui ont pour matrices :

Ce filtre permet de détecter les contours d'une image comme ceci :

import java.awt.image.BufferedImage;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;


public class Sobel {

 public static void main(String[] args) {
  BufferedImage source=null;
  try {
   source = ImageIO.read(new File("D:\\exemple.jpg"));
  }
  catch (IOException e) {
   e.printStackTrace();
  }
  
  /* Définition de la première convolution */
  Kernel kernel1 = new Kernel(3, 3, new float[]{1f, 0f, -1f, 2f, 0f, -2f, 1f, 0f, -1f});
  ConvolveOp convolution1 = new ConvolveOp(kernel1);
  BufferedImage resultatIntermediaire = convolution1.filter(source, null);
  
  /* Définition de la deuxième convolution */
  Kernel kernel2 = new Kernel(3, 3, new float[]{1f, 2f, 1f, 0f, 0f, 0f, -1f, -2f, -1f});
  ConvolveOp convolution2 = new ConvolveOp(kernel2);
  BufferedImage resultat = convolution2.filter(resultatIntermediaire, null);
  
  /* Ecriture du résultat */
  try {
   ImageIO.write(resultat, "JPG", new File("D:\\resultat.jpg"));
  } 
  catch (IOException e) {
   e.printStackTrace();
  }
 }

}

Lissage par convolution

Le lissage par convolution consiste à appliquer un filtre particulier de dimensions 5*5 qui permet d'atténuer les contours. Cette matrice est la suivante :

new float[]{ 4/1344f, 18/1344f, 19/1344f, 18/1344f, 4/1344f, 18/1344f, 80/1344f, 132/1344f, 80/1344f, 18/1344f, 29/1344f, 132/1344f, 218/1344f, 132/1344f, 29/1344f, 18/1344f, 80/1344f, 132/1344f, 80/1344f, 18/1344f, 4/1344f, 18/1344f, 29/1344f, 18/1344f, 4/1344f}

Le résultat est le suivant :

import java.awt.image.BufferedImage;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;


public class Lissage {

 public static void main(String[] args) {
  BufferedImage source=null;
  try {
   source = ImageIO.read(new File("D:\\exemple.jpg"));
  }
  catch (IOException e) {
   e.printStackTrace();
  }
  
  /* Définition de la convolution */
  Kernel kernel1 = new Kernel(5, 5, new float[]{ 4/1344f, 18/1344f, 19/1344f, 18/1344f, 4/1344f, 18/1344f, 80/1344f, 132/1344f, 80/1344f, 18/1344f, 29/1344f, 132/1344f, 218/1344f, 132/1344f, 29/1344f, 18/1344f, 80/1344f, 132/1344f, 80/1344f, 18/1344f, 4/1344f, 18/1344f, 29/1344f, 18/1344f, 4/1344f});
  ConvolveOp convolution = new ConvolveOp(kernel1);
  BufferedImage resultat = convolution.filter(source, null);
  
  /* Ecriture du résultat */
  try {
   ImageIO.write(resultat, "JPG", new File("D:\\resultat.jpg"));
  } 
  catch (IOException e) {
   e.printStackTrace();
  }
 }

}

Inversion des couleurs

Pour inverser les couleurs, on effectuer un traitement pixel par pixel :

  • red=255-red
  • green=255-green
  • blue=255-blue
import java.awt.image.BufferedImage;
import java.awt.image.RescaleOp;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;


public class InversionCouleur {

 public static void main(String[] args) {
  BufferedImage source=null;
  try {
   source = ImageIO.read(new File("D:\\exemple.jpg"));
  }
  catch (IOException e) {
   e.printStackTrace();
  }
  
  /* Définition de la transformation */
  RescaleOp op = new RescaleOp(-1.0f, 255f, null);
  BufferedImage resultat = op.filter(source, null);
  
  /* Ecriture du résultat */
  try {
   ImageIO.write(resultat, "JPG", new File("D:\\resultat.jpg"));
  } 
  catch (IOException e) {
   e.printStackTrace();
  }
 }

}

Niveaux de gris

Pour passer une image en niveau de gris, on utilise la classe ColorConvertOp :

import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.awt.image.RescaleOp;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;


public class NiveauGris {

 public static void main(String[] args) {
  BufferedImage source=null;
  try {
   source = ImageIO.read(new File("D:\\exemple.jpg"));
  }
  catch (IOException e) {
   e.printStackTrace();
  }
  
  /* Définition de la transformation */
  ColorConvertOp op = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
  BufferedImage resultat = op.filter(source, null);
  
  /* Ecriture du résultat */
  try {
   ImageIO.write(resultat, "JPG", new File("D:\\resultat.jpg"));
  } 
  catch (IOException e) {
   e.printStackTrace();
  }
 }

}

Sepia

La passage d'une image en sepia est une transformation non affine pixel par pixel, il n'existe pas de classe permettant de définir ce genre de transformation.

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;


public class Sepia {

 public static void main(String[] args) {
  BufferedImage source=null;
  try {
   source = ImageIO.read(new File("D:\\exemple.jpg"));
  }
  catch (IOException e) {
   e.printStackTrace();
  }

  int w = source.getWidth();
  int h = source.getHeight();
  for(int i=0; i<w; i++){
   for(int j=0; j<h; j++){
    Color c = new Color(source.getRGB(i, j));
    int outputRed = (int) Math.min(255, ((c.getRed() * 0.393f) + (c.getGreen() *0.769f) + (c.getBlue() * 0.189f)));
    int outputGreen = (int) Math.min(255, ((c.getRed() * 0.349f) + (c.getGreen() *0.686f) + (c.getBlue() * 0.168f)));
    int outputBlue = (int) Math.min(255, ((c.getRed() * 0.272f) + (c.getGreen() * 0.534f) + (c.getBlue() *  0.131f)));
    source.setRGB(i,j,new Color(outputRed, outputGreen, outputBlue).getRGB());
   }
  }
  
  /* Ecriture du résultat */
  try {
   ImageIO.write(source, "JPG", new File("D:\\resultat.jpg"));
  } 
  catch (IOException e) {
   e.printStackTrace();
  }
 }

}
A voir également
Ce document intitulé « Traitement des images » issu de CodeS SourceS (codes-sources.commentcamarche.net) est mis à disposition sous les termes de la licence Creative Commons. Vous pouvez copier, modifier des copies de cette page, dans les conditions fixées par la licence, tant que cette note apparaît clairement.
Rejoignez-nous