/* hyster-tp.c - Edouard Thiel - 19/01/2001 Compilation : cc hyster-tp.c bsutil.c -o hyster-tp \ `~/helium/helium-cfg --cflags --libs` -lm Usage : hyster-tp [image-in.pgm] */ #include #include #include "bsutil.h" /* Variables globales */ He_node *princ, *panel1, *text_load, *canvas, *panel2, *mess, *butt_sobel, *butt_candi, *butt_seuil, *butt_propa, *text_seuil_haut, *text_seuil_bas; BsMap *gbm_orig = NULL, *gbm_sobX = NULL, *gbm_sobY = NULL, *gbm_sobM = NULL, *gbm_candi = NULL, *gbm_res = NULL; XImage *gxi = NULL; /*-------------------------- A L G O R I T H M E S --------------------------*/ /* * Fixe l'épaisseur du bord de bm à e, puis affecte les pixels qui sont dans * le bord de l'image, à la valeur de leur pixel miroir dans l'image. */ void BordMiroir (BsMap *bm, int e) { int x, y; SetBorderBsMap (bm, e); /* Haut et bas */ for (y = -bm->bord; y < 0; y++) for (x = 0; x < bm->xsiz; x++) { bm->tab[y][x] = bm->tab[-y][x]; bm->tab[bm->ysiz-1-y][x] = bm->tab[bm->ysiz-1+y][x]; } /* Gauche, droite et coins */ for (x = -bm->bord; x < 0; x++) for (y = -bm->bord; y < bm->ymax; y++) { bm->tab[y][x] = bm->tab[y][-x]; bm->tab[y][bm->xsiz-1-x] = bm->tab[y][bm->xsiz-1+x]; } } /* * Filtre linéaire de bm1 dans bm2 */ #define FILTREMAX 11 typedef struct { int taille; /* voisinage centré taille*taille */ double coef[FILTREMAX][FILTREMAX]; /* accès : coef[y][x] */ } Filtre; void FiltreLineaire (BsMap *bm1, BsMap *bm2, Filtre *f) { int x, y, ll = f->taille/2; BordMiroir (bm1, ll); for (y = 0; y < bm1->ysiz; y++) for (x = 0; x < bm1->xsiz; x++) { double s = 0; int xx, yy; for (yy = -ll; yy <= ll; yy++) for (xx = -ll; xx <= ll; xx++) s += bm1->tab[y + yy][x + xx] * f->coef[yy+ll][xx+ll]; bm2->tab[y][x] = s; } } /* * Calcul de Sobel X, Y et Module */ void CalculSobel (BsMap *bm, BsMap *sobX, BsMap *sobY, BsMap *sobM) { Filtre fx = { 3, {{ -1, 0, 1 }, { -2, 0, 2 }, { -1, 0, 1 }}}; Filtre fy = { 3, {{ -1, -2, -1 }, { 0, 0, 0 }, { 1, 2, 1 }}}; int x, y; /* Sobel X et Y */ FiltreLineaire (bm, sobX, &fx); FiltreLineaire (bm, sobY, &fy); /* Module de Sobel */ for (y = 0; y < sobM->ysiz; y++) for (x = 0; x < sobM->xsiz; x++) { double gx = sobX->tab[y][x], gy = sobY->tab[y][x]; sobM->tab[y][x] = sqrt (gx*gx + gy*gy); } } /* * Cherche le min et le max dans bm, puis fait une expansion de * dynamique des niveaux de gris de [min..max] à [0..255] dans bm. */ void Normaliser (BsMap *bm) { int x, y, min = bm->tab[0][0], max = bm->tab[0][0]; for (y = 0; y < bm->ysiz; y++) for (x = 0; x < bm->xsiz; x++) if (min > bm->tab[y][x]) min = bm->tab[y][x]; else if (max < bm->tab[y][x]) max = bm->tab[y][x]; for (y = 0; y < bm->ysiz; y++) for (x = 0; x < bm->xsiz; x++) bm->tab[y][x] = (bm->tab[y][x] - min) * 255 / (max - min); } /* * Renvoie la norme de (x,y) */ double Norme (int x, int y) { return sqrt ((double) x*x + y*y); } /* * Points candidats pour la détection de contours par Hystérésis. * * Marque les points candidats à 255 et les autres à 0. Un point est candidat * si la norme de son gradient en ce point est supérieure à celle de ses 2 * voisins en projection. Les 2 voisins considérés sont le point devant et et * le point derrière dans la direction du gradient. */ void PointsCandidats (BsMap *sobX, BsMap *sobY, BsMap *candi) { /* A COMPLETER */ } /* * Propagation récursive du seuillage par hystérésis. * * - Retour immédiat : * si le point n'est pas dans l'image, * ou si le point est déjà marqué, * ou si le point n'est pas candidat, * ou si le point est inférieur au seuil bas sB. * * - On marque le point à 255 dans res. * * - On propage récursivement sur les 8 voisins. */ void PropaRec (BsMap *sobM, BsMap *candi, BsMap *res, int sB, int x, int y) { /* A COMPLETER */ } /* * Seuillage par hystérésis (seuil bas et seuil haut). * * (Hystérésis, du grec husterein « être en retard » : retard de l'effet sur * la cause dans le comportement des corps soumis à une action physique). * * - Premier parcours : on initialise res à 0 * - Second parcours : pour chaque point >= au seuil haut sH on lance PropaRec. */ void PropaHysteresis (BsMap *sobM, BsMap *candi, BsMap *res, int sB, int sH) { /* A COMPLETER */ } /*---------------------------- I N T E R F A C E ----------------------------*/ void voir_image (BsMap *bm) { int l; /* On adapte la taille à l'image */ HeSetX (canvas, 0); HeSetWidth (canvas, bm ? bm->xsiz : 50); HeSetHeight (canvas, bm ? bm->ysiz : 50); HeJustify (panel2, canvas, HE_TOP); HeSetWidth (panel2, HeGetExtWidth(canvas)); HeFit (princ); HeExpand (panel2, NULL, HE_RIGHT); l = HeGetWidth (princ) - HeGetExtWidth(canvas); if (l > 0) HeSetX (canvas, l/2); HeSetMessageLabel (mess, bm ? bm->title : ""); /* On met à jour gxi et on provoque un réaffichage */ FreeXImage (gxi); gxi = NewXImageFromBsMap (bm, LUT_VGA_GREY); HePostRepaint (canvas); } void canvas_repaint_proc (He_node *hn, Window win) { if (gxi == NULL) HeDrawBg (canvas, he_black); else PaintXImage (gxi, win); } void sobel_proc (He_node *hn) { if (gbm_orig == NULL) return; CalculSobel (gbm_orig, gbm_sobX, gbm_sobY, gbm_sobM); Normaliser (gbm_sobM); SetTitleBsMap (gbm_sobM, "Module de Sobel normalisé"); voir_image (gbm_sobM); HeSetActive (butt_candi, TRUE); } void candi_proc (He_node *hn) { if (gbm_orig == NULL) return; PointsCandidats (gbm_sobX, gbm_sobY, gbm_candi); SetTitleBsMap (gbm_candi, "Points candidats"); voir_image (gbm_candi); HeSetActive (butt_seuil, TRUE); HeSetActive (butt_propa, TRUE); } void seuils_proc (He_node *hn) { int sH = atoi(HeGetTextValue(text_seuil_haut)), sB = atoi(HeGetTextValue(text_seuil_bas)), x, y; char bla[100]; if (gbm_orig == NULL) return; /* Seuils */ for (y = 0; y < gbm_candi->ysiz; y++) for (x = 0; x < gbm_candi->xsiz; x++) gbm_res->tab[y][x] = gbm_candi->tab[y][x] == 0 ? 0 : /* noir */ gbm_sobM->tab[y][x] < sB ? -1 : /* bleu */ gbm_sobM->tab[y][x] < sH ? -10 : /* vert */ -12 ; /* rouge */ sprintf (bla, "Bleu < %d <= vert < %d <= rouge", sB, sH); SetTitleBsMap (gbm_res, bla); voir_image (gbm_res); } void propag_proc (He_node *hn) { int sH = atoi(HeGetTextValue(text_seuil_haut)), sB = atoi(HeGetTextValue(text_seuil_bas)), x, y; char bla[100]; if (gbm_orig == NULL) return; PropaHysteresis (gbm_sobM, gbm_candi, gbm_res, sB, sH); /* Post-traitement pour la visualisation */ for (y = 0; y < gbm_candi->ysiz; y++) for (x = 0; x < gbm_candi->xsiz; x++) gbm_res->tab[y][x] = gbm_res->tab[y][x] ? -12 : 180+gbm_orig->tab[y][x]*(255-180)/255; sprintf (bla, "Hystérésis avec seuils (%d, %d)", sB, sH); SetTitleBsMap (gbm_res, bla); voir_image (gbm_res); } void quit_proc (He_node *hn) { HeQuit(0); } void load_proc (He_node *hn) { char *nom = HeGetTextValue (text_load); FreeBsMap(gbm_orig); gbm_orig = NULL; FreeBsMap(gbm_sobX); gbm_sobX = NULL; FreeBsMap(gbm_sobY); gbm_sobY = NULL; FreeBsMap(gbm_sobM); gbm_sobM = NULL; FreeBsMap(gbm_candi); gbm_candi = NULL; FreeBsMap(gbm_res); gbm_res = NULL; HeSetActive (butt_candi, FALSE); HeSetActive (butt_seuil, FALSE); HeSetActive (butt_propa, FALSE); gbm_orig = ReadBsMapFromPGM (nom, 0); if (gbm_orig == NULL) { HeSimpleDialog ( HE_DIALOG_BELL, HE_DIALOG_TITLE, "Attention", HE_DIALOG_MESSAGE, "Erreur de lecture du fichier", HE_DIALOG_QUOTED, nom, HE_DIALOG_BUTTOK, "Ok", 0); } else { gbm_sobX = NewBsMap (gbm_orig->ysiz, gbm_orig->xsiz, 0); gbm_sobY = NewBsMap (gbm_orig->ysiz, gbm_orig->xsiz, 0); gbm_sobM = NewBsMap (gbm_orig->ysiz, gbm_orig->xsiz, 0); gbm_candi = NewBsMap (gbm_orig->ysiz, gbm_orig->xsiz, 0); gbm_res = NewBsMap (gbm_orig->ysiz, gbm_orig->xsiz, 0); if (gbm_sobX == NULL || gbm_sobY == NULL || gbm_sobM == NULL || gbm_candi == NULL || gbm_res == NULL) HeQuit(1); } voir_image (gbm_orig); } void plus_proc (He_node *hn) { He_node *t = HeGetClientData (hn); char *nom = HeGetButtonLabel (hn), bla[32]; int v = atoi (HeGetTextValue (t)); if (strcmp(nom, "+") == 0) v++; else if (strcmp(nom, "-") == 0) v--; else if (strcmp(nom, "++") == 0) v += 10; else if (strcmp(nom, "--") == 0) v -= 10; if (v < 0) v = 0; else if (v > 255) v = 255; sprintf (bla, "%d", v); HeSetTextValue (t, bla); } void reaffi_proc (He_node *hn) { voir_image (gbm_orig); } /*---------------------------- P R I N C I P A L ----------------------------*/ int main (int argc, char **argv) { int code_sortie; HeInit (&argc, &argv); princ = HeCreateFrame(); HeSetFrameLabel (princ, "Hystérésis"); panel1 = HeCreatePanel (princ); text_load = HeCreateText (panel1); HeSetTextVisibleLen (text_load, 35); HeSetTextCompletion (text_load, TRUE); HeSetTextNotifyProc (text_load, load_proc); HeSetPanelLayout (panel1, HE_LINE_FEED); HeCreateButtonP (panel1, "Charger", load_proc, NULL); HeCreateButtonP (panel1, "Reafficher", reaffi_proc, NULL); HeCreateButtonP (panel1, "Quit", quit_proc, NULL); HeSetPanelLayout (panel1, HE_LINE_FEED); butt_sobel = HeCreateButtonP (panel1, "Sobel", sobel_proc, NULL); butt_candi = HeCreateButtonP (panel1, "Candidats", candi_proc, NULL); butt_seuil = HeCreateButtonP (panel1, "Seuils", seuils_proc, NULL); butt_propa = HeCreateButtonP (panel1, "Propager", propag_proc, NULL); HeSetPanelLayout (panel1, HE_LINE_FEED); HeCreateMessageP (panel1, "Seuil bas ", TRUE); text_seuil_bas = HeCreateText (panel1); HeSetTextVisibleLen(text_seuil_bas, 5); HeSetTextValue (text_seuil_bas, "100"); HeCreateButtonP (panel1, "--", plus_proc, text_seuil_bas); HeCreateButtonP (panel1, "-" , plus_proc, text_seuil_bas); HeCreateButtonP (panel1, "+" , plus_proc, text_seuil_bas); HeCreateButtonP (panel1, "++", plus_proc, text_seuil_bas); HeSetPanelLayout (panel1, HE_LINE_FEED); HeCreateMessageP (panel1, "Seuil haut", TRUE); text_seuil_haut = HeCreateText (panel1); HeSetTextVisibleLen(text_seuil_haut, 5); HeSetTextValue (text_seuil_haut, "200"); HeCreateButtonP (panel1, "--", plus_proc, text_seuil_haut); HeCreateButtonP (panel1, "-" , plus_proc, text_seuil_haut); HeCreateButtonP (panel1, "+" , plus_proc, text_seuil_haut); HeCreateButtonP (panel1, "++", plus_proc, text_seuil_haut); HeSetPanelLayout (panel1, HE_LINE_FEED); HeFit(panel1); canvas = HeCreateCanvas (princ); HeSetCanvasRepaintProc (canvas, canvas_repaint_proc); HeJustify (canvas, panel1, HE_TOP); HeMoveY (canvas, 5); panel2 = HeCreatePanel (princ); mess = HeCreateMessage (panel2); HeFit (panel2); HeJustify (panel2, canvas, HE_TOP); HeFit (princ); if (argc > 1) { HeSetTextValue (text_load, argv[1]); load_proc (text_load); } else voir_image (NULL); code_sortie = HeMainLoop (princ); FreeBsMap(gbm_orig); FreeBsMap(gbm_sobX); FreeBsMap(gbm_sobY); FreeBsMap(gbm_sobM); FreeBsMap(gbm_candi); FreeBsMap(gbm_res); FreeXImage (gxi); return code_sortie; }