Les Bases du Traitement d'Image

Partie 6 : L'Environnement EdEnviTI et son utilisation

Ce document est la sixième et dernière partie intitulée « l'Environnement Logiciel de Traitement d'Image EdEnviTI : Principe et Programmation », du cours : « Les Bases du Traitement d'Image et de la Vision Industrielle et Robotique ».

Dans cette dernière partie, nous présentons l'environnement logiciel de traitement d'image EdEnviTI dans lequel sont implantés TOUS les opérateurs des parties précédentes, constituant la bibliothèque EdVision. Nous détaillons ensuite la façon de l'utiliser :

  • comment compiler et exécuter un opérateur (fichiers nécessaires) ;
  • comprendre les codes des différentes parties ;
  • comment programmer un nouvel opérateur, en recopiant puis modifiant les fichiers constituant l'opérateur fourni en exemple dans l'environnement.

Enfin, nous donnerons quelques conseils dans le cadre de l'approfondissement de ce cours.

N'hésitez pas à me donner votre avis sur le contenu de ce cours dans le forum d'entraide sur l'imagerie : 14 commentaires Donner une note à l'article (5).

Article lu   fois.

L'auteur

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Introduction

I-A. Qu'est-ce qu'un environnement de traitement d'image ?

L'Environnement Logiciel de Traitement d'Image EdEnviTI dans lequel les opérateurs de cet ouvrage sont réalisés est constitué :

  • de la définition des structures de données (cf. Partie 2 de ce cours intitulée : « Visualisation des Images et Opérateurs Simples ») : point (EdPOINT), image (EdIMAGE) ;
  • des macros de création des structures de données, et d'accès aux divers champs ;
  • des fonctionnalités de base : création/libération de la mémoire des données, lecture/écriture d'une image (entête et données).

C'est un logiciel de fabrication « MAISON », sans prétention, mais qui a déjà fait ses preuves au niveau de son efficacité, comme nous allons le voir par la suite. Les détails de sa conception et de sa réalisation sont présentés dans notre ouvrage(1).

I-B. Quel est l'intérêt ?

L'intérêt d'un tel environnement est double :

  • pédagogique ;
  • et économique.

I-B-1. Intérêt pédagogique

Cet environnement se veut pédagogique dans le sens où il a pour but de permettre à un étudiant d'un niveau moyen(2) en langage C de réussir à implanter ses propres opérateurs. Ainsi, la difficulté, c'est-à-dire l'accès aux champs des données grâce à l'utilisation de pointeurs est totalement masquée. Le rôle de l'environnement va être de fournir des « fonctions » d'accès, avec des noms explicites, qui seront pour des raisons de rapidité d'exécution fournies sous forme de MACROS.

L'étudiant peut alors concentrer son effort sur la conception de l'algorithme, car l'implantation lui a été rendue aisée :

  • d'une part par les fonctionnalités de base fournies. En effet, partir de zéro, c'est-à-dire refaire un tel environnement serait plus complexe que la programmation des opérateurs de base (opérateurs de seuillage, de lissage, ou de morphologie mathématique : érosion, dilatation) ;
  • d'autre part par la fourniture d'un exemple, ici l'opérateur de lissage moyen, dont la compréhension de l'implantation ne nécessite qu'un niveau moyen en langage C. Il s'agira seulement d'adapter le code fourni pour implanter d'autres opérateurs, ce que nous verrons dans cette partie.

I-B-2. Intérêt économique

J'ai découvert cette manière de travailler en arrivant au laboratoire de recherche Systèmes de Perception : SP(3)de l'Établissement Technique Central de l'Armement : ETCA en 1986. La conception et la réalisation d'un Environnement de Programmation(4) étaient l'un des axes de recherche de l'équipe Algorithmie, qui a permis la soutenance de plusieurs doctorats. C'est une manière de travailler que l'on retrouve également en industrie aujourd'hui.

En effet, supposons une équipe de chercheurs ou de développeurs industriels en imagerie. Chacun de ses membres a pour objectif de développer des algorithmes de traitement d'image. Pour ce faire chacun a à utiliser certaines fonctionnalités telles que :

  • la manipulation des données telles qu'une image, un point, etc. ;
  • la création, la lecture, l'écriture d'une image ;
  • la lecture, l'écriture d'un pixel d'une image source ou résultat.

