1. Introduction 2. Lire et afficher une image

Transcription

1. Introduction 2. Lire et afficher une image
Master 2 – Image
22 novembre 2011
Les Bibliothèques
ImageJ et OpenCV
1. Introduction
Cette séance est consacrée à une introduction à la programmation sur le traitement
d'image. Deux bibliothèques sont présentées :
•
ImageJ, en Java,
•
OpenCV 2.3.x, en C/C++.
1.1 Image J
1. Sous Eclipse, créer un projet java
2. à l'adresse http://www.math-info.univ-paris5.fr/~npyun/ télécharger le fichier ij.jar et
l'importer dans le projet
3. Créer le package de votre choix et une première classe.
1.2 OpenCV
1. Sous Eclipse, créer un projet C++ utilisant MinGW comme comilateur.
2. Inclure le path dans Properties – C/C++ Build – Settings – GCC C++ Compiler –
Includes.
Pour trouver le chemin taper sur le terminal la commande pkg-config --cflags opencv.
3. Préciser les librairies (core, imgproc, highgui, features2D) utilisées ainsi que le
chemin des librairies dans Properties – C/C++ Build – Settings – GCC C++ Linker –
Librairies.
Pour trouver le chemin taper sur le terminal la commande pkg-config --libs opencv.
2. Lire et afficher une image
2.1 ImageJ
On se propose de lire et stocker une image de deux manières, soit avec la
bibliothèque standard de oracle sun, soit avec la bibliothèque imageJ.
1. Bibliothèque standard avec la classe ImageIO du package javax.imageio:
intéressez-vous surtout à la méthode BufferedImage read(File file).
http://download.oracle.com/javase/6/docs/api/javax/imageio/ImageIO.html
2. Bibliothèque ImageJ notamment aux classes ImagePlus et ImageProcessor:
s'intéresser à la méthode ImagePlus openImage(Strng path) de la classe Opener
du pakage ij.io.
P1
http://rsbweb.nih.gov/ij/developer/api/index.html
Dans une classe Utilities, écrire les deux méthodes static suivantes:
•
public static BufferedImage getBufferedImage(File file) throws IOException,
•
public static ImageProcessor getImageProcessor(File file) throws IOException,
•
tester la méthode getImageProcessor avec dans une méthode main. Pour afficher
l'image chargée, utiliser la classe ImagePlus, notamment:
◦ au contructeur ImagePlus(java.lang.String title, ImageProcessor ip)
◦ et à la méthode show().
http://rsbweb.nih.gov/ij/developer/api/index.html
2.2 OpenCV
Pour lire une image utiliser la fonction imread.
•
Mat img = imread(filename)
La classe Mat (pour matrix) permet de stocker l'image sous forme matricielle sous la
forme BGR donc avec 3 canaux à 8 bits chacun.
Pour obtenir une image en niveaux de gris donc sur un canal de 8 bits, écrire :
•
Mat img = imread(filename, 0);
Pour afficher une image écrire :
•
namedWindow( "Display Image", CV_WINDOW_AUTOSIZE );
imshow( "Display Image", img );
3. Conversion en niveaux de gris
Rappel: niveau de gris
R+G+B
.
3
3.1 Image J
Dans une classe ToGrayScale:
•
Créer un membre d'instance private ImageProcessor outputProcessor.
•
Écrire une méthode d'instance public void run(ImageProcessor ip) qui convertit
l'image couleur ip en un niveaux de gris. Le niveau de gris sera stocké dans
outputProcessor. Tester la méthode.
◦ Vouc ne pouvez pas créer d'instance d'ImageProcessor(classe abstraite) ! Un
niveau de gris sur 8 bits correspond à un ByteProcessor. Un ByteProcessor
dérive d'ImageProcessor.
◦ outputProcessor est une instance de ByteProcessor de même hauteur et même
largeur que l'ImageProcessor ip.
◦ Pour accéder au pixels d'un ImageProcessor, utiliser la méthode Object
getPixels().
P2
▪ la méthode getPixels rend un tableau à 1 dimension. Notons qu'il retourne
dans sa déclaration un Object, il faudra caster. Le tableau contient la ligne 0,
puis la ligne 1 etc... Pour accéder au pixel de ligne 4 et de colonne 3 il faut
donc écrire 4×width+3 .
▪ Représentation d'un pixel en RGB :
Pour récupérer le canal R, on utilise un masque : int r=(p>>16)&0xFF ;
Octet pd fort
Octet 2
Octet 1
Octet 0
Rien/alpha
Canal R
Canal G
Canal B
3.2 OpenCV
•
Écrire une fonction toGrayScale qui retourne une Mat en niveaux de gris. Tester la
méthode.
◦ Vec3f intensity = img.at<Vec3f>(x, y);
float blue = intensity.val[0];
float green = intensity.val[1];
float red = intensity.val[2];
on obtient ainsi les 3 canaux qui nous intéressent pour le pixel de coordonnées
x et y.
◦ Mat result ;
result.create(img.size(),CV_8U);
Pour créer une Mat avec la même taille que img contenant des octets non
signés uchar.
4. Extraction d'histogramme
Rappel: un histogramme est un tableau d'occurrences des différents niveau de gris
de l'image. Nous avons 256 niveaux de gris [0..255]. En sortie, nous aurons un tableau de
taille constante égale à 256.
4.1 ImageJ
Dans
la
classe
Utilities,
écrire
une
méthode
public
static
int[]
getGrayScaleHistogram(ImageProcessor processor) où processor est un ByteProcessor.
Cette méthode rendra l'histogramme de processor sous forme d'un tableau d'entiers.
Attention: En java, le type byte est signé et en complément à 1! Ainsi:
byte p=−110=111111112 or int p=25510=111111112 , il faudra penser à utiliser
les masques.
Compléter la méthode de test main et afficher l'histogramme. Pour afficher
l'histogramme, on utilisera la classe HistogramWindow du package ij.gui, après avoir
chargé l'image puis l'avoir transformée en niveaux de gris.
P3
4.2 Opencv
Écrire une méthode
d'une image Mat img.
•
getGrayScaleHistogram permettant d'obtenir l'histogramme
CV_Assert(img.depth() == CV_8U); permet de vérifier que img est bien une image
en niveaux de gris.
5. Utilisation de filtres
5.1 ImageJ
Dans cette section, il est question de créer une classe Filter qui permet d'appliquer
un filtre quelconque sur l'image. Pour cela, nous avons besoin d'un constructeur qui prend
en paramètre un tableau de double(i.e double[ ][ ]) représentant le filtre à appliquer ainsi
que les la hauteur et la largeur du filtre, outpuProcessor contiendra la sortie après
traitement, weight sera le poids permettant de pondérer le filtre.
private double[][] mask;
private int maskWidth;
private int maskHeight;
private ImageProcessor outputProcessor;
private double weight;
public Filter(double [][]mask){
this.mask=mask;
this.maskHeight=this.mask.length;
this.maskWidth=this.mask[0].length;
this.computeWeight();
}
•
La méthode private void computeWeight() calcule l'inverse de la somme des
éléments du masque.
•
private byte[][] extractLocalWindow(ImageProcessor processor,int row, int col) est la
méthode permettant de prélever une fenêtre de l'image processor, centrée en (col,
row) ayant la même largeur et hauteur que le masque. Les bords posent problème.
Pour cela, nous utiliserons des « pixels miroirs ».
•
public byte convolve(byte [][] window) rend un byte qui représente la convolution
entre une fenêtre window et le masque.
•
public void run(ImageProcessor inputProcessor) cette méthode applique le filtre sur
l'ensemble des pixels de inputProcessor qui est une image en niveaux de gris et
stocke l'image de sortie dans outputProcessor.
•
Écrire les précédentes méthodes et tester cette classe dans une méthode main.
•
Écrire la classe MeanFilter qui dérive de la classe Filter et qui prend pour masque
la matrice:
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
P4
•
•
Écrire la classe GaussianFilter qui dérive de la classe Filter qui prend pour masque
la matrice:
1
9
18
9
1
9
81
162
81
9
18
162 324 162
18
9
81
162
81
9
1
9
18
9
1
Tester les classes précédentes.
5.2 OpenCV
•
Mat kern = (Mat_<char>(3,3) << 0, -1, 0,
-1, 5, -1,
0, -1, 0);
Ci-dessus nous avons créer la matrice suivante
(
0 −1 0
−1 5 −1
0 −1 0
)
En s'inspirant de cette exemple et en utilisant la méthode filter2D
(http://opencv.itseez.com/modules/imgproc/doc/filtering.html#filter2d), créer les
méthodes meanFilter et gaussianFilter.
6. Pour aller plus loin
Que ce soit sur imageJ ou sur OpenCV, toutes les méthodes ou fonctions écrites
sont déjà implémentées. Les exercices précédents doivent permettre à l'étudiant
d'acquérir les bases pour utiliser les bibliothèques. Toutefois, rien ne remplace les tutoriels
officiels et les documents standards. Vous trouverez sur la page http://www.math-info.univparis5.fr/~npyun/ plusieurs documents officiels vous permettant une véritable maîtrise de
ces bibliothèques.
Par exemple, en vous aidant de la documentation, trouvez la transformée de Fourier
discrète et appliquez-la à l'image. Visualisez le résultat.
P5