COMMENT CREER UNE LIBRAIRIE POUR Tcl ?

(Partie 2)

Cette partie va aborder l'écriture proprement dite de fonctions de traitement d'images dans une librairie pouvant être appelée depuis un script Tcl. Nous montrerons aussi comment utiliser efficacement notre extension depuis l'environnement graphique AUDACE (raapelons que ce dernier programme est écrit entièrement en Tcl et en Tk).

Nous allons travailler deux fonctions. L'une ajoute une constante à tous les pixels d'une image. L'autre effectue le fenêtrage interactif d'une zone de l'image. Les noms de commande respectifs de ces fonctions vues par l'utilisateur sont qm_offset et qm_window.

Ajoutez un nouveau fichier de code depuis l'environnement de programmation (voir la première partie de ce tutorial). Nommez ce fichier qtit1.cpp. Voici le code qu'il contient :

// Projet      : AudeLA
// Librairie   : LIBQM
// Fichier     : QTIT1.CPP
// Compilateur : Visual C++ 6.0
// Auteur      : Christian Buil
// Dernière modification : 02/04/2000
// Description : Fonctions de traitement d'images
// ==============================================

#include "libqm.h"

/********************* OFFSET ********************/
/* Ajoute ou retranche une constante à une image */
/*************************************************/

int offset(short cst,short imax,short jmax,float *p)
{
int i,taille;

if (p==NULL) return(PB);

taille=(int)imax*jmax;

for (i=0;i<taille;i++)
   {
   p[i]=p[i]+(float)cst;
   if (p[i]>32767.0)
      p[i]=32767;
   else if (p[i]<-32768.0)
      p[i]=-32768;
   }

return(OK);
}  

/************ CALC_WINDOW ****************/
/* Fenétrage                             */
/*****************************************/

short calc_window(short x1,short y1,short x2,short y2,
                  short imax,short jmax,short imax2,short jmax2,
                  float *p,float *p_out)
{
short i,j;
int adr,ptc;

if (x1==-999) return(PB);

ptc=0;
for (j=y1-1;j<y2;j++)
   {
   adr=(int)j*imax;
   for (i=x1-1;i<x2;i++,ptc++) *(p_out+ptc)=*(p+(adr+(int)i));
   }

return(OK);
}

Considérons la fonction offset. Les paramètres tous d'abord :

  • CST : c'est la constante de type entier que vous allez ajouter (ou soustraire si elle est négative) à tous les pixels de l'image.
  • (IMAX, JMAX) : c'est la taille en pixel de l'image suivant les axes horizontaux et verticaux.
  • P : c'est un pointeur qui donne l'adresse mémoire du premier pixel de l'image (notez que l'image est codée en réel sur 4 octets dans Audela (type float).

Après que l'on ai vérifier que le pointeur image est bien valide (c'est à dire qu'il pointe bien vers une zone mémoire valide), on détermine la dimension de l'image (variable TAILLE).

On entre ensuite dans une boucle qui balaye tous les pixels en y ajoutant la constante. Le calcul est effectué avec des nombres réels et on vérifie que l'on ne déborde pas la capacité de stockage d'un codage sur deux octets. On finit en répondant OK.

Rappelez-vous qu'il est nécessaire de déclarer la fonction offset dans le fichier libqm.h (nous l'avons déjà fait dans la partie 1 du présent tutorial) :

int offset(short cst,short imax,short jmax,float *p);

Ecrivons à présent la fonction CmdOffset dans le fichier qmtcl1.cpp. Cette fonction réalise le décodage des paramètres entrés par l'utilisateur :

/************************* CmdOffset ***********************/
/* Appel de la fonction 'offset'                           */
/* Ajoute une constante à l'image                          */
/***********************************************************/

int CmdOffset(ClientData clientData,Tcl_Interp *interp,int argc,char *argv[])
{
float *p;
short imax,jmax;
short sh,sb;
char s[256];
IMAGE *image;

if (argc!=2)
   {
   sprintf(s,"Usage: %s valeur", argv[0]);
   Tcl_SetResult(interp,s,TCL_VOLATILE);
   return TCL_ERROR;
   }

if (get_image_info(&image,1,interp)==TCL_ERROR)
   {
   Tcl_SetResult(interp,"Format d'image incorrect",TCL_VOLATILE);
   return TCL_ERROR;
   }
p=image->p;
imax=image->imax;
jmax=image->jmax;
sh=image->sh;
sb=image->sb;

if (offset((short)atoi(argv[1]),imax,jmax,p)==PB)
   {
   Tcl_SetResult(interp,"Calcul impossible",TCL_VOLATILE);
   return TCL_ERROR;
   }

SetResult(interp,"OK",TCL_VOLATILE);
return TCL_OK;
}

On contrôlez tout d'abord que l'utilisateur à bien fourni le nombre correct d'arguments (ici il y a un seul argument, la valeur de l'offset, mais rappelez-vous qu'il faut aussi comptabiliser le nom de la fonction) :

if (argc!=2)
   {
   sprintf(s,"Usage: %s valeur", argv[0]);
   Tcl_SetResult(interp,s,TCL_VOLATILE);
   return TCL_ERROR;
   }

On appelle ensuite la commande get_image_info qui, comme son nom l'indique, retourne des informations sur l'image actuellement en mémoire. Cette fonction, bien pratique, sera décrite plus tard. Les informations utiles sont l'adresse mémoire de l'image, ces dimensions et la valeur courante des seuils de visualisation. Il est important de préciser ici qu'il est supposé que l'image a été stockée dans la mémoire (chargée depuis le disque si on préfère) avec les outils fourni dans la bibliothèque Audela. Le processus et toutes les initialisations nécessaires sont automatiquement réalisées si vous utilisez par exemple l'interface AUDACE.

if (get_image_info(&image,1,interp)==TCL_ERROR)
   {
   Tcl_SetResult(interp,"Format d'image incorrect",TCL_VOLATILE);
   return TCL_ERROR;
   }
p=image->p;
imax=image->imax;
jmax=image->jmax;
sh=image->sh;
sb=image->sb;

La fonction de calcul d'offset est ensuite appelée :

if (offset((short)atoi(argv[1]),imax,jmax,p)==PB)
   {
   Tcl_SetResult(interp,"Calcul impossible",TCL_VOLATILE);
   return TCL_ERROR;
   }

On finit l'exécution en retournant une chaîne ('"OK") qui s'affichera à l'écran à la fin du calcul (s'il n'y a pas d'erreurs).

Tcl_SetResult(interp,"OK",TCL_VOLATILE);
return TCL_OK;

}

                      (1/4)