Si chacun écrit ses propres fonctionnalités :

  • d'une part, beaucoup de travail inutile aura été effectué, car un seul membre aurait pu s'en charger pour l'équipe ;
  • d'autre part, chacun a créé ses propres fonctionnalités avec son cahier des charges, des noms et des paramètres qui lui sont propres, d'où une très mauvaise cohérence du logiciel global. En effet, il sera quasiment impossible de faire interagir les développements logiciels des différents développeurs. Un utilisateur voulant se plonger dans la bibliothèque globale verra la même fonctionnalité avec d'une part des noms différents dans chacun des programmes, mais également, d'autre part, des paramètres d'appels différents, ainsi que des fonctionnements légèrement différents.

Ainsi, l'utilisation d'un tel environnement, qu'il soit conçu et réalisé par l'équipe de la société, ou autres (environnements gratuits OpenCV, CLEOPATRE, EdEnviTI ou commerciaux Khoros (Coral), LabView (National Instrument), Matlab, etc.) regroupant au minimum les fonctionnalités « usuelles » du « Programmeur en Traitement d'Image », permet :

  • d'éviter la multiplication de développements algorithmiques inutiles ;
  • d'assurer une cohérence de l'ensemble du logiciel, grâce à la standardisation.

I-B-3. Intérêts autres : « légèreté » et efficacité

L'objectif de l'environnement de traitement d'image EdEnviTI fourni sur le site web « www.developpez.com » est d'aider le développeur, mais sans trop le contraindre. Ainsi, il se doit d'être léger, c'est-à-dire simple d'utilisation et minimal, pour en permettre des évolutions et adaptations.

EdEnviTI a prouvé son efficacité. Conçu et réalisé initialement pour des besoins pédagogiques(5) , je l'ai ensuite utilisé pour mes propres développements de recherche pour sa simplicité et son efficacité. Coder simplement sans se soucier des structures de données manipulées et notamment des combinaisons de pointeurs lors des accès aux données, permet de gagner en efficacité.

En effet, effectuant des recherches notamment sur l'optimisation algorithmique et de l'implantation des opérateurs, je travaille en deux étapes :

  • le développement de l'algorithme, sans optimisation temporelle de l'implantation, en utilisant l'environnement logiciel : cette étape permet d'obtenir une solution assez rapidement. Si cette solution est satisfaisante, elle devient la solution de référence, et permet de passer à la seconde étape. Si cette solution ne s'avère pas satisfaisante, elle serait à reprendre en modifiant l'algorithme ;
  • l'optimisation temporelle de l'implantation, notamment en jouant sur un accès rapide aux données à l'aide d'une manipulation efficace des pointeurs. Les résultats obtenus par cette seconde implantation sont comparés à ceux de la solution de référence, ce qui permet de valider cette seconde implantation, beaucoup plus complexe et délicate.

Chacune des deux optimisations, ainsi séparée, peut être correctement évaluée. D'autre part, la recherche des problèmes (ou bogues de programmation) est grandement simplifiée.

Enfin, cet environnement, écrit en langage C « propre » est compatible C++(6).

II. Utilisation de l'environnement EdEnviTI

II-A. Composition de l'environnement

L'environnement logiciel EdEnviTI comporte six fichiers :

  • trois fichiers de l'environnement proprement dit, c'est-à-dire des fichiers à utiliser avec TOUT opérateur développé dans l'environnement :

    • EdStructures.h : contenant les structures de données, et les macros définitions de création et d'accès aux champs des données,
    • EdUtilities.c : contenant le code source en langage C des fonctionnalités de l'environnement et EdUtilitaires.h, contenant les prototypes correspondants ;
  • trois fichiers, relatifs à un opérateur particulier, par exemple le lissage moyen, détaillé lors de la seconde partie :

    • EdMeanFiltering.c : code source en langage C, dans l'environnement EdEnviTI, de la partie Interface avec l'utilisateur,
    • EdLibMeanFiltering.c : code source de l'opérateur « proprement dit », et EdLibMeanFiltering.h contenant le prototype de la fonction.

II-B. Exemple du filtrage moyen

II-B-1. Utilisation

Dans les deux cas d'utilisation : sous les systèmes d'exploitation Windows et Linux, nous conseillons de créer un répertoire TImage(7), comportant quatre répertoires, deux pour les logiciels, deux pour les images :

  • src : stockant les fichiers source : « .c », et « .h », donc notamment les six fichiers mentionnés ci-dessus ;
  • Projet (Windows) ou bin (Linux) : stockant sous Windows les projets (« .dev » en DevCpp, « .blk » sous CodeBlock), ainsi que les exécutables « .exe » sous Windows et sans extension sous Linux ;
  • Image : contenant les images à traiter ;
  • ImRes : contenant les images traitées ou résultats. L'utilisation de ce répertoire évite l'écrasement malheureux de l'image source, résultant d'une fausse manipulation.

