Enoncé du TP2 (fichier PDF, 72 Ko)
Transcription
Enoncé du TP2 (fichier PDF, 72 Ko)
PARI51 - Images Numériques - TP 2 c Besserer B. année universitaire 2004-2005 1 Compression avec pertes Le mode de compression avec pertes le plus répandu est la compression JPEG (Join Photograph Expert Group). Ce mode de compression conserve la qualité visuelle d’une image en atteignant des taux de compression records. Mais l’usage d’un fort taux de compression produit des artefacts qui deviennent rapidement visibles, surtout sur des images contenant des aplats de couleurs et des dégradés. La compression JPEG donne de meilleurs résultats sur des images qui sont "naturelles". Reprenez les images portrait.tif, billes.tif et canopee.png que vous avez utilisées lors du TP1. Sauvegardez ces images avec XnView au format JPEG en modifiant les options (cliquez sur le bouton option) et en plaçant le taux de compression à 75%. Enregistrez les images dans un nouveau répertoire local. Pour comparer visuellement les images, vous devez fermer le fichier, et l’ouvrir à nouveau (son nom reste dans la liste des fichiers utilisés récemment, dans le menu Fichier). Comparez visuellement avec le fichier d’origine. Bien que visuellement semblables, les images ne sont pas identiques ; nous allons mettre les différences en évidence à la fin du TP. Comme lors du TP1 et de la compression sans pertes, nous allons dresser un tableau comparatif : Pour les 3 images, faites une sauvegarde avec des taux de compression JPEG de 1%, 10% 25%, 50%, 75%, 85% et 100%etc... Lorsque vous enregistrer vos fichiers, modifier les noms (par exemple billes_25.jpg, billes_50.jpg, etc... Relevez la taille des fichiers, en Ko. Effectuez également une appréciation subjective de la qualité de l’image : Déterminez à partir de quel taux de compression les artefacts peuvent être perçus (on autorise un agrandissement de 200% au maximum). Taille du fichier en Ko "Qualité" JPEG - sans pertes (png ou tif) 100 85 75 50 25 10 1 Présentez le tableau pour les 3 images Commentaires (évaluation subjective) Faites également vos essais pour les basses qualités (1, 10%, 25%, 50%) avec le format JPEG2000 (avec XnView, version 1.25 ou supérieure), à comparer avec le JPEG standard en choisissant, pour la comparaison, le fichier JPEG de taille la plus proche. Remarquez que le format JPEG2000 propose également un mode de compression sans pertes (la qualité est donc forcément maximale, à assimiler au 100% du JPEG). Faites la compression de ces 3 images en JPEG2000 et relevez la taille. Comparez la taille avec une compression PNG. 1.1 La compression avec pertes est-elle meilleure sur des images infographiques ? L’image ci-dessous (heart.gif, téléchargeable) est issue d’un programme de dessin vectoriel, sauvegardé sous forme d’image bitmap GIF, 256 couleurs. Sauvegardez cette image au format JPEG avec une qualité de 50%. Ce fichier JPEG est ouvert et l’image est de nouveau sauvegardée au format GIF. Relevez la taille des fichiers et complétez le tableau. 1 Fichier GIF d’origine Fichier JPEG 50% de qualité Fichier GIF enregistré d’après le fichier JPEG Expliquez pourquoi le format JPEG ne permet pas de gain de taille, et pourquoi la taille du fichier final fait plus du double que le fichier d’origine ? 2 lecture et affichage d’un fichier BMP 2.1 Description du format BMP Le format BMP est un format "natif" de l’environnement graphique Windows et OS/2, ce format est également beaucoup utilisé sous DOS. L’API Win32 intègre les structures nécessaires pour manipuler les DIBs, le DIB (Device Independent Bitmap) étant la structure mémoire utilisée pour l’affichage GDI. Une grande partie du travail est donc déjà faite, sachant qu’un fichier BMP consiste en l’enregistrement d’un fichier DIB précédé d’une entête supplémentaire de 14 octets. La structure d’un fichier BMP est donc la suivante : – En-tête du fichier (en anglais file header), 14 octets. La structure correspondante est définie dans windows.h : BITMAPFILEHEADER – En-tête du bitmap (en anglais bitmap information header, appelé aussi information Header). De taille variable selon la version. Généralement 40 octets. Deux structures définies dans windows.h : BITMAPINFO, qui inclu BITMAPINFOHEADER. – Palette (optionnellement) – Corps de l’image 2.2 Programmation en mode console et affichage graphique Afin de ne pas trop "déstabiliser" les étudiants non familiarisés avec la programmation de l’API Win32, ou avec la programmation d’IHM (Interfaces Homme-Machine) en général, nous allons developper nos programmes en mode console. Les entrées sorties sont donc possibles avec printf et scanf. Néanmoins, un code vous est fourni pour afficher une image dans une fenêtre graphique. Mais dans un souci de simplicité du code et de compréhension, la procédure d’affichage comporte plusieurs restrictions : – Seules les images true color (24 bits/pixels — sans palette) peuvent être affichées, – La largeur de l’image doit être multiple de 4 (impératif), – Les boites de dialogues affichant les images sont modales : il faut cliquer sur OK pour fermer l’image et continuer le programme. Théoriquement, le code fourni peux se compiler avec les compilateurs freeware permettant l’usage de l’API Win32, comme OpenWatcom (http ://www.openwatcom.org/) ou LCC-Win32 (http ://www.cs.virginia.edu/ lccwin32/) — ce dernier étant un compilateur C et non C++. Téléchargez l’archive PARI51_TP2.zip. Décompressez l’archive dans un répertoire local. Examinez le code et la structure du projet. Si vous ne connaissez pas le maniement de VisualC, faites appel à l’intervenant. 1. Compilez et testez le programme. – Une erreur se produit à l’exécution lorsqu’on essaye de libérer l’espace mémoire alloué. Corrigez ce problème. – L’image s’affiche à l’envers... Consultez l’aide en ligne de BITMAPINFOHEADER, et modifiez le code pour résoudre le problème. 2. Modifier le code pour pouvoir lire des fichiers BMP. Le code fourni permettant la lecture du fichier PGM sera écarté du programme principal et mis dans une procédure que vous appellerez 2 ReadPGM() en choisissant des paramètres d’appels adaptés. Affichez les informations essentielles lors de la lecture du fichier BMP : Taille, nombre de bits/plan, etc. L’affichage de ces valeurs pourra s’effectuer simplement par une succession d’appels à printf, ou si vous le souhaitez (et si vous savez faire... utilisez SetDlgItemText !) dans la boite de dialogue. N’oubliez pas : vous disposez de la structure BITMAPINFOHEADER qui est déjà définie dans la WIN32 API, ansi que BITMAPFILEHEADER. Tapez simplement BITMAPINFOHEADER ou BITMAPFILEHEADER dans l’éditeur de Visual C, positionnez votre curseur sur ce mot et appuyez sur F1 pour consulter l’aide en ligne. Lorsque la lecture BMP fonctionnera, mettez le code dans une procédure ReadBMP() avec des paramètres adéquats pour pouvoir l’utiliser par la suite. Montrez à l’intervenant que votre code charge et affiche des images BMP. N’oubliez pas d’utiliser des images dont la largeur est un multiple de 4 3. Modification du gamma de l’image : Ecrivez une routine qui modifie chaque composante de chaque pixel selon la fonction y = x(1/γ) . La valeur γ est un paramètre pouvant varier de 0.45 à 2.2 (vous pouvez demander à l’utilisateur de la saisir, par un simple scanf). N’oubliez pas de limiter la valeur y à 255 au maximum. Testez. Faites une démonstration 4. Opération entre deux images : Modifiez votre code pour charger 2 images, puis effectuez la soustraction pixel à pixel, composante par composante, de ces 2 images (la mémoire peut être adressée de façon "linéaire", de i = 0 à i = h × w × 3. Attention, le résultat peut être négatif. Pour pouvoir visualiser des valeurs négatives, nous allons transformer le résultat de la soustraction comme suit : T = ((P1 − P2 ) × A), limiter T par un test (−128 < T < +128) puis effectuez D = T + 128. D est le résultat que vous afficherez. A est une valeur d’amplification. Si les 2 images sont identiques, l’image résultat sera grise (128). Si des différences apparaissent, leur intensité tendra vers le blanc si elles sont positives, vers le noir si elles sont négatives. Utilisez ce programme pour mettre en évidence les différences (les pertes) lors de la compression JPEG : Ouvrez votre fichier canopee_50.jpg, sauvegardez-le en BMP (canopee1.bmp), ainsi que le fichier d’origine (canopee2.bmp). Effectuez la soustraction avec votre programme. Les différences doivent être visibles (A = 5, par exemple). Faites la même opération avec canopee_100.jpg et le fichier d’origine. Concluez. Faites une démonstration A Structures de données typedef struct tagBITMAPFILEHEADER { WORD bfType; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; } BITMAPFILEHEADER, *PBITMAPFILEHEADER; typedef struct tagBITMAPINFO { BITMAPINFOHEADER bmiHeader; RGBQUAD bmiColors[1]; } BITMAPINFO, *PBITMAPINFO; typedef struct tagBITMAPINFOHEADER{ DWORD biSize; LONG biWidth; LONG biHeight; WORD biPlanes; WORD biBitCount; DWORD biCompression; DWORD biSizeImage; LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant; } BITMAPINFOHEADER, *PBITMAPINFOHEADER; 3 B extraits du code fourni // lecture fichier image PGM { FILE* fp=fopen("test1.pgm","rb"); char type[3]; int profondeur; fscanf(fp,"%s %d %d %d" ,type,&w,&h,&profondeur); printf("type de fichier : %s\n",type); printf("largeur %d x hauteur %d, max value=%d\n",w,h,profondeur); value=(unsigned char*)malloc(sizeof(unsigned char)*w*h); fread(value, sizeof(unsigned char), w*h, fp); fclose(fp); } // création d’une structure DIB vraies couleurs a partir du PGM data = (unsigned char*) malloc((h * w * 3) + sizeof(BITMAPINFOHEADER)); // mise à zero de la zone mémoire allouée ZeroMemory(data, (h * w * 3) + sizeof(BITMAPINFOHEADER)); // remplissage des champs nécéssaires dibheader = (BITMAPINFOHEADER*)data; dibheader->biSize = sizeof(BITMAPINFOHEADER); dibheader->biHeight = h; dibheader->biWidth = w; dibheader->biPlanes = 1; dibheader->biBitCount = 24; dibheader->biCompression = BI_RGB; // positionnement sur les données data = data + sizeof(BITMAPINFOHEADER); // copie des valeurs PGM dans les 3 plans for (j=0; j < h; j++) for(i=0; i < w; i++) { *data = *value; data++; *data = *value; data++; *data = *value; data++; value++; } 4