Le but du TD est de realiser un programme qui prend en entree :
et qui sorte dans un fichier ou sur la sortie standard un fichier texte contenant les chaines de contours sous la forme:
[nb de chaines de contours] [nb de maillons de la chaine 1] [x_chaine1_maillon1] [y_chaine1_maillon1] ... [x_chaine1_maillonn] [y_chaine1_maillonn] [nb de maillons de la chaine 2] ...
Ce fichier de contours peut etre affiche, superpose a l'image, par une commande du type :
affgros -ima image.pgm -pix1 image.contours
Vous pourrez reprendre le squelette du programme d'exemple du TD1
Le programme contient plusieurs etapes:
Utilisez la fonctions de la bibliotheque Rpti pour calculer :
Sauvegardez chacune de cez images respectivement dans les fichiers "lapl" et "grad", affichez-les avec affgros pour en tester le contenu
Sur l'image suivante, observez les transitions entre les zones positives et negatives du laplacien.
Vous observez qu'elles sont de deux types: transitions horizontales et verticales. Elles sont localisees a la frontiere entre deux pixels. Nous allons calculer une image pour chaque type de transition.
Quelle est la taille de l'image des transitions horizontales, c.-a-d. entre pixel (x,y) et (x+1,y) ? des transitions verticales, c.a-d. entre pixel (x,y) et (x,y+1) ?
Creez une image pour chaque type de transition, de type char, qui vaut 0 quand il n'y a pas de changement de signe, et 1 quand il y en a un. Sauvegardez et visualisez ces deux images.
Dans cette derinere etape, il s'agit d'effectuer le chainage des transitions, en effectuant un seuillage par hysteresis sur la norme du gradient.
Pour effectuer ce chainage, il suffit de parcourir chaque image de transitions, et des qu'on trouve une transition pour laquelle la norme du gradient est superieure au seuil haut, de la suivre dans ces deux images pour toutes les transitions dont la norme du gradient est superieurs au seuil bas. La norme du gradient associee a une transition pourra par exemple la moyenne de la norme des deux pixels voisins d'une transition.
Lorsqu'on rencontre une transition, il faut parcourir la chaine dans les deux sens a partir de ce point, et fusionner les deux tableaux de points ainsi obtenus. Le tableau final doit permettre de parcourir la chaine en gardant la zone positive du laplacien sur la droite
Visualisez le resultat obtenu en faisant varier les seuils
Editez le fichier ~/.zshenv pour ajouter les lignes :
export ROBOTVIS=/home/divers/devernay/robotvis PATH=$ROBOTVIS/bin:$PATH
Pour relire l'environnement :
. ~/.zshenv
Des images se trouvent dans /home/divers/devernay/herve
#include <Rpti.h> #include <Rimage.h> ... IMAGE d2x, d2y, lapl; int dimx, dimy; float *d2xdata, *d2ydata, *lapldata; d2x = ptiGaussianRecDerivative2X(imin, sigma, IMAGE_FLOAT); d2y = ptiGaussianRecDerivative2Y(imin, sigma, IMAGE_FLOAT); /* on alloue lapl de memes caracteristiques que d2x */ lapl = imageMalloc(IMAGE_HEADER(d2x)); dimx = IMAGE_DIMX(lapl); dimy = IMAGE_DIMY(lapl); d2xdata= (float*)IMAGE_DATA(d2x); d2ydata= (float*)IMAGE_DATA(d2y); lapldata= (float*)IMAGE_DATA(lapl); /* parcours de l'image ligne par ligne */ for (y=0; y<dimy; y++) { for (x=0; x<dimx; x++) { lapldata[x+y*dimx] = d2xdata[x+y*dimx] + d2ydata[x+y*dimx]; } } /* on peut liberer l'espace utilise par d2x et d2y */ imageFree(d2x); imageFree(d2y); /* si on veut enregistrer lapl... */ imageSave("lapl", lapl, IMAGE_INRIMAGE_FORMAT);
Utiliser de la meme meme maniere ptiGaussianRecGradient :
IMAGE dx, dy, gradnorm; float *dxdata, *dydata, *gradnormdata; dx = imageMalloc(IMAGE_HEADER(lapl)); dy = imageMalloc(IMAGE_HEADER(lapl)); gradnorm =imageMalloc(IMAGE_HEADER(lapl)); ptiGaussianRecGradient(imin, sigma, IMAGE_FLOAT, &dx, &dy); dxdata = (float*)IMAGE_DATA(dx); dydata = (float*)IMAGE_DATA(dy); gradnormdata = (float*)IMAGE_DATA(gradnorm); etc...
On alloue des images de taille dimx*dimy, sachant que la derniere ligne de tx ne sert pas, de meme que la derniere colonne de ty.
IMAGE tx, ty; unsigned chqr *txdata, *tydata; IMAGE_HEADER_P header; IMAGE_HEADER_DIMX(header) = dimx; IMAGE_HEADER_DIMY(header) = dimy; IMAGE_HEADER_TYPE(header) = IMAGE_CHAR; tx = imageMalloc(header); ty = imageMalloc(header); if ((tx == NULL) || (ty == NULL)) { fprintf(stderr,"alloc_free: pb with imageMalloc CHAR\n"); } /* parcourir l'image de laplacien, remplir tx et ty avec des 0 et des 1 */ txdata = (unsigned char *)IMAGE_DATA(tx); tydata = (unsigned char *)IMAGE_DATA(ty); ... /* transition de (x,y) a (x+1,y) */ txdata[x+y*dimx] = ... /* transition de (x,y) a (x,y+1) */ tydata[x+y*dimx] = ... ...
typedef struct { float x; float y; } point_t; typedef struct { int nbpts; point_t *pts; } contour_t; typedef struct { int nbcont; contour_t *cont; } lescontours_t; lescontours_t lescontours = { 0, NULL}; ... contour_t cont = { 0, NULL }; ... /* ajouter un point de contour a cont */ cont.nbpts++; /* on realloue la taille necessaire pour le tableau */ cont.pts = (point_t*) realloc(cont.pts, cont.nbpts*sizeof(point_t)); cont.pts[nbpts-1].x = 123.5; cont.pts[nbpts-1].y = 72; ... /* afficher le contour */ for (i=0;i<cont.nbpts; i++) { printf("%g %g\n", cont.pts[i].x, cont.pts[i].y); } ... /* ajouter un contour a lescontours */ lescontours.nbcont++; /* on realloue la taille necessaire pour le tableau */ lescontours.cont = (contour_t*) realloc(lescontours.cont, lescontours.nbcont*sizeof(contour_t)); lescontours.cont.[nbcont-1].nbpts = cont.nbpts; lescontours.cont.[nbcont-1].pts = cont.pts; ...