Accueil du site > Programmation > Conversion d’images couleur en niveaux de gris

Conversion d’images couleur en niveaux de gris

lundi 17 janvier 2005, par Pierre-Luc Bacon

Mon activité éditoriale sur ce site a été réduite ce dernier mois en raison de l’écriture d’un programme de traitement vidéo. Cet article est le premier d’une série qui s’attardera à effectuer diverses opérations de capture et de traitement de l’image. Dans ces lignes sera présenté un programme de conversion d’images en format PPM vers le format PGM.

L’algorithme de transformation de l’espace des valeurs rouge, vert et bleu en sa représentation par niveaux de gris est d’une grande simplicité à réaliser. Son importance en est pas moins considérable puisque l’espace de niveaux de gris d’une image est une étape essentielle de tous traitements car la complexité du programme et le temps de calcul s’en trouvent réduits. Cela permettra par exemple de tirer profit des filtres convolutifs du genre Prewitt ou Sobel.

Pour convertir les valeurs RGB, il suffit d’appliquer la formule suivante :

Y=R*0,299+G*0,587+B*0,114

où Y exprime le niveau de gris pour un pixel donné

Formats PNM

Ce type de format permet de coder une image dans sa plus simple expression. Le terme « PNM » est une généralisation d’un type d’images regroupant les formats réels « PBM », « PGM » et « PPM ». Ces extensions servent à définir trois types d’images : binarisées pour le PBM, en niveaux de gris pour le PGM et en couleur pour le PPM. Tous les fichiers PNM se structurent de la même manière à l’exception près du format PBM. Tout d’abord, une entête détermine le type par un « chiffre magique » (indicateur commençant par P), les dimensions de l’image et son intensité maximale. Les lignes ne peuvent dépasser plus de 70 charactères et tous commentaires doivent être précédés du symbole « # ». Les formats PNM n’introduisent aucune compression les pixels : il suffit donc d’en exprimer la valeur par RVB pour le PPM, niveau de gris dans le cas du PGM ou simplement avec des « 1 » ou « 0 » pour le PBM. Il est important de noter que pour un même format d’image peut correspondre des tailles en mémoire différentes. Cela provient simplement d’une écriture soit en mode binaire ou ASCII beaucoup plus lourde en espace. Le tableau qui suit résume ces formats et leurs indicateurs.

FormatIndicateurs (ASCII,bin.)Description
PBMP4,P1Monochome
PGMP2,P5Niveaux de gris
PPMP3,P6Couleur

Une image PPM binaire pourrait alors avoir cette forme :

P6
#Commentaire
320 292
255
[...valeurs RGB...]

Programmation

Pour accéder aux informations du fichier, il suffit d’utiliser une fonction « fopen » qui retournera un descripteur de fichier correspondant à celui ouvert ou créé. Même si l’image peut être représentée en valeurs binaires pour certains formats, il ne sera pas nécessaire d’ouvrir un fichier avec l’attribut binaire « b » ou de gérer la conversion en mode décimal soit-même.

Dans le programme présenté ici, on ouvre un fichier PPM duquel on lit les informations pertinentes qu’on retransmet ensuite dans un second fichier PGM après application de la formule de niveaux de gris. Au lancement, des arguments sur le nom du fichier source et celui produit seront exigés.

int main (int argc, char **argv)
{

 if (argc == 1)
   {
     printf ("Arguments insuffisants\n");
     printf ("nivgris [source] [destination]\n");
     return -1;
   }

 fpr = fopen (argv[1], "r");
 if (fpr == NULL)
   {
     printf ("Impossible de lire le fichier\n");
     exit (-1);
   }


 fpw = fopen (argv[2], "w");
 if (fpw == NULL)
   {
     printf ("Impossible d'ouvrir le fichier en ecriture\n");
     exit (-1);
   }

Un tableau de caractères servira de « buffer » pour comparer les informations d’entête tirées du fichier en usant d’une fonction fgets. Nous nous assurerons d’abord d’avoir affaire au bon format de fichier en regardant le chiffre magique sur la première ligne. Si un commentaire est introduit sur la seconde ligne, il sera absorbé par un fgets supplémentaire. Précision ici qu’il est important d’avoir un fichier organisé de la même manière qu’expliquée plus haut car tous commentaires situés ailleurs que sur la deuxième ligne viendra déranger l’ordre d’analyse. Bien sûr, une version plus robuste de ce programme pourrait être faite, mais rappelons qu’il doit servir d’abord de structure pour visualiser le résultat des opérations de traitement.

fgets (info, 10, fpr);
 if (strncmp (info, "P6", 2) != 0)
   {
     printf ("Mauvais format de fichier\n");
     fclose (fpr);
     fclose (fpw);
     exit (-1);
   }
 fgets (info, 70, fpr);

 if ((strncmp (info, "#", 1)) == 0)
   {
     fgets (info, 10, fpr);
   }
 sscanf (info, "%d %d", &largeur, &hauteur);
 fgets (info, 10, fpr);
 sscanf (info, "%d", &valmax);
 if (valmax > 255)
   {
     printf ("Valeur maximale trop eleve\n");
     fclose (fpr);
     fclose (fpw);
     exit (-1);
   }

Pour lire l’ensemble des pixels de l’image, nous utiliserons les informations récupérées dans l’entête pour contrôler le déroulement d’une double boucle : une première s’exécutera pour passer de ligne en ligne alors qu’une seconde avancera sur un même ligne. Une seule boucle aurait pu également être employée pour cette tache où le paramètre de contrôle serait le produit de la hauteur par la largeur.

Les valeurs RGB ainsi extraites seront utilisées pour le calcul du niveau de gris du pixel ensuite réécrit dans le second fichier. Avant d’y placer ce pixel, il aura fallu définir au prélable des informations d’entête pour l’image PGM tirées du fichier PPM à la seule différence que « P5 » sera utilisé plutôt que « P6 ».

fprintf (fpw, "P5\n%d %d\n%d\n", largeur, hauteur, valmax);
 int x, y;
 unsigned char r, g, b, niv;

 for (y = 0; y < hauteur; y++)
   {
     for (x = 0; x < largeur; x++)
       {
         r = fgetc (fpr);
         g = fgetc (fpr);
         b = fgetc (fpr);
         niv = r * 0.299 + 0.587 * g + 0.114 * b;
         putc (niv, fpw);
       }
   }

Les fichiers sont finalement fermés et la fonction main retourne.

fclose (fpr);
 fclose (fpw);
 return 0;

Pour compiler, utilisez cette commande :

gcc -Wall niv_gris.c -o nivgris

Une fois l’exécutable créé, le lancement se fera ainsi :

./nivgris fichiersource.ppm fichiersortant.pgm

Ce code peut certainement constituer une base efficace pour tester le résultat de différents filtres d’images. Le passage d’une image de type RGB en niveaux de gris permettra l’application de méthodes de calcul de gradients pour l’extraction de contours. Cette prochaine étape sera d’ailleurs détaillée dans l’article suivant de cette série.

JPEG - 11.2 ko
Image originale
JPEG - 7.5 ko
Résultat

Documents joints

Enregistrer au format PDF
Marquer cet article: Delicious Technorati

Répondre à cet articleRépondre à l'auteur:Pierre-Luc BaconRecommander à un ami

8 Messages de forum