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=−110=111111112 or int p=25510=111111112 , 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