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.
/* Chemin vers l'image à charger */ String pathImage = "D:\\image.jpg"; BufferedImage image; try { image = ImageIO.read(new File(pathImage)); } catch (IOException e) { e.printStackTrace(); }
try { ImageIO.write(image, "JPG", new File("image.jpg")); } catch (IOException e) { e.printStackTrace(); }
/* 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); } }
/* 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);
/* 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());
La classe RescaleOp permet d'appliquer une transformation affine sur les pixels d'une image.
RescaleOp(float scaleFactor, float offset, RenderingHints hints)
RescaleOp(float[] scaleFactor, float[] offset, RenderingHints hints)
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)
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.
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.
Pour définir le noyau, nous utilisons le constructeur : Kernel(int width, int height, float[] data)
Par exemple, pour définir le noyau suivant :
On utilise :
new Kernel(3, 2, new float[]{1, 2, 3, 4, 5, 6})
/* 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);
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(); } } }
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}
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(); } } }
Pour inverser les couleurs, on effectuer un traitement pixel par pixel :
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(); } } }
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(); } } }
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(); } } }