Le mode opératoire pour compiler les codes source constituant l'opérateur de lissage moyen est le suivant :

  • Windows : que l'on utilise DevCpp, ou CodeBlocks, il faut créer un projet C, en mode « console » contenant les trois fichiers « .c » : EdMeanFiltering.c (contenant le programme principal : main()), EdLibMeanFiltering.c, EdUtilities.c. Les trois fichiers « .h » : EdStructures.h, EdUtilities.h, et EdLibMeanFiltering.h sont inclus par l'instruction « #include «   » ». Il suffit ensuite de lancer la compilation : « Build ».
  • Linux : il faut compiler « à la main » à l'aide des commandes suivantes, réalisant la compilation des sources : EdUtilities.c, EdMeanFiltering.c et EdLibMeanFiltering.c, puis l'édition de lien permettant l'obtention de l'exécutable EdMoyen, et enfin le transfert de l'exécutable dans le répertoire « bin » puis le nettoyage : destruction des fichiers objets « .o » inutiles.
 
Sélectionnez
      gcc -c EdUtilities.c
    gcc -c EdMeanFiltering.c
    gcc -c EdLibMeanFiltering.c
    gcc -o EdMeanFiltering EdMeanFiltering.o EdLibMeanFiltering.o EdUtilities.o
    mv EdMeanFiltering ../bin/
    rm *.o

Dans les deux cas, l'exécution (ou utilisation de l'opérateur) est réalisée à partir d'une console. Sous Linux, l'utilisation des consoles est naturelle. Sous Windows, il faut taper la commande « cmd » dans le menu « exécuter ».

Enfin pour obtenir le résultat tant espéré il faudra sous le répertoire contenant l'exécutable :

  • Linux : taper(8) :
 
Sélectionnez
./EdMeanFiltering ../Image/NomImageSrc.pgm ../ImRes/NomImageRes.pgm
  • Windows : taper la même ligne, sauf « ./ » pour l'exécutable, et remplacer les séparateurs « / » par « \ » dans les chemins pour accéder aux fichiers images, soit :
 
Sélectionnez
EdMeanFiltering ..\Image\NomImageSrc.pgm ..\ImRes\NomImageRes.pgm

Il est possible d'obtenir cette ligne de manière plus simple à l'aide du glisser/déposer appliqué successivement à chacun des trois éléments.

Les images de Lenna, en version originale : Lenna.pgm, ou bruitée : LennaNoise.pgm peuvent être prises pour visualiser l'effet du lissage Mmoyen. On observe, sur l'image bruitée une diminution notable du bruit, mais également une dégradation de la netteté de l'image, c'est-à-dire un effet de flou, notamment au niveau des détails : plumes et bords du chapeau.

II-B-2. Détails pour l'opérateur lissage moyen

Interface utilisateur 

Les lignes ci-dessous détaillent la partie « Interface Utilisateur » de l'opérateur de lissage moyen : fichier EdMeanFiltering.c.

Cette partie est la même, à l'exception près de l'appel de l'opérateur proprement dit, pour tout opérateur réalisant son traitement à partir d'une image source, et ayant une image résultat pour unique sortie.

Il faut commencer par inclure les trois fichiers « header (ou .h) » : deux de l'environnement, le troisième de l'opérateur :

 
Sélectionnez
#include "EdStructures.h"
#include "EdUtilities.h"
#include "EdLibMeanFiltering.h"

Ensuite, il faut en langage C, dans le programme principal ou main()déclarer toutes les variables utilisées de types :

  • pour réaliser des calculs : octets, réels, etc. ;
  • chaînes de caractères ;
  • descripteurs de fichiers ;
  • pointeurs sur les structures de données : par exemple EdIMAGE et EdPOINT.
 
Sélectionnez
int main(int argc, char **argv)
{
  /* --- Declarations --- */
  EdIMAGE       *image = NULL,*imres = NULL;
  int           nlig = 0, ncol = 0;
  unsigned char prof = 0;
  FILE          *fichier = NULL, *fichres = NULL;
  int           ret;
  
  /* --- Suite Programme de l'Interface  --- */
  
  /* ---  Fin de l'operateur --- */    
  fprintf(stderr,"End of MeanFiltering operator\n");
  system("PAUSE"); // Windows Only
  exit(0) ;
}

