INFO-F-101 Programmation Projet 4 Année académique 2008-2009 1 Introduction Une image peut-être décomposée en un tableau de points élémentaires appelés pixels (abréviation de picture element). Supposons que nous ne manipulions que des images en niveaux de gris (ou grayscale en anglais), c est-à-dire, des images dont les «couleurs» sont uniquement des nuances de gris. On peut représenter une telle image par une matrice d entiers, dont la valeur des éléments représente l intensité lumineuse des pixels de l image. Par conséquent, un traitement d image peut être réalisé en manipulant la matrice qui la représente. Dans ce projet, nous vous demandons d écrire un programme qui permet d appliquer un filtre graphique particulier à une image qui vous est donnée sur fichier au format PGM. 2 Fichier PGM Un fichier PGM (Portable Gray Map) est un fichier composé de deux parties : un en-tête et une matrice dont chaque élément représente le niveau de gris d un pixel de l image. Dans ce projet, nous considérerons qu il y a 256 niveaux de gris allant de 0 pour le noir à 255 pour le blanc. L entête contient 3 lignes. La première ligne est toujours la même, il s agit de l identifiant d un fichier PGM : P2. La seconde ligne contient 2 entiers : le nombre de colonnes et le nombre de lignes de pixels de l image. Enfin, la troisième ligne contient la valeur maximale que peut prendre un pixel (ici : 255). Les lignes qui suivent donnent l intensité de chaque pixel. Ceux-ci sont énumérés ligne par ligne et colonne par colonne. Ainsi la première valeur est l intensité du pixel du coin supérieur gauche, la seconde est l intensité du pixel de la première ligne, deuxième colonne, etc. Par exemple, un fichier PGM contenant les informations ci-dessous est l encodage d une image représentant une barre oblique blanche sur fond noir (voir Fig. 1) P2 10 6 255 0 114 255 114 0 0 0 0 0 0 0 0 123 255 123 0 0 0 0 0 0 0 0 112 255 101 0 0 0 0 0 0 0 0 115 255 103 0 0 0 0 0 0 0 0 111 255 121 0 0 0 0 0 0 0 0 145 255 135 0 De nombreux outils existent pour visualiser ces fichiers, les mots clés à taper dans un moteur de recherche pour les trouver sont : pgm viewer. Dans les salles informatiques, par exemple, vous pouvez utiliser le visualisateur d image pour ouvrir et imprimer des images au format pgm. 1
Fig. 1 Image de la barre oblique 3 Lecture et écriture sur fichier On peut écrire et lire sur un fichier en utilisant des flux comme cin et cout. Comme vous le savez, l instruction cin>> i; lit une valeur sur input et la stocke dans la variable i. Il est possible de créer un nouveau flux, dont on peut choisir le nom (par exemple fin), et qu on peut associer à un fichier de son choix. Ce flux permet de lire les données sur le fichier (et non pas sur l input du terminal, contrairement à cin). Ainsi, l instruction fin lira une information sur le fichier auquel fin est associé, et la placera dans la variable i. Pour ce faire, il faut tout d abord inclure la bibliothèque fstream en plus d iostream. Ensuite, il faut associer un fichier à une variable en déclarant un flux. Supposons que le fichier sur lequel on désire lire est picture.pgm, on écrira ifstream fin("picture.pgm"). On obtient alors un flux fin qui est associé au fichier picture.pgm. Pour écrire sur un fichier, on procède de même en remplaçant ifstream par ofstream. Dans cas, si le fichier spécifié n existe pas, il est créé automatiquement. Voici un exemple : #include<fstream> using namespace std; int main() { ifstream fin("fichierinput.pgm"); ofstream fout("fichieroutput.pgm"); // ouverture du fichier à lire // ouverture du fichier à écrire } char a; fin >> a; fout << a <<endl; // lecture d un caractère sur le fichier de lecture // écriture d un caractère dans le fichier d écriture Notez aussi que le type char permet de récupérer les caractères. Cela sera nécessaire pour lire la première ligne contenant P2, du fichier PGM. 4 Fonctions à écrire Soit MAX, la taille maximale d une image, et N, la taille maximale d un nom de fichier (on peut initialiser ces constantes à des valeurs suffisamment grandes. Par exemple : MAX=1000 et N=50). On vous demande d écrire les fonctions suivantes : 1. void chargerimage(char fichier[n], int& l, int& h, int img[max][max]), qui reçoit un nom de fichier PGM dans fichier, et lit l image contenue dans ce fichier. La fonction doit lire l image sur le fichier fichier et stocker les valeurs des pixels de l image dans la 2
Fig. 2 Recherche de la médiane et remplacement du pixel par la médiane matrice img. Les dimensions de l image (largeur et hauteur) doivent être stockées dans l et h respectivement. 2. void ecrireimage(char fichier[n], int l, int h, int img[max][max]), symétrique de la précédente, et qui écrit l image img de dimensions l et h dans le fichier spécifié, selon le format PGM. 3. void luminosity(int value, int l, int h, int img[max][max]), qui applique un filtre luminosité à l image. Ce dernier modifie la luminosité de l image : soit il éclaircit chaque pixel si value est positive, soit il assombrit l image si value est négative. value est un pourcentage entre 100% et 100%. En pratique, le filtre consiste à remplacer chaque pixel de coordonnée (i, j) par : ( img[i][j] + 255 value ) 100 Attention toutefois, si cette valeur est plus grande que 255, vous devez la ramener à 255. De même, si cette valeur est plus petite que zéro, vous la ramènerez à zéro. 4. void diffusion(int nbre_passe, int l, int h,int img[max][max]) qui applique un filtre de diffusion sur une image. Un filtre de diffusion a pour but de diffuser les valeurs moyennes par rapport aux valeurs des pixels voisins. Avec ce filtre, les valeurs, dont l écart est vraiment grand par rapport à leurs voisins, sont atténuées par la valeur moyenne. Le filtre ne traite que les pixels de coordonnées (i, j) avec 0 < i < l et 0 < j < h. Pour un tel pixel de coordonnées (i, j), nous appelons V i,j l ensemble qui contient sa valeur, ainsi que celles de ses huit voisins : les pixels de coordonnées (i 1, j 1), (i 1, j), (i 1, j+1),(i, j 1), (i, j + 1), (i + 1, j 1), (i + 1, j) et (i + 1, j + 1). Le traitement consiste à remplacer la valeur de chaque pixel (i, j) par la valeur médiane de V i,j. La médiane d un ensemble E est la valeur m (contenue dans E) telle qu il y a dans E autant de valeurs plus grande que m, que de valeurs plus petites que m. La Fig. 2 illustre cela. Enfin, pour produire un effet convaincant, ce filtre doit être appliqué plusieurs fois de suite sur l image. Le paramètre nbre_passe indique combien de fois votre fonction doit appliquer le filtre. 5 Exemples Les figures 3, 4 et 5 donnent des exemples d application de ces filtres. 3
Fig. 3 L image initiale Fig. 4 L image après avoir ajouté 40% de luminosité 4
Fig. 5 L image après traitement par le filtre de diffusion avec 200 passes. Consignes pour la remise du projet À respecter scrupuleusement! 1. Votre projet doit comporter votre nom et votre numéro de groupe. 2. Votre projet doit être dactylographié. Les projets écrits à la main ne seront pas corrigés. 3. Votre code doit être commenté. 4. Vous devez respectez les modalités suivantes : Date : le 17 novembre Lieu : au Secrétariat «étudiants» du Département d Informatique, local 2N8.104 Heure : Avant 16h Le secrétariat ferme à 16h. Après 16h, les projets sont considérés comme en retard, et vous perdez 1 point sur votre note finale (plus un point par jour de retard). Les projets en retard doivent être déposés dans la caisse prévue à cet effet près du secrétariat. 5