Etudions à présent la fonction C qui a pour charge d'effectuer le fenêtrage (c'est à dire une fonction qui isole une portion d'une image dans une nouvelle image). Voici la procédure de calcul (à coder par exemple dans le fichier qtit1.cpp) :

/************ CALC_WINDOW ****************/
/* Fenêtrage                             */
/*****************************************/
short calc_window(short x1,short y1,short x2,short y2,
                  short imax,short jmax,short imax2,short jmax2,
                  short *p,short *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);
}

La fonction calc_window est simple. Mais il est important de noter que l'on passe en paramètre deux pointeurs. L'un donne l'adresse de l'image sur laquelle va porter l'opération de fénêtrage, l'autre désigne l'adresse d'une zone mémoire dimensionnée correctement pour contenir l'image fenêtrée (le résultat de l'opération).

La fonction qui formate les paramètre de l'utilisateur avant l'appel de la routine calc_window est un peu plus complexe qu'à l'accoutumé du fait qu'il faut définir un zone mémoire devant recevoir l'image traitée. Voici le code à implémenter dans qmtcl1.cpp.

/************************* CmdWindow ***********************/
/* Appel de la fonction 'window'                           */
/* Fenêtrage d'une image                                   */
/***********************************************************/
int CmdWindow(ClientData clientData,Tcl_Interp *interp,int argc,char *argv[])
{
int retour;
float *p,*p0;
short imax,jmax;
short imax2,jmax2;
short sh,sb;
short tempo;
int i;
char s[256];
short x1,y1,x2,y2;
IMAGE *image;

// Vérifie que la commande a le bon nombre d'argument
// --------------------------------------------------
if (argc!=5)
   {
   sprintf(s,"Usage: %s x1 y1 x2 y2", argv[0]);
   Tcl_SetResult(interp,s,TCL_VOLATILE);
   return TCL_ERROR;
   }

x1=(short)atoi(argv[1]);
y1=(short)atoi(argv[2]);
x2=(short)atoi(argv[3]);
y2=(short)atoi(argv[4]);

if (x1>x2)
   {
   tempo=x1;
   x1=x2;
   x2=tempo;
   }
if (y1>y2)
   {
   tempo=y1;
   y1=y2;
   y2=tempo;
   }
imax2=x2-x1+1;
jmax2=y2-y1+1;


// Lit les informations sur l'image contenue dans le buffer 1
// ----------------------------------------------------------
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;

// Vérifie la cohérance des donnéees
// ---------------------------------
if (imax2>imax || jmax2>jmax || x2>imax || y2>jmax || x1<1 || y1<1)
   {
   Tcl_SetResult(interp,"Fenêtre incorrecte",TCL_VOLATILE);
   return TCL_ERROR;
   }

// Copie l'image dans un tampon intermédiaire p0
// ---------------------------------------------
if ((p0=(float *)_malloc((int)sizeof(float)*imax*jmax))==NULL)
  {
  Tcl_SetResult(interp,"Problème de mémoire",TCL_VOLATILE);
  return TCL_ERROR;
  }
memmove(p0,p,(int)sizeof(float)*imax*jmax);

// Redimensionne le buffer 1 à la nouvelle
// taille de l'image après fenêtrage
// ---------------------------------------
sprintf(s,"buf%d format %d %d",1,imax2,jmax2);
retour=Tcl_Eval(interp,s);
if (retour!=TCL_OK) return retour;

// Récupère le pointeur mémoire du buffer 1
// ----------------------------------------
sprintf(s,"buf%d pointer",1);
retour=Tcl_Eval(interp,s);
if (retour!=TCL_OK) return retour;
retour=Tcl_GetInt(interp,interp->result,&i);
if (retour!=TCL_OK) return retour;
p=(float *)i;

// Effectue le fenêtrage
// ---------------------
if (calc_window(x1,y1,x2,y2,imax,jmax,imax2,jmax2,p0,p)==PB)
   {
   _free(p0);
   Tcl_SetResult(interp,"Calcul impossible",TCL_VOLATILE);
   return TCL_ERROR;
   }

// Libère la mémoire du tampon intermédiaire
// -----------------------------------------
_free(p0);

// Signale sur la console que tout c'est bien passé
// ------------------------------------------------
Tcl_SetResult(interp,"OK",TCL_VOLATILE);
return TCL_OK;
}

Après avoir décodé les coordonnées de la fenêtre (x1, y1) et (x2, y2), puis appelé la fonction get_image_info, on alloue un tampon mémoire dans lequel on va copier l'image à traiter :

// Copie l'image dans un tampon intermédiaire p0
// ---------------------------------------------
if ((p0=(float *)_malloc((int)sizeof(float)*imax*jmax))==NULL)
  {
  My_Tcl_SetResult(interp,"Problème de mémoire",TCL_VOLATILE);
  return TCL_ERROR;
  }
memmove(p0,p,(int)sizeof(float)*imax*jmax);

La fonction _malloc est équivalente à la fonction standard malloc du langage C. Nous verrons la petite différence plus loin. Notez que la librairie Tcl contient elle aussi une fonction d'allocation mémoire qui lui est propre, mais dont le fonctionnement est similaire à malloc. On aurait pu utiliser cette fonction Tcl ici (avantage : elle est indépendante de la plate-forme).

On modifie ensuite la taille du buffer image de manière à ce qu'elle corresponde à la dimension finale de l'image fenêtrée :

// Redimensionne le buffer 1 à la nouvelle
// taille de l'image après fenêtrage
// ---------------------------------------
sprintf(s,"buf%d format %d %d",1,imax2,jmax2);
retour=Tcl_Eval(interp,s);
if (retour!=TCL_OK) return retour;

Remarquez l'usage de la commande Audela buf1 format x y, où (x, y) sont les nouvelles tailles du buffer numéro 1.

Il reste à obtenir l'adresse mémoire effective du buffer  numéro 1. Nous avons déjà vu ce type d'opération avec la commande
offset :

// Récupère le pointeur mémoire du buffer 1
// ----------------------------------------
sprintf(s,"buf%d pointer",1);
retour=Tcl_Eval(interp,s);
if (retour!=TCL_OK) return retour;
retour=Tcl_GetInt(interp,interp->result,&i);
if (retour!=TCL_OK) return retour;
p=(float *)i;

On peut à présent effectuer le fenêtrage proprement dit :

// Effectue le fenêtrage
// ---------------------
if (calc_window(x1,y1,x2,y2,imax,jmax,imax2,jmax2,p0,p)==PB)
   {
   _free(p0);
   Tcl_SetResult(interp,"Calcul impossible",TCL_VOLATILE);
   return TCL_ERROR;
   }

On finit en libérant la mémoire allouée pour le tampon intermédiaire :

_free(p0);

 

                     (3/4)