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