Traitement d`images en Java

publicité
Traitement d'images en Java
par Mohamed Slim (slim_java)
Date de publication : 03 juillet 2010
Dernière mise à jour :
Cet article est destiné aux développeurs Java qui souhaitent écrire des applications
permettant de faire du traitement d'images en Java avec l'API Java 2D.
Pour comprendre les notions présentées dans cet article, une connaissance préalable de
l'API SWING est un minimum requis.
Traitement d'images en Java par Mohamed Slim (slim_java)
I - Introduction..............................................................................................................................................................3
I-A - Image numérique........................................................................................................................................... 3
I-A-1 - Image vectorielle................................................................................................................................... 3
I-A-2 - Image matricielle................................................................................................................................... 3
I-B - Traitement d'images....................................................................................................................................... 4
II - Traitement d'images en Java.................................................................................................................................4
II-A - Introduction....................................................................................................................................................4
II-B - Java2D.......................................................................................................................................................... 5
II-B-1 - Fonctionnalités......................................................................................................................................5
II-B-2 - Architecture de l'API.............................................................................................................................5
III - Étude de cas.........................................................................................................................................................6
III-A - Présentation de l'application........................................................................................................................ 6
III-B - Architecture.................................................................................................................................................. 7
IV - Implémentation......................................................................................................................................................8
IV-A - Construction des menus..............................................................................................................................8
IV-B - Lecture d'un fichier image en local........................................................................................................... 10
IV-C - Affichage des images................................................................................................................................ 11
IV-D - Création d'images......................................................................................................................................12
IV-E - Traitement sur les images......................................................................................................................... 13
IV-E-1 - Réduire la taille de l'image............................................................................................................... 13
IV-E-2 - Récupérer les pixels de l'image........................................................................................................14
IV-E-3 - Modifier la couleur des pixels de l'image..........................................................................................14
IV-E-4 - Binarisation de l'image...................................................................................................................... 15
IV-E-5 - Convolution mathématique................................................................................................................15
IV-F - Enregistrement d'une image...................................................................................................................... 17
V - Liens utiles...........................................................................................................................................................18
VI - Conclusions.........................................................................................................................................................18
VII - Remerciements.................................................................................................................................................. 18
-2-
http://slim-boukettaya.developpez.com/tutoriels/traitement-images-java/
Traitement d'images en Java par Mohamed Slim (slim_java)
I - Introduction
I-A - Image numérique
Les images que vous affichez sur votre écran, que vous créez ou modifiéez avec votre logiciel de dessin comme
Photoshop ou Gimp, sont en fait stockées sur votre ordinateur sous forme binaire (suite de 0 et de 1). Elles sont
appelées de ce fait des images numériques.
Ces images sont divisées on deux types : les images matricielles et les images vectorielles.
I-A-1 - Image vectorielle
D'après Wikipédia, une image vectorielle (ou image en mode trait), en informatique, est une image numérique
composée d'objets géométriques individuels (segments de droite, polygones, arcs de cercle, etc.) définis chacun par
divers attributs de forme, de position, de couleur, etc.
Elle se différencie de cette manière des images matricielles (ou " bitmap "), dans lesquelles on travaille sur des pixels.
Ces images peuvent être créés avec des logiciels spécifiques comme Adope Flash ou Adope Illustrator.
Il existe de nombreux formats de fichiers vectoriels, parmi lesquels, on peut citer : .SVG, .DXF ou .DWG.
I-A-2 - Image matricielle
Une image matricielle ou bitmap est représentée, comme son nom l'indique, par une matrice de points (un tableau
à deux dimensions).Ces points sont appelés des pixels.
Le nom pixel provient du terme anglais PICture ELement qui signifie le plus petit élément de l'image qui peut être
manipulé par le matériel et les logiciels d'imageries ou d'impression.
En fait, vos fichiers d'extension .bmp, .jpg, .gif, .png sont des fichiers d'images bitmap.
Lorsque vous zoomez une image bitmap comme le montre la figure ci-dessous, vous pouvez identifier ces points
coloriés à cause de l'effet aliasing (ou crénelage) qui apparaitront lors d'une faible résolution.
Chaque pixel (abrégé px) admet une couleur et est approximativement rectangulaire.
Les couleurs de l'image peuvent être codées suivant une palette, comme pour le format GIF, ou peuvent aussi être
codées dans l'espace de couleur RVB (ou RGB en anglais pour Red, Green, Blue) où chaque couleur est représentée
par trois couleurs fondamentales Rouge (Red) Vert (Green) et Bleu (Blue).
Vous pouvez consulter cette page pour obtenir le codage sur trois octets de vos couleurs préférées.
Les axes de l'image sont orientés de la façon suivante :
-3-
http://slim-boukettaya.developpez.com/tutoriels/traitement-images-java/
Traitement d'images en Java par Mohamed Slim (slim_java)
Chaque pixel est repéré par ses coordonnées x et y.
Avant d'enregistrer une image, il faut lui attribuer un format de stockage comme le format .jpg ou .bmp.
Chaque format utilise un algorithme de compression qui peut être avec perte ou sans perte.
Parmi ces algorithmes, on peut citer LZW, RLE, etc.
Pour plus d'information sur les images numériques, vous pouvez consulter ce lien.
I-B - Traitement d'images
Le traitement d'images est l'ensemble des opérations qui entrainent la modification des images numériques.
Ces modifications portent généralement sur la couleur des pixels.
Plusieurs techniques sont utilisées pour manipuler ces données,
le but étant l'amélioration de ces données afin d'obtenir une plus grande lisibilité de l'image.
On trouve plusieurs logiciels gratuits ou payants spécifiques pour le traitement des images matricielles ou vectorielles.
On peut citer Adope Photoshop pour le traitement des images bitmap.
II - Traitement d'images en Java
II-A - Introduction
Java est un langage de programmation multiplateforme connu par la richesse de ses API et par sa portabilité.
À la base, Java été conçu pour écrire des pages Web dynamiques intégrant des applets, chez le client, qui
communiquent avec des Servlets sur les serveurs.
Cette orientation vers le Web a changé grâce à la multitude des classes Java (3780 classes dans Java SE 6). On
peut trouver dès lors des applications de bureau ou d'autres destinées pour les PDA écrites en Java.
Java est présent aussi dans le domaine de l'infographie. C'est grâce à son API
logiciels de traitement et d'analyse d'images performants comme
utilisable sur différents systèmes d'exploitation.
-4-
Java 2D qu'on peut écrire des
imageJ qui est riche en fonctionnalités et
http://slim-boukettaya.developpez.com/tutoriels/traitement-images-java/
Traitement d'images en Java par Mohamed Slim (slim_java)
II-B - Java2D
II-B-1 - Fonctionnalités
Java 2D est une API composée par un ensemble de classes destinées à l'imagerie et à la création de dessin 2D.
Elle permet de :
•
•
•
•
dessiner des lignes, des rectangles et toute autre forme géométrique ;
replisser les formes par des couleurs unies ou en dégradés et lui ajouter des textures ;
ajouter du texte, lui attribuer différentes polices et contrôler son rendu ;
dessiner des images, éventuellement en effectuant des opérations de filtrage.
Dans cet article on va traiter la partie imagerie de l'API comme on va voir les différentes fonctions fournies pour faire
le traitement d'images.
II-B-2 - Architecture de l'API
Pour travailler avec les images sous Java 2D, il faut connaitre deux classes importantes de l'API :
A
java.awt.Image :
c'est la super classe fournie dans la JDK depuis sa version 1.0. C'est une classe abstraite qui permet de
représenter les images sous forme d'un rectangle de pixels.
La restriction de cette classe est qu'elle ne permet pas d'accéder aux pixels. Elle est donc inadaptée pour le
traitement d'images.
B
java.awt.image.BufferedImage :
Ajoutée à la JDK depuis sa version 2. Elle hérite de la classe Image et implémente ses interfaces pour permettre
d'examiner l'intérieur des images chargées et travailler directement sur ses données. On peut donc à partir d'un
objet BufferedImage, récupérer les couleurs des pixels et changer ces couleurs. Comme son nom l'indique,
BufferedImage est une image tampon. Cette classe gère l'image dans la mémoire et fournit des méthodes
pour l'interprétation des pixels. Si on veut faire du traitement d'images, il faut donc travailler avec des objets
BufferedImage. Comme le montre la figure suivante, un objet BufferedImage est composé de deux parties :
-5-
http://slim-boukettaya.developpez.com/tutoriels/traitement-images-java/
Traitement d'images en Java par Mohamed Slim (slim_java)
•
•
java.awt.image.ColorModel:
cette classe définit la façon d'interpréter les couleurs. Le ColorModel est capable de traduire les valeurs
des données provenant du Raster en objet java.awt.Color.
java.awt.image.Raster :
elle contient les données de l'image et peut les représenter comme un tableau de valeurs de pixels.
Aussi, elle maintient les données de l'image dans la mémoire et fournit des méthodes pour accéder
à des pixels spécifiques au sein de l'image. Modifier les données d'une image est en créer d'autres
instances.
Pour plus d'informations sur l'API Java2D, vous pouvez consulter ce lien http://java.sun.com/j2se/1.4.2/docs/
guide/2d/spec.html.
III - Étude de cas
III-A - Présentation de l'application
Cette application est un logiciel écrit en Java permettant d'appliquer certaines opérations sur les images bitmap.
Elle permet de :
•
•
•
lire des fichiers images et les afficher sur l'écran ;
enregistrer des images après modification sur le disque ;
appliquer un ensemble de filtres comme :
•
rendre l'image en niveau de gris ou binarisation de l'image ,
•
assombrir les couleurs des pixels ,
•
ajouter un effet de brillance. Appliquer certain filtres linéaires ,
•
zoomer / dézoomer l'image.
-6-
http://slim-boukettaya.developpez.com/tutoriels/traitement-images-java/
Traitement d'images en Java par Mohamed Slim (slim_java)
J'ai écrit cette application spécialement pour cet article, donc vous pouvez télécharger
le code et l'améliorer
suivant vos besoins.
L'application supporte seulement le format .jpg, vous devez donc modifier le code pour pouvoir gérer d'autres formats.
Pour comprendre les codes présents dans la partie qui suit, une connaissance de l'API SWING est nécessaire
notamment la partie programmation par délégation et la gestion des événements.
III-B - Architecture
L'application est composée de deux classes :
Classe Cadre :
cette classe représente la fenêtre principale de l'application.
Le constructeur de cette classe permet de créer trois menus :
•
•
•
le menu « Fichier » contient un sous-menu « Ouvrir » qui permet d'ouvrir un fichier image stocké sur le
disque et un deuxième sous menu « Enregistrer » qui permet d'enregistrer une image sur le disque après
modification ;
le menu « Filtre » contient cinq sous menus qui présentent les principaux traitements applicables sur les
images chargées depuis le disque ;
le menu « Retailler » quant à lui, contient le sous menu « Zoomer » et « Dézoomer » permettant
respectivement comme le nom de chacun l'indique d'agrandir ou de réduire la taille de l'image chargée.
Classe PanDessin :
Cette classe dérive de JPanel. Elle présente le panneau où seront affichées les images chargées par l'application.
Elle admet un attribut unique monImage de type BufferedImage qui présente à tout moment l'image chargée affichée
dans le panneau.
Cette classe présente le c�ur de l'application. Ses méthodes permettent de modifier les images.
BufferedImage monImage = null;
protected
}
protected
}
protected
}
protected
void reduireImage(){
void agrandirImage(){
void imageConvolue(){
void imageEclaircie(){
-7-
http://slim-boukettaya.developpez.com/tutoriels/traitement-images-java/
Traitement d'images en Java par Mohamed Slim (slim_java)
}
protected
}
protected
}
protected
}
protected
}
protected
}
protected
}
protected
}
void imageSombre(){
void imageBinaire(){
void imageEnNiveauGris(){
void modifierImage(){
void ajouterImage(File fichierImage){
BufferedImage getImagePanneau(){
void enregistrerImage(File fichierImage){
IV - Implémentation
IV-A - Construction des menus
Les opérations de traitement sont déclenchées suite aux appuis sur la commande correspondante dans la barre de
menus.
Par exemple si vous voulez ouvrir une image comme une opération de début, il faut sélectionner le menu « Fichier
» et cliquer ensuite sur le sous-menu « Ouvrir » et de la même façon pour les autres opérations.
La création du menu doit se faire dans le constructeur de la classe Cadre :
public Cadre()
{
setJMenuBar(menuBar);
menuBar.add(fichierMenu);
fichierMenu.setText("Fichier");
fichierMenu.add(ouvrirMenu);
ouvrirMenu.addActionListener((ActionListener)this);
ouvrirMenu.setText("ouvrir");
fichierMenu.add(enregistrerMenu);
enregistrerMenu.addActionListener((ActionListener)this);
enregistrerMenu.setText("enregistrer");
menuBar.add(filtreMenu);
filtreMenu.setText("Filtre");
filtreMenu.add(niveauGrisMenu);
niveauGrisMenu.addActionListener((ActionListener)this);
niveauGrisMenu.setText("niveau de gris");
filtreMenu.add(binarisationMenu);
binarisationMenu.addActionListener((ActionListener)this);
binarisationMenu.setText("binarisation");
filtreMenu.add(assombrirMenu);
assombrirMenu.addActionListener((ActionListener)this);
assombrirMenu.setText("assombrir");
filtreMenu.add(brillanceMenu);
brillanceMenu.addActionListener((ActionListener)this);
brillanceMenu.setText("brillance");
filtreMenu.add(convolutionMenu);
convolutionMenu.addActionListener((ActionListener)this);
convolutionMenu.setText("convolution");
menuBar.add(retaillerMenu);
retaillerMenu.setText("retailler");
retaillerMenu.add(agrandirMenu);
-8-
http://slim-boukettaya.developpez.com/tutoriels/traitement-images-java/
Traitement d'images en Java par Mohamed Slim (slim_java)
agrandirMenu.addActionListener((ActionListener)this);
agrandirMenu.setText("agrandir");
retaillerMenu.add(reduireMenu);
reduireMenu.addActionListener((ActionListener)this);
reduireMenu.setText("reduire");
}
// ajouter le panneau de dessin
getContentPane().add(panneau);
La dernière instruction du constructeur permet d'associer un objet de la classe PanDessin à l'objet Cadre, ce qui
permet d'ajouter un panneau à notre fenêtre. Ce panneau sera ensuite la zone d'affichage des images.
Selon le principe de programmation par délégation, un appui sur l'un des sous-menus, fait appel à la méthode
actionPerformed() :
public void actionPerformed(ActionEvent )
Selon le sous-menu sélectionné, cette méthode fait appel à la méthode correspondante dans la classe PanDessin.
public void actionPerformed(ActionEvent cliqueMenu)
{
if (cliqueMenu.getSource().equals(ouvrirMenu))
{
// ouvrir une image
[...]
panneau.ajouterImage(..chemin du fichier image..) ;
}
}
else if (cliqueMenu.getSource().equals(enregistrerMenu))
{
// enregistrer une image
[...]
panneau.enregistrerImage(fichierEnregistrement);
}
}
else if (cliqueMenu.getSource().equals(niveauGrisMenu))
{
// Changer l'image en niveau de gris
panneau.imageEnNiveauGris();
}
else if (cliqueMenu.getSource().equals(brillanceMenu))
{
// Eclaircir l'image
panneau.imageEclaircie();
}
else if(cliqueMenu.getSource().equals(assombrirMenu))
{
// Rendre l'image plus sombre
panneau.imageSombre();
}
else if (cliqueMenu.getSource().equals(binarisationMenu))
{
// Rendre l'image binaire
panneau.imageBinaire();
}
else if (cliqueMenu.getSource().equals(convolutionMenu))
{
// Faire la convolution mathématique suivant un masque donné
panneau.imageConvolue();
}
else if (cliqueMenu.getSource().equals(agrandirMenu))
{
// Agrandir l'image
panneau.agrandirImage();
}
-9-
http://slim-boukettaya.developpez.com/tutoriels/traitement-images-java/
Traitement d'images en Java par Mohamed Slim (slim_java)
else if (cliqueMenu.getSource().equals(reduireMenu))
{
//reduire la taille de l'image
panneau.reduireImage();
}
}
IV-B - Lecture d'un fichier image en local
La méthode ajouterImage() de la classe PanDessin permet de lire un fichier image. Elle prend en paramètre un objet
de type java.io.File qui correspond au fichier image :
protected void ajouterImage(File fichierImage)
{
// lire l'image
monImage = ImageIO.read(fichierImage);
// Appel à repaint pour activer l'affichage du panneau et visualisation
// de l'image sur la surface du panneau.
repaint();
}
L'objet fhcierImage est un objet de la classe java.io.File. On peut obtenir cet objet grâce au constructeur de la classe
File qui prend en paramètre le chemin du fichier.
File fichierImage = new File("C:\\duke.jpg"));
La méthode statique read() de la classe ImageIO permet de charger une image en mémoire depuis ce fichier en lui
associant un objet BufferedImage. Cette méthode attend que l'image soit entièrement chargée avant de retourner
l'objet BufferedImage.
ImageIO est une classe du paquetage
javax.imageio.
Ce paquetage contient les classes de base et les interfaces pour la gestion des fichiers images. On trouve les classes
suivantes :
•
•
•
•
•
ImageIO : pour décrire le contenu des fichiers images y compris les métadonnées ;
ImageReader, ImageReadParam et ImageTypeSpecifier : pour contrôler le processus de lecture d'image.
ImageWriter et ImageWriteParam : pour contrôler le processus d'écriture des images ;
ImageTranscoder : pour faire le transcodage entre les formats ;
IIOException : pour signaler les erreurs.
Les formats .jpg ou .gif sont des formats externes utilisés pour représenter des images numériques. Pour utiliser ces
images en Java, il faut convertir ces formats en un format interne.
Comme on a vu plus haut, cette conversion est faite par les classes du paquetage javax.imageio notamment la classe
ImageReader et ImageTranscoder. En fait, les formats supportés sont GIF, PNG, JPEG, BMP, WBMP.
FORMAT
JPEG
PNG
BMP
WBMP
GIF
LU
oui
oui
oui
oui
oui
ECRIT
oui
oui
oui
oui
non
La classe ImageIO choisit un lecteur approprié, en fonction du type de fichier. Dans ce but, elle peut consulter
l'extension de fichier et le "numéro magique" qui se trouve dans les premiers octets, et qui identifie le format du fichier.
- 10 -
http://slim-boukettaya.developpez.com/tutoriels/traitement-images-java/
Traitement d'images en Java par Mohamed Slim (slim_java)
Lorsqu'un lecteur adapté ne peut être trouvé ou si le lecteur ne parvient pas à décoder le contenu du fichier, la
méthode read() renvoie null.
D'autres formats comme le format TIFF peuvent être traités par l'installation de fichiers JAR contenant des plug-ins
qui une fois installés, permettront qu'un nouveau format sera automatiquement compris, sans aucune modification
du code de l'application.
Chaque format d'image à son avantage et son inconvénient :
Format
GIF
PNG
JPG
Avantages
Supporte les
animations et
gère les pixels
transparents.
Compression
sans perte.
Supportent
les images en
couleurs réelles
(codées sur 24
bits)
Idéal pour
les images
photographiques
Inconvénients
Ne pend en
charge que 256
couleurs
Ne supporte pas
d'animation
Compression
avec perte.
N'est pas bon
pour les images
contenant du
texte et toute
autre image où
les données sont
critiques.
On peut utiliser la méthode getReaderFormatNames() pour connaitre les formats supportés en lecture :
String names[] = ImageIO.getReaderFormatNames();
for (int i = 0; i < names.length; ++i)
{
System.out.println(" fomat supportée en lecture :" + names[i]);
}
Ce code retourne uniquement les formats supportés en standard et aucun des plug-ins supplémentaires ne sera
mentionné.
IV-C - Affichage des images
Après avoir lu le fichier de l'image avec la méthode read() et obtenu un objet BufferedImage pour la représenter en
mémoire, elle peut être maintenant affichée dans notre panneau.
La méthode paintComponent() du panneau est spécialisée dans l'affichage des éléments graphiques qui se trouve
dans la surface du panneau. Cette méthode est automatiquement sollicitée dès que nous avons besoin d'afficher ou
de réafficher la fenêtre de l'application.
Nous devons donc passer par cette méthode pour être sûr que notre image soit réaffichée au moment du
rafraîchissement.
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
if(monImage != null)
g.drawImage(monImage, 0, 0, null);
}
- 11 -
http://slim-boukettaya.developpez.com/tutoriels/traitement-images-java/
Traitement d'images en Java par Mohamed Slim (slim_java)
Pour afficher notre image, il faut utiliser la méthode :
drawImage(Image img, int x, int y, ImageObserver observer)
de la classe java.awt.Graphics.
•
•
•
le premier paramètre de la méthode doit être de type Image ou un type dérivé. Dans notre cas, l'objet
monImage est de type BufferedImage, elle fait référence à l'image en mémoire.
x et y : présentent les coordonnées du point haut gauche de l'image.
observer : utilisée pour mettre à jour l'affichage de l'image lors d'un téléchargement d'une façon asynchrone.
Ce paramètre n'est pas utilisé lorsque l'on travaille avec des BufferedImage qui utilisent le mode de
chargement synchrone. Il peut être à null.
Lors du chargement de l'image, vous pouvez lui imposer une taille, par exemple vous pouvez l'ajuster à la surface
du panneau.
g.drawImage(monImage, 0, 0,mon_panneau.getWtith(),mon_panneau.getHeight(), null);
IV-D - Création d'images
Une image peut être dessinée dans la surface d'un panneau, comme elle peut être elle aussi, une surface pour
dessiner des formes 2D ou même des images.
On peut dessiner des formes géométriques comme des cercles, des polygones dans une image en utilisant les
méthodes de dessin fournies par Java 2D comme fillOval() ou fillPolygon() :
BufferedImage image = new BufferedImage(width_image, height_image, BufferedImage.TYPE_INT_RGB);
// on récupère le contexte graphique de la BufferedImage
Graphics2D g = image.createGraphics();
// la couleur de dessin est le bleu
g.setColor( Color.blue );
// on dessine un cercle rempli de rayon 200 dont le centre est de coordonnées (30,30)
int Rayon = 200 ;
g.fillOval( 50, 50, Rayon, Rayon );
// on libère la mémoire utilisée pour le contexte graphique
g.dispose();
- 12 -
http://slim-boukettaya.developpez.com/tutoriels/traitement-images-java/
Traitement d'images en Java par Mohamed Slim (slim_java)
la première instruction permet de créer une image vide. On spécifie ses dimensions et sont type. Le type utilisé pour
cette image est BufferedImage.TYPE_INT_RGB.
Les pixels d'une image de ce type sont spécifiés par un entier décrivant les valeurs de rouge, de vert et de bleu sans
prendre en considération la couche alpha.
Les types d'images indiquent comment les couleurs des pixels sont codés. Vous trouvez une liste des différents types
pris en charge par la classe BufferedImage
ici.
IV-E - Traitement sur les images
IV-E-1 - Réduire la taille de l'image
En utilisant le menu « Retailler » on peut réduire ou agrandir la taille de l'image.
Il faut donc faire une transformation affinée à l'image.
protected void reduireImage()
{
// créer une nouvelle image qui contient les mêmes données de l'image source mais ayant //
une taille réduite par 2.
BufferedImage imageReduite = new BufferedImage((int)(monImage.getWidth()*0.5),(int)
( monImage.getHeight()*0.5), monImage.getType());
// Une transformation affine effectue un changement d'échelle sur l'image.
// On doit spécifier le rapport suivant les axes x et y.
// la valeur 0.5 présente le coefficient de multiplication.
AffineTransform reduire = AffineTransform.getScaleInstance(0.5, 0.5);
//
//
//
//
AffineTransformOp effectue une transformation géométrique d'une image source pour produire une image
destination. Il faut donc faire une interpolation des pixels pour construire l'image cible.
L'entier AffineTransformOp.TYPE_BICUBIC présente un compromis entre le temps de calcul et les
performances.
int interpolation = AffineTransformOp.TYPE_BICUBIC;
AffineTransformOp retaillerImage = new AffineTransformOp(reduire, interpolation);
retaillerImage.filter(monImage, imageReduite );
monImage = imageReduite ;
}
// Appel à repaint pour activer l'affichage du panneau et visualisation
// de l'image sur le panneau après changement
repaint();
- 13 -
http://slim-boukettaya.developpez.com/tutoriels/traitement-images-java/
Traitement d'images en Java par Mohamed Slim (slim_java)
IV-E-2 - Récupérer les pixels de l'image
Comme indiqué au début de l'article, un objet BufferedImage permet de manipuler les pixels de l'image. Le tableau
de pixels de l'image est matérialisé par un objet de type java.awt.image.Raster.
En utilisant un objet instance de cette classe, on peut récupérer les informations sur la couleur des pixels.
Raster tramePixel = monImage.getRaster();
int[] couleurRGB = new int[3];
System.out.println("teinte rouge = "+couleurRGB[0]);
System.out.println("teinte verte = "+couleurRGB[1]);
System.out.println("teinte bleu = "+couleurRGB[2]);
La couleur du pixel renvoyée est stockée dans le tableau couleurRGB de taille 3.
La première case contient la valeur de la composante rouge, la deuxième pour la composante verte et la dernière
case pour la teinte bleu.
Dans notre cas, on a une connaissance préalable du type d'image qui est de type BufferedImage.TYPE_INT_RGB
, c'est-à-dire que le modèle de couleur est RGB sans transparence.
Que fait-on alors si on ne connait pas le type de l'image et le modèle de couleur utilisé ?
C'est ici qu'intervient la classe ColorModel qui est une composante de la classe BuferedImage et qui permet de
représenter le modèle de couleur utilisé pour chaque image. Ainsi, une manière de faire est d'utiliser la méthode
getDataElements() qui retourne la couleur du pixel sans vous charger de spécifier le modèle de couleur utilisé.
Une nouvelle version du code précédent devient :
Raster tramePixel = monImage.getRaster();
ColorModel modeleCouleur = monImage.getColorModel();
Object objCouleur
= tramePixel.getDataElements(x, y, null);
System.out.println("teinte rouge = "+ modeleCouleur.getRed(objCouleur));
System.out.println("teinte verte = "+ modeleCouleur .getGreen(objCouleur)) ;
System.out.println("teinte bleu = "+ modeleCouleur.getBlue(objCouleur));
IV-E-3 - Modifier la couleur des pixels de l'image
Cependant, si on veut changer les couleurs de pixels, cette fois-ci il faut utiliser un objet de type
WritableRaster.
Comme son nom l'indique, cette classe étend la classe Raster :
+--java.awt.image.Raster +--java.awt.image.WritableRaster
Une manière de faire est d'utiliser cette fois ci la méthode setDataElements() à la place de la méthode
getDataElements() pour la modification des pixels.
int xPixel = 100 ;
int yPixel = 100 ;
WritableRaster trameModifiable = monImage.getRaster();
ColorModel modèleCouleur = monImage.getColorModel();
int rgb = Color.white.getRGB();
Object couleurBlanc = modèleCouleur.getDataElements(rgb, null);
// la pixel qui se trouve à la position (100,100) va prendre la couleur blanche
trameModifiable.setDataElements(xPixel, yPixel, couleurBlanc);
- 14 -
http://slim-boukettaya.developpez.com/tutoriels/traitement-images-java/
Traitement d'images en Java par Mohamed Slim (slim_java)
IV-E-4 - Binarisation de l'image
Une image binaire est composée de pixels ayant uniquement l'une des deux couleurs noir ou blanc. Théoriquement,
Il y a plusieurs méthodes pour rendre une image binaire.
Si on travaille avec la méthode de seuillage simple, la valeur de chaque pixel P(x, y) est comparée à un seuil S et si
cette valeur est supérieure à S, le pixel prend la valeur 1 (noir), sinon il prend la valeur 0 (blanc).
En travaillant avec des BufferedImage, on peut rendre une image binaire on utilisant tout simplement le type
BufferedImage.TYPE_BYTE_BINARY.
protected void imageBinaire()
{
BufferedImage imgBinaire = new BufferedImage(monImage.getWidth(), monImage.getHeight(),
BufferedImage.TYPE_BYTE_BINARY);
Graphics2D surfaceImg = imgBinaire.createGraphics();
surfaceImg.drawImage(monImage, null, null);
monImage = imgBinaire;
}
// Appel à repaint pour activer l'affichage du panneau et visualisation
// de l'image sur le panneau après changement
repaint();
Par contre, vous pouvez utiliser la méthode de seuillage. En effet, si vous aviez fait ce choix, vous
auriez dû faire référence au code permettant de modifier la couleur des pixels présenté en haut. Toutefois,
avant de faire la binarisation de l'image, il faut l'avoir modifiée en niveau de gris en utilisant le type
BufferedImage.TYPE_BYTE_GRAY pour avoir une seule composante de couleur.
IV-E-5 - Convolution mathématique
Théoriquement, la convolution est le fait d'utiliser une matrice d'entiers appelée aussi masque ou noyau, pour
multiplier les valeurs de couleur d'un pixel donné de l'image par ce masque.
Le principe de l'algorithme consiste à amplifier la valeur d'un pixel P et de chacun des n pixels qui l'entourent par la
valeur correspondante dans le noyau. Le but est d'additionner l'ensemble des résultats pour que le pixel P prenne
la valeur du résultat final.
Je ne suis pas un spécialiste en la matière mais vous pouvez consulter cet article pour plus de détails sur le sujet.
Le masque qu'on va utiliser est de taille 3x3.
float[
{
0.1f,
0.1f,
0.1f,
};
] masqueFlou =
0.1f, 0.1f,
0.2f, 0.1f,
0.1f, 0.1f
Il permet de rendre l'image floue comme le montre la figure suivante :
- 15 -
http://slim-boukettaya.developpez.com/tutoriels/traitement-images-java/
Traitement d'images en Java par Mohamed Slim (slim_java)
La méthode utilisée pour ce filtre est imageConvolue() :
protected void imageConvolue()
{
BufferedImage imageFlou = new BufferedImage(monImage.getWidth(),monImage.getHeight(),
monImage.getType());
float[ ] masqueFlou =
{
0.1f, 0.1f, 0.1f,
0.1f, 0.2f, 0.1f,
0.1f, 0.1f, 0.1f
};
Kernel masque = new Kernel(3, 3, masqueFlou);
ConvolveOp opération = new ConvolveOp(masque);
opération.filter(monImage, imageFlou);
monImage = imageFlou;
// Appel à repaint pour activer l'affichage du panneau et visualisation
// de l'image sur le panneau après changement
}
repaint();
L'opération de multiplication ou plus précisément la convolution mathématique est réalisée par un objet de la classe
ConvolveOp. Si vous voulez appliquer d'autres opérations comme la segmentation, l'estompage ou le gradient,
vous devez tout simplement modifier les coefficients de la matrice de convolution définis par la variable
float[ ] masqueFlou
float[ ] masqueGradientX =
{
-1f, 0f, 1f ,
-2f, 0f, 2f ,
-1f, 0f, 1f
};
- 16 -
http://slim-boukettaya.developpez.com/tutoriels/traitement-images-java/
Traitement d'images en Java par Mohamed Slim (slim_java)
float[ ] masqueGradientY =
{
1f, 2f, 1f,
0f, 0f, 0f,
-1f, -2f, -1f
};
Par exemple pour obtenir le gradient de Sobel, vous pouvez utiliser le masque ci-dessus :
IV-F - Enregistrement d'une image
Finalement, notre image source définie par un objet BufferedImage qu'on a obtenu déjà a partir d'un fichier sur le
disque, a subi différentes transformations.
On peut donc conclure que les données de l'image source sont modifiées et que son tableau de pixels (trame) stocké
dans la mémoire a changé de valeurs. On obtient alors une image affichée sur la surface du panneau différente de
l'image initialement chargée.
Il faut donc penser à enregistrer cette nouvelle image localisée dans la mémoire sur le disque.
Une manière de le faire consiste à créer une image à partir de la surface du panneau (objet de PanDessin) et
enregistrer cette image dans un format donné. Pour créer cette image, on utilise la méthode getImagePanneau() :
protected BufferedImage getImagePanneau()
{
// récupérer une image du panneau
int width = this.getWidth();
int height = this.getHeight();
BufferedImage image = new BufferedImage(width, height,
Graphics2D g = image.createGraphics();
this.paintAll(g);
g.dispose();
return image;
}
BufferedImage.TYPE_INT_RGB);
Par la suite, on fait appel à la méthode enregistrerImage() qui permet d'écrire cette image sur le disque en utilisant
la méthode statique write() de la classe ImageIO.
protected void enregistrerImage(File fichierImage)
{
String format ="JPG";
BufferedImage image = getImagePanneau();
ImageIO.write(image, format, fichierImage);
}
Comme pour la lecture des fichiers images, il faut connaitre les formats supportés en écriture par la classe ImageIO.
Pour récupérer ces formats on peut utiliser la méthode getWriterFormatNames() :
String[] names = ImageIO.getWriterFormatNames();
for (int i = 0; i < names.length; ++i)
{
System.out.println ("format supportée en ecriture : " + names[i]);
}
Cette méthode retourne uniquement les formats supportés en standard et aucun des plug-ins supplémentaires ne
sera mentionné.
Avec ce dernier paragraphe, qui traite l'enregistrement d'image en Java 2D, on arrive à la fin de la présentation de
l'application à travers laquelle j'ai essayé d'exploiter les fonctionnalités de l'API Java 2D fournis pour le traitement
d'images. D'autres méthodes dans le code de l'application n'ont pas été mentionnées vu qu'il s'agit des mêmes
traitements expliqués plus haut avec une élémentaire modification dans le code.
- 17 -
http://slim-boukettaya.developpez.com/tutoriels/traitement-images-java/
Traitement d'images en Java par Mohamed Slim (slim_java)
V - Liens utiles
•
•
•
•
•
Documentation de l'API
Ecrire des plug-in pour de nouveau formats
Guide de l'API java 2D
Partie Image de la FAQ GUI
Partie listener de la FAQ GUI
VI - Conclusions
Dans cet article, j'ai présenté différentes fonctionnalités de l'API Java 2D pour le traitement d'images.
J'ai expliqué le code d'une application fenêtrée qui permet de faire plusieurs opérations sur les images bitmap comme
la lecture, l'enregistrement, l'application de filtres et le dimensionnement.
Pour terminer, il faut dire que le traitement d'images en Java n'est pas limité aux services de l'API Java 2D, mais
les dépassent pour utiliser l'API Java Advanced Image ou couramment JAI, qui étend les services offerts par Java
2D tout en étant compatible avec celle-ci.
VII - Remerciements
Je tiens à remercier la rubrique Java de Developpez.com et son responsable Ricky81.
Je remercie aussi Jacques THERY pour la relecture orthographique de l'article.
- 18 -
http://slim-boukettaya.developpez.com/tutoriels/traitement-images-java/
Téléchargement