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) |