Après les déclarations, le « Usage » (ou manière d'utiliser) a un double rôle :

  • de contrôler le nombre de paramètres transmis. C'est un premier contrôle très simple qui permet de ne pas continuer si les paramètres dont a besoin le programme ne sont pas transmis. Les paramètres sont, dans le cas présent, les noms des images source et résultat. Comme le système d'exploitation compte également le nom de la commande, c'est-à-dire l'exécutable, ce nombre est de trois ;
  • d'informer l'utilisateur des paramètres à transmettre à l'opérateur, si ceux-ci n'ont pas été transmis en nombre correct.

Pour des traitements complexes comportant un certain nombre de paramètres, cette fonctionnalité est très pratique.

 
Sélectionnez
if(argc != 3)
{
    fprintf(stderr,"USAGE :  PMeanFiltering image immoy \n");
    fprintf(stderr,"image : name of the image to filter \n");
    fprintf(stderr,"immoy : name of the result image \n");
    fprintf(stderr,"Smooth Filtering by Mean Filter of B&W image \n");
    system ("PAUSE"); // Windows Only
    exit(0);
}

Les fichiers des images source et résultat sont ensuite ouverts, ce qui donne lieu à un second contrôle. Le fichier de l'image source est ouvert en lecture : option « r », celui de l'image résultat est ouvert en écriture : option « w ». Attention, sous Windows uniquement(9), il faut ouvrir les deux fichiers en binaire : option « b », soit « rb » et « wb », sinon l'image n'est pas entièrement lue, ce qui n'est malheureusement pas détecté par les « sécurités » mises en œuvre par les fonctionnalités de lecture et d'écriture !

 
Sélectionnez
  /* --- Source Image --- */
  if(!(fichier = fopen(*++argv,"rb")))
  {
    fprintf(stderr,"Source Image %s Pb of Opening\n",*argv);
    system ("PAUSE"); // Windows Only
    exit(0);
  } 
  /* --- Result Image  --- */
  if(!(fichres = fopen(*++argv,"wb")))
  {
    fprintf(stderr,"Result Image %s Pb of Opening\n",*argv);
    system ("PAUSE"); // Windows Only
    exit(0);
  }

On obtient une erreur d'ouverture sur l'image résultat (ouverte en écriture) si trop de fichiers sont simultanément ouverts, ce qui a peu de chances d'arriver. En revanche, une erreur d'ouverture sur l'image source (ouverte en lecture) arrive si cette image n'existe pas, ou n'est pas au bon emplacement, ce qui arrive de temps en temps.

La lecture de l'entête permet d'obtenir la résolution de l'image : son nombre de lignes, et son nombre de colonnes. Seuls deux types de fichiers images peuvent être lus, aux formats(10) :

  • PGM, i.e. en niveaux de gris d'extension « .pgm » ;
  • PPM, i.e. en couleur : RVB, d'extension « .ppm ».

La fonction de lecture de l'entête renvoie la valeur « 0 » pour une lecture correcte, des valeurs différentes en cas de problèmes.

 
Sélectionnez
  /* --- Reading of Image Header --- */
  if ((ret = Reading_ImageHeader(fichier, &ncol, &nlig, &prof)))
  {
    fprintf (stderr, "Problem of Reading Image Header \n");
    system("PAUSE");
    exit(0);
  }
  fprintf(stderr, "Size of the Image : %d lines x %d colums : Type : %d\n", 
    nlig,ncol, (int)prof);  
  if (prof != 1)
  {
    fprintf(stderr," the source image is not a B&W image \n");
    system ("PAUSE"); // Windows Only
    exit(0);
  }

Les structures EdIMAGE sont ensuite créées : la partie entête par la macro crea_IMAGE(), puis la partie pixels de l'image par la fonction Creation_Image() qui remplit également les champs de l'entête.

 
Sélectionnez
  /* --- Creation of Image Headers and Data --- */
  if (crea_IMAGE(image) == NULL)    /* creation of Image Header  */
  {
    fprintf(stderr,"Error of Memory Allocation  \n");
    system ("PAUSE"); // Windows Only
    exit (0);
  }
  ret = Creation_Image (image, nlig, ncol, prof); // Image Data
  if (!ret)
  {
    fprintf(stderr,"Error of Memory Allocation of Pixels  \n");
    system ("PAUSE"); // Windows Only
    exit (0);
  }
 
  if (crea_IMAGE(imres) == NULL) 
  {
    fprintf(stderr,"Error of Memory Allocation  \n");
    system ("PAUSE"); // Windows Only
    exit (0);
  }
  ret = Creation_Image (imres, nlig, ncol, prof);
  if (!ret)
  {
    fprintf(stderr,"Error of Memory Allocation of Pixels  \n");
    system ("PAUSE"); // Windows Only
    exit (0);
  }

L'image est ensuite lue grâce à la fonction Reading_ImageData() : les données des pixels de l'image sont transférées du fichier image, stocké sur disque dur, en mémoire vive (ou RAM) .

 
Sélectionnez
  /* --- Reading of Image Data from file to Memory --- */
  ret = Reading_ImageData(fichier,image); // Image Pixel Data
  if (!ret)
  {
    fprintf(stderr,"Problem of Reading \n");
    system ("PAUSE"); // Windows Only
    exit(0);
  }

L'opérateur est appelé par l'instruction : « MeanFiltering (image, imres); » .

 
Sélectionnez
  /* --- Smoothing by Mean Filtering --- */
  ret = MeanFiltering (image, imres);
  if (ret != 0)
  {
    fprintf(stderr,"Error of Memory Allocation in MeanFiltering Operator \n");
    system ("PAUSE"); // Windows only
    exit(0);
  }

L'image résultat est stockée dans un fichier : Entête (écriture directe par fprintf()) et Pixels (par la fonction Writing_ImageData()).

 
Sélectionnez
/* --- Writing of the Image Result in File --- */
  fprintf(fichres,"P5\n#creating by EdEnviTI\n%d %d\n255\n",
    (int)ncol, (int)nlig); // Header 
  ret = Writing_ImageData(fichres, imres); // Image Pixel Data
  if (!ret)
  {
    fprintf(stderr,"Problem of Writing \n");
    system ("PAUSE"); // Windows Only
    exit(0);
  }

Ensuite, l'espace mémoire dynamiquement alloué est libéré par la fonction Free_Image(), puis les fichiers de type image sont refermés.

 
Sélectionnez
 /* --- Free of Images --- */
  ret = Free_Image(image);
  if(ret == FALSE)
  {
    fprintf(stderr,"Problem of Free the Memory \n");
  }
  ret = Free_Image(imres);
  if(ret == FALSE)
  {
    fprintf(stderr,"Problem of Free the Memory \n");
  }
  fclose (fichier);
  fclose (fichres);

II-B-3. Opérateur « proprement dit »

Il faut commencer par inclure les deux fichiers « header (ou .h)" » de l'environnement. L'opérateur de filtrage moyen se présente comme une fonction «  MeanFiltering() » à deux paramètres : les images d'entrée et de sortie, qui renvoie un code d'erreur :

  • 0 : en cas de fonctionnement correct ;
  • 1 si problème d'allocation de mémoire pour les deux structures de type EdPOINT.

Nous avons généralisé cette présentation des opérateurs. Les opérateurs plus complexes renvoient d'autres codes d'erreur.

 
Sélectionnez
#include "EdStructures.h"
#include "EdUtilities.h"

int MeanFiltering(EdIMAGE *image, EdIMAGE *imres)

Avant d'entrer dans le vif des traitements, et de manière à pouvoir accéder aux valeurs des pixels courant et voisin (du voisinage 3 x 3 centré autour du pixel courant) par la macro PIXEL(), il faut allouer deux structures EdPOINT, à partir de deux pointeurs : point et pointv.

 
Sélectionnez
  /* current and neighbour (voisin in French) points */
  EdPOINT    *point = NULL, *pointv=NULL; 
  if(crea_POINT(point) == NULL)     /* Memory Allocation of point */
  {
     fprintf(stderr,"Error of Memory Allocation \n");
     return 1; 
  }
  if(crea_POINT(pointv) == NULL) 
  {
     fprintf(stderr,"Error of Memory Allocation \n");
     return 1;
  }

Comme le balayage vidéo avec examen du voisinage 3 x 3 centré ne s'applique pas sur les bords, il est usuel, dans les opérateurs de lissage de recopier pour les bords de l'image résultat les pixels de l'image originale. Ainsi, l'extrait de code suivant recopie les première et dernière lignes, puis les première et dernière colonnes.

 
Sélectionnez
  /* --- Initialisation of Image Borders : Copy of the Original Image  --- */
  for(POINT_X(point) = 0; POINT_X(point) < NCOL(image); 
           POINT_X(point)++)
  {
    POINT_Y(point) = 0;                  /* first line */
    PIXEL(imres, point) = PIXEL(image, point);

    POINT_Y(point) = NLIG(image) - 1;    /* last line */
    PIXEL(imres, point) = PIXEL(image, point);
  } /*--- End of copy of first and last lines --- */ 

  for(POINT_Y(point) = 0; POINT_Y(point) < NLIG(image); 
           POINT_Y(point)++)
  {
    POINT_X(point) = 0;                  /* first column */
    PIXEL(imres, point) = PIXEL(image, point);

    POINT_X(point) = NCOL(image) - 1;    /* last column */
    PIXEL(imres, point) = PIXEL(image, point);
  } /*--- End of copy of first and last columns --- */

Nous reconnaissons dans l'extrait de code suivant, le code du balayage vidéo, avec examen du voisinage 3 x 3 centré, présenté dans le second article. La variable mean (n'est pas de type unsigned char bien évidemment, mais de type int par exemple) est initialisée à zéro, avant le parcours du voisinage. Le cumul des intensités des pixels du voisinage est réalisé dans cette variable. La moyenne est calculée en divisant ce cumul par le nombre de points du voisinage, c'est-à-dire 9. Cette valeur est ensuite stockée dans le pixel courant, de type unsigned char de l'image résultat. Le changement explicite de type, ou « Cast » de la ligne : « PIXEL(imres, point) = (unsigned char)mean; » permet d'éviter un « Warning » lors de la compilation(11).

 
Sélectionnez
/* --- Video Scan of the image, except the Border :
         Smooting by Mean Filtering  --- */    
  for(POINT_Y(point) = 1; POINT_Y(point) < NLIG(image) - 1; 
           POINT_Y(point)++)
  for(POINT_X(point) = 1; POINT_X(point) < NCOL(image) - 1; 
           POINT_X(point)++)
  {
    mean = 0;    /* initialisation  */
    /* ---  Video Scan of the 3x3 neighbourhood --- */
    for(j = 0; j < 3; j++)
    for(i = 0; i < 3; i++)
    {
      /* Computation of the Image Coordinates of the Neighbour point */
      POINT_X(pointv) = POINT_X(point) + i - 1;
      POINT_Y(pointv) = POINT_Y(point) + j - 1;            
      mean += (int)PIXEL(image, pointv); 
    } /* --- End of the Neighbourhood Video Scan --- */
    mean /= 9;/* Normalisation : At the end ! */
    PIXEL(imres, point) = (unsigned char)mean;
  }/* --- End of the Image Video Scan --- */
  /* --- Memory Free  --- */
  free((void *)pointv);
  free((void *)point);
  return 0;

II-C. Comment créer un nouvel opérateur ?

Le but de ce paragraphe est la réalisation d'un nouvel opérateur, par exemple le lissage gaussien en utilisant le code source du lissage moyen que nous allons modifier. Cette manière de procéder sera la même à chaque création d'un nouvel opérateur.

Il faut commencer par recopier les trois fichiers propres à l'opérateur :

  • Interface : EdMeanFiltering.c en EdGaussianFiltering.c ;
  • Opérateur : EdLibMeanFiltering.c et EdLibMeanFiltering.h en respectivement EdLibGaussianFiltering.c et EdLibGaussianFiltering.h.

Ensuite, il faut utiliser le même mode opératoire avec le filtre gaussien, que nous venons de le voir avec le filtre moyen.

II-C-1. Modifications du fichier EdGaussianFiltering.c

Pour des raisons de cohérence, il vaut mieux modifier :

  • le cartouche initial : le filtrage gaussien remplace le filtrage moyen ;
  • il en est de même pour la partie « USAGE », les commentaires d'appel et de fin de l'opérateur.

En revanche, il est impératif de modifier :

  • pour l'inclusion : le nom fichier prototype EdLibMeanFiltering.h par EdLibGaussianFiltering.h ;
  • pour l'appel de l'opérateur : MeanFiltering() par GaussianFiltering().

II-C-2. Modifications du fichier EdLibGaussianFiltering.h

Une seule petite modification est impérative à réaliser : le nom de l'opérateur : MeanFiltering() par GaussianFiltering(), en plus de la modification du cartouche qui est optionnelle.

II-C-3. Modifications du fichier EdLibGaussianFiltering.c

À part les modifications déjà rencontrées du cartouche (facultative) et du nom de l'opérateur, il est plus cohérent de changer le nom de la variable de cumul, mean en gauss. En effet, le nom des variables se veut d'être explicite : le calcul est ici de la valeur gaussienne et non de la valeur moyenne. Les deux seules vraies modifications au niveau de l'opérateur sont, comme cela a été mentionné lors du second article, pour l'algorithme :

  • l'ajout au cumul de la valeur du point courant, à l'issue du parcours du voisinage ;
 
Sélectionnez
gauss += (int)PIXEL(image, point);
  • la normalisation par 10, au lieu de 9.
 
Sélectionnez
gauss /= 10;/* Normalisation : At the end ! */

Remarquons qu'il est très simple de passer d'un opérateur à un autre pour des opérateurs de lissage, mais également de morphologie mathématique : érosion, dilatation…

Mais, il ne faudrait pas croire à la simplicité de tous les opérateurs de traitement d'images. Certains sont beaucoup plus compliqués. Ainsi, il ne faut pas non plus tomber dans le piège de certains commerciaux qui vendent leur bibliothèque de traitement d'images « au poids », c'est-à-dire au nombre d'opérateurs, sachant qu'il y en a des simples que l'on développe en moins de dix minutes… et des très compliqués (cf. le troisième article de la série) qui nécessitent pour leur conception et leur réalisation une bonne partie des trois années de travaux d'un doctorat ! Ce temps ne comporte pas que le développement de la solution finale, l'algorithme étant donné. Il comporte notamment toutes les solutions conçues, implantées testées, améliorées… avant d'être abandonnées, qui ont permis la conception de la solution finale.

II-D. Utilisation générale

L'intérêt d'avoir séparé l'interface utilisateur de l'opérateur proprement dit est la possibilité de réaliser des opérateurs plus complexes à partir d'opérateurs simples, en modifiant uniquement la partie interface, qui va appeler un certain nombre d'opérateurs plus simples.

Comme nous l'avons vu lors du cinquième article, la détection de contours limitée à l'étape d'affinage incluse enchaîne le calcul du gradient, le seuillage sur la norme et l'affinage des contours. Le code du fichier EdGradientThinning.c de la bibliothèque EdVision enchaîne :

  • le calcul du gradient, selon trois algorithmes possibles :

    • Prewitt (GradientPrewitt (image, imnorm, imarg)),
    • Sobel (GradientSobel (image, imnorm, imarg)),
    • et Kirsh (GradientKirsh4 (image, imnorm, imarg)) à quatre directions,
  • le seuillage sur la norme du gradient (ClassicThreshold (imnorm, impts, thH)) ;
  • et l'affinage des contours (ThinningEdges (imnorm, imarg, impts)).

Pour une détection de contours allant jusqu'à l'obtention de Lignes Polygonales ou Segments, il faut ajouter les trois étapes de Prolongation (ou Fermeture), de Chaînage des Contours puis d'Approximation Polygonale.

Ainsi, un opérateur peut avoir une ou plusieurs images en entrée et en sortie, ainsi que des données numériques en entrée et sortie. Des paramètres de contrôle, tels que des valeurs de seuils et autres peuvent également être passés par la ligne de commande et être récupérés par les fonctions C : atoi() pour un nombre entier, atof() pour un nombre réel simple.

III. Conclusion

III-A. De la sixième et dernière partie

Dans cette dernière partie, nous avons présenté l'environnement logiciel de traitement d'image EdEnviTI dans lequel sont implantés TOUS les opérateurs des parties précédentes, constituant la bibliothèque EdVision. Les codes source de l'environnement EdEnviTI, des opérateurs de la bibliothèque EdVision, ainsi qu'un certain nombre d'images sont disponibles sur le site web « www.developpez.com ». Nous avons ensuite détaillé la façon de l'utiliser :

  • comment compiler et exécuter un opérateur (fichiers nécessaires) ;
  • comprendre les codes des parties « interface » (fichier EdOperateur.c) et « opérateur proprement dit » (fichier EdLibOperateur.c) ;

comment programmer un nouvel opérateur (exemple « GaussianFilter »), en recopiant puis modifiant les fichiers constituant l'opérateur (« FMeanFilter ») fourni en exemple dans l'environnement.

III-B. Du Cours

Cette dernière partie est la fin du cours intitulé « Les Bases du Traitement d'Image et de la Vision Industrielle et Robotique », cours à vocation « Tout Public » ou accessible à des étudiants de niveau DUT/BTS /« Bachelor » de filières technologiques (GEII, GIM, GMP, R&T pour les DUT) non informaticiennes.

Dans les cinq premiers articles nous avons présenté :

  • une longue, mais nécessaire introduction à l'imagerie : les domaines d'applications, ainsi que le métier (première partie) ;
  • un certain nombre d'opérateurs simples de par la régularité des calculs :

    • de visualisation, prétraitements des images (seconde partie),
    • une première chaîne complète, i.e. réalisant une application simple (quatrième partie),
    • de segmentation en contours (cinquième partie).

III-C. Quelques conseils

La « conception et le développement d'opérateurs de Vision » ne s'apprenant pas uniquement à la lecture d'un cours : un cours d'image n'est pas un roman, je vous conseille, dans le but d'approfondir ce cours de programmer par vous-même dans un premier temps les opérateurs présentés et de comparer votre solution aux codes de la bibliothèque EdVision. C'est ce que l'on appelle dans notre jargon « la Pédagogie par Projet ».

Nous avons testé cette année à l'ISTY(12), dans le cadre d'un projet pédagogique commun entre les étudiants/apprentis de seconde année du cycle d'ingénieurs de nos départements : « Informatique » et « Mécatronique », pour cette année, incluant en plus « Systèmes Électroniques Embarqués » à partir de l'an prochain, ce type de pédagogie. Nous avons choisi le domaine de la « Robotique contrôlée Vision »(13), et plus particulièrement :

  • la robotique mobile et autonome ;
  • la robotique en interaction avec l'homme.

Pour la plupart des projets, la vision était embarquée sur une carte Raspberry PI 2. Les bibliothèques OpenCV (version 3.0.0) et EdVision ont été mises à disposition.

L'intérêt de cette pédagogie est la confrontation quasi immédiate avec la dure réalité, notamment en termes de :

  • choix des opérateurs en fonction de leur complexité en termes de puissance de calcul nécessaire, impliquant une résolution réduite au quart du format VGA : 320 x 240 pour obtenir un traitement à la cadence vidéo ;
  • réglage des nombreux paramètres, dont l'utilisation est généralement malheureusement floue dans la documentation d'OpenCV.

IV. Remerciements

Avec la fin de ce cours composé de six parties, je tiens à renouveler mes remerciements à l'ensemble du Comité de rédaction de « Developpez.com », et tout particulièrement Francis Walter pour ses précieux conseils et encouragements, Claude Leloup pour sa minutieuse relecture orthographique et typologique, Djibril et f-leb pour leur aide à la mise en forme et utilisation des divers outils d'écriture. Cela a été un plaisir de travailler avec vous pour la publication de ce cours.

V. Bibliothèques fournies

À l'issue de ce cours, nous fournissons avec cette dernière partie, deux bibliothèques :

Les opérateurs de la bibliothèque EdVision sont développés dans l'environnement EdEnviTI. Les codes source sont dans le répertoire « src », et les projets configurés dans le répertoire « Projet ». Ils sont configurés dans l'environnement de développement Bloodshed Dev C++, en version 4.9.9.2 compatible Windows 7. Pour Windows 8 et 10, il faut utiliser une version plus récente 5.X et recompiler les projets. Pour Linux, il faut compiler les fichiers à l'aide de gcc, en vous inspirant du fichier Alire.txt.

Les algorithmes des opérateurs sont détaillés dans la partie II de l'ouvrage « Les bases du traitement d'image et de la vision industrielle et robotique » (aux éditions Lulu.com : http://www.lulu.com/spotlight/bonnin) qui contient également un certain nombre d'exercices, sujets d'évaluations. Leurs codes source sont détaillés dans la partie III.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   


« Les Bases du Traitement d'Image et de la Vision Industrielle et Robotique », Patrick Bonnin, auto édition Lulu : www.lulu.com.
L'étudiant possède les bases du langage C : les instructions élémentaires, les instructions de structures algorithmiques : tests, boucles, mais ne maîtrise pas ni les structures de données complexes, ni la notion de pointeurs.
dont le Directeur Scientifique était le Pr Bertrand Zavidovique, mon directeur de doctorat.
EdEnviTI en est une version minimale, très très très… simplifiée.
Faire développer les codes source en langage C des opérateurs de base : seuillages, filtres lisseurs : gaussien, médian, le moyen étant donné en exemple, les opérateurs de morphologie mathématique : érosion, dilatation, ouverture, fermeture en imagerie binaire, par un public d'étudiants en seconde année d'IUT en département GEII.
À la modification près des prototypes complets C du style « int fonction(void) », en prototype C++ : « int fonction() ».
Pour ne pas avoir de difficulté sous Windows avec DevCpp, ce répertoire doit être proche de la racine d'un disque. Les emplacements tels que le Bureau et Mes Documents ainsi que les répertoires dont le nom comporte un espace sont INTERDITS.
« ./ » : signifie sous Linux que la commande se trouve dans le répertoire courant.
mais fonctionne également correctement sous Linux.
Pour d'autres formats, utiliser par exemple IrFan View sous Windows, pour les transformer en PGM ou PPM.
En effet, il faut autant que faire se peut, obtenir une compilation exempte de « warning ». Dans bien des cas où les exécutables n'ont pas le comportement attendu, un des « warnings » explique l'erreur.
ISTY : Institut des Sciences et Techniques des Yvelines, l'École Publique d'Ingénieurs de l'Université de Versailles Saint-Quentin.
i.e. nos domaines de recherche, Pierre Blazevic (Directeur de l'École) et moi-même (Chef du Département Systèmes Électroniques Embarqués).
À l'exception de la décomposition en composantes connexes (ou blob detection).

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2016 Patrick Bonnin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.