_______________________________________________________________________________________________________________________________________ /*************************************************************************************************************************************/ /* */ /* F O N C T I O N S D E B A S E D E G E S T I O N D E S C O N T O U R S : */ /* */ /* */ /* Definition : */ /* */ /* Ce fichier contient toutes les fonctions */ /* de base de calcul des contours (extraction, */ /* remplissage,...) d'une images raster, quelle que */ /* soit la definition. */ /* */ /* */ /* Author of '$xiii/contours$FON' : */ /* */ /* Jean-Francois COLONNA (LACTAMME, 19870000000000). */ /* */ /*************************************************************************************************************************************/ /*===================================================================================================================================*/ /*************************************************************************************************************************************/ /* */ /* R E M P L I S S A G E D U V O I S I N A G E D ' U N P O I N T D ' U N E I M A G E : */ /* */ /*************************************************************************************************************************************/ BFonctionI DEFV(Common,DEFV(Float,SINT(Iremplissage_voisinage_____increment_recursif_du_niveau_de_remplissage,FZERO))); /* Cet increment (ou decrement, suivant son signe...) permet de changer le niveau de */ /* remplissage a chaque nouveau niveau de recursivite... */ DEFV(Common,DEFV(Logical,SINT(Iremplissage_voisinage_____calculer_l_histogramme_du__bord,FAUX))); /* Cet indicateur introduit le 20230823132102 permet de calculer l'histogramme du 'bord' */ /* en particulier pour savoir quel est son niveau majoritaire... */ DEFV(Common,DEFV(Int,SINT(Iremplissage_voisinage_____nombre_de_points_du__fond,ZERO))); DEFV(Common,DEFV(pointF_2D,Iremplissage_voisinage_____centre_de_gravite_du__fond)); /* Introduit le 20161105103427 et complete le 20161105105224 par l'edition... */ DEFV(Common,DEFV(Logical,SINT(Iremplissage_voisinage_____calculer_la_matrice_d_inertie_du__fond,FAUX))); DEFV(Common,DEFV(matrixF_2D,Iremplissage_voisinage_____matrice_d_inertie_du__fond)); /* Donnees introduites le 20230825094226 pour calculer les moments d'inertie d'un contour. */ DEFV(Common,DEFV(Logical,SINT(Iremplissage_voisinage_____rechercher_le_niveau_maximal_d_un_point_isole,FAUX))); DEFV(Common,DEFV(genere_Float,SINT(Iremplissage_voisinage_____niveau_maximal_d_un_point_isole,F_MOINS_L_INFINI))); /* Afin de calculer le niveau maximal du fond (introduit le 20230827092529). On notera */ /* l'usage de 'genere_Float' et non pas de 'genere_p' afin de faciliter la recherche de */ /* ce maximum... */ #define TEST_REMPLISSAGE_POINT_ISOLE(direction,x,y) \ Bblock \ Test(IL_FAUT(direction)) \ Bblock \ Test(TEST_DANS_L_IMAGE(x,y)) \ Bblock \ DEFV(genere_p,INIT(voisin,load_point(imageA,x,y))); \ /* Recuperation du niveau du point courant. */ \ \ INCR(nombre_de_voisins_total,I); \ \ Test(EST_VRAI(ITb1(fond,INDX(voisin,NOIR)))) \ Bblock \ INCR(nombre_de_voisins_appartenant_au_fond,I); \ Eblock \ ATes \ Bblock \ Eblock \ ETes \ Eblock \ ATes \ Bblock \ Eblock \ ETes \ Eblock \ ATes \ Bblock \ Eblock \ ETes \ Eblock #define MOVE_REMPLISSAGE(direction,x,y) \ Bblock \ Test(IL_FAUT(direction)) \ Bblock \ CALS(Iremplissage_voisinage(imageR \ ,imageA \ ,x,y \ ,coin_gauche,coin_droite \ ,coin_inferieur,coin_superieur \ ,fond,bord \ ,est_______,nord______,ouest_____,sud_______ \ ,nord_est__,nord_ouest,sud_ouest_,sud_est___ \ ,ADD2(niveau_de_remplissage \ ,Iremplissage_voisinage_____increment_recursif_du_niveau_de_remplissage \ ) \ ) \ ); \ Eblock \ ATes \ Bblock \ Eblock \ ETes \ Eblock \ /* Fonction de test de la necessite de faire un deplacement dans */ \ /* une 'direction' argument, et si oui, donc, remplir le voisinage */ \ /* du point courant dans cette direction. */ DEFV(Local,DEFV(FonctionI,Iremplissage_voisinage(imageR ,imageA ,X,Y ,coin_gauche,coin_droite ,coin_inferieur,coin_superieur ,fond,bord ,est_______,nord______,ouest_____,sud_______ ,nord_est__,nord_ouest,sud_ouest_,sud_est___ ,niveau_de_remplissage ) ) ) DEFV(Argument,DEFV(image,imageR)); /* Image Resultat contenant le remplissage du contour Argument. */ DEFV(Argument,DEFV(image,imageA)); /* Image Argument. */ DEFV(Argument,DEFV(Int,X)); DEFV(Argument,DEFV(Int,Y)); /* Coordonnees entieres 'X' et 'Y'. */ DEFV(Argument,DEFV(Int,coin_gauche)); /* Definition */ DEFV(Argument,DEFV(Int,coin_droite)); /* du cadre */ DEFV(Argument,DEFV(Int,coin_inferieur)); /* a l'interieur duquel */ DEFV(Argument,DEFV(Int,coin_superieur)); /* se fait le remplissage. */ DEFV(Argument,DEFV(Logical,DTb1(fond,COULEURS))); /* Definit ainsi pour chaque niveau s'il appartient ('VRAI') ou pas */ /* ('FAUX') au fond, c'est-a-dire a ce que l'on doit remplir. */ DEFV(Argument,DEFV(Logical,DTb1(bord,COULEURS))); /* Definit ainsi pour chaque niveau s'il appartient ('VRAI') ou pas */ /* ('FAUX') au bord, c'est-a-dire a ce qui delimite le contour. */ DEFV(Argument,DEFV(Logical,est_______)); /* Variable logique indiquant si l'on doit emprunter la direction 'est' */ /* ('VRAI') ou pas ('FAUX') lors du parcours recursif de l'interieur */ /* du contour. */ DEFV(Argument,DEFV(Logical,nord______)); /* Variable logique indiquant si l'on doit emprunter la direction 'nord' */ /* ('VRAI') ou pas ('FAUX') lors du parcours recursif de l'interieur */ /* du contour. */ DEFV(Argument,DEFV(Logical,ouest_____)); /* Variable logique indiquant si l'on doit emprunter la direction 'ouest' */ /* ('VRAI') ou pas ('FAUX') lors du parcours recursif de l'interieur */ /* du contour. */ DEFV(Argument,DEFV(Logical,sud_______)); /* Variable logique indiquant si l'on doit emprunter la direction 'sud' */ /* ('VRAI') ou pas ('FAUX') lors du parcours recursif de l'interieur */ /* du contour. */ DEFV(Argument,DEFV(Logical,nord_est__)); /* Variable logique indiquant si l'on doit emprunter la direction 'nord_est' */ /* ('VRAI') ou pas ('FAUX') lors du parcours recursif de l'interieur */ /* du contour. */ DEFV(Argument,DEFV(Logical,nord_ouest)); /* Variable logique indiquant si l'on doit emprunter la direction 'nord_ouest' */ /* ('VRAI') ou pas ('FAUX') lors du parcours recursif de l'interieur */ /* du contour. */ DEFV(Argument,DEFV(Logical,sud_ouest_)); /* Variable logique indiquant si l'on doit emprunter la direction 'sud_ouest' */ /* ('VRAI') ou pas ('FAUX') lors du parcours recursif de l'interieur */ /* du contour. */ DEFV(Argument,DEFV(Logical,sud_est___)); /* Variable logique indiquant si l'on doit emprunter la direction 'sud_est' */ DEFV(Argument,DEFV(genere_Float,niveau_de_remplissage)); /* Niveau a utiliser pour remplir le contour Argument. */ /*-----------------------------------------------------------------------------------------------------------------------------------*/ Bblock INIT_ERROR; /* ATTENTION : 'INIT_ERROR' est mis en tete des variables locales au cas ou des couples */ /* ('BDEFV','EDEFV') suivraient... */ /*..............................................................................................................................*/ Test(IFET(TEST_DANS_L_IMAGE(X,Y) ,IFET(INCLff(X,coin_gauche,coin_droite) ,INCLff(Y,coin_inferieur,coin_superieur) ) ) ) Bblock Test(TEST_POINT_NON_MARQUE(X,Y)) Bblock /* On ne traite que les points sur lesquels on n'est pas encore passe ; on */ /* notera qu'il serait imprudent de tester 'NIVEAU_DE_MARQUAGE' avec */ /* un 'IFEQ' a cause des problemes lies aux 'liste de substitution'. */ DEFV(genere_p,INIT(point,load_point(imageA,X,Y))); /* Recuperation du niveau du point courant. */ Test(IL_FAUT(Iremplissage_voisinage_____rechercher_le_niveau_maximal_d_un_point_isole)) Bblock Test(EST_FAUX(ITb1(fond,INDX(point,NOIR)))) Bblock DEFV(Int,INIT(nombre_de_voisins_total,ZERO)); DEFV(Int,INIT(nombre_de_voisins_appartenant_au_fond,ZERO)); TEST_REMPLISSAGE_POINT_ISOLE(est_______,SUCX(X),NEUT(Y)); TEST_REMPLISSAGE_POINT_ISOLE(nord______,NEUT(X),SUCY(Y)); TEST_REMPLISSAGE_POINT_ISOLE(ouest_____,PREX(X),NEUT(Y)); TEST_REMPLISSAGE_POINT_ISOLE(sud_______,NEUT(X),PREY(Y)); TEST_REMPLISSAGE_POINT_ISOLE(nord_est__,SUCX(X),SUCY(Y)); TEST_REMPLISSAGE_POINT_ISOLE(nord_ouest,PREX(X),SUCY(Y)); TEST_REMPLISSAGE_POINT_ISOLE(sud_ouest_,PREX(X),PREY(Y)); TEST_REMPLISSAGE_POINT_ISOLE(sud_est___,SUCX(X),PREY(Y)); Test(IFEQ(nombre_de_voisins_appartenant_au_fond,nombre_de_voisins_total)) /* Le point courant {X,Y} n'est pas du 'fond' et n'a pas de voisin, il est donc isole : */ Bblock EGAL(Iremplissage_voisinage_____niveau_maximal_d_un_point_isole ,MAX2(Iremplissage_voisinage_____niveau_maximal_d_un_point_isole,FLOT(point)) ); Eblock ATes Bblock Eblock ETes Eblock ATes Bblock Eblock ETes Eblock ATes Bblock Eblock ETes Test(EST_FAUX(ITb1(bord,INDX(point,NOIR)))) Bblock MARQUAGE_POINT(X,Y); /* Marquage systematique des points qui ne sont pas au bord dans une image */ /* de travail, afin d'eviter des "trous" crees par exemple lorsque les */ /* listes de "bord" et de "fond" ne sont pas complementaires. */ Test(EST_VRAI(ITb1(fond,INDX(point,NOIR)))) Bblock /* Traitement des points qui n'appartiennent pas au "bord", et */ /* qui appartiennent au "fond". */ Test(TEST_MASQUE_ACTIF(X,Y,MASQUER_PARCOURS)) Bblock store_point(GENP(TRNP(niveau_de_remplissage)),imageR,X,Y,FVARIABLE); /* Finalement, remplissage du point courant {X,Y} qui appartient au "fond", */ /* n'appartient pas au "bord" et n'est pas masque (ou bien l'est, mais */ /* est compatible avec le seuil et la portee du masquage...). */ Test(IL_NE_FAUT_PAS(Iremplissage_voisinage_____calculer_la_matrice_d_inertie_du__fond)) Bblock INCR(Iremplissage_voisinage_____nombre_de_points_du__fond,I); /* Comptage des points (introduit le 20161105103427). */ INCR(ASD1(Iremplissage_voisinage_____centre_de_gravite_du__fond,x),FLOT(X)); INCR(ASD1(Iremplissage_voisinage_____centre_de_gravite_du__fond,y),FLOT(Y)); /* Calcul "iteratif" du centre de gravite (introduit le 20161105103427). */ Eblock ATes Bblock INCR(ASD2(Iremplissage_voisinage_____matrice_d_inertie_du__fond,cx,cx) ,MUL2(SOUS(X,ASD1(Iremplissage_voisinage_____centre_de_gravite_du__fond,x)) ,SOUS(X,ASD1(Iremplissage_voisinage_____centre_de_gravite_du__fond,x)) ) ); INCR(ASD2(Iremplissage_voisinage_____matrice_d_inertie_du__fond,cx,cy) ,MUL2(SOUS(X,ASD1(Iremplissage_voisinage_____centre_de_gravite_du__fond,x)) ,SOUS(Y,ASD1(Iremplissage_voisinage_____centre_de_gravite_du__fond,y)) ) ); INCR(ASD2(Iremplissage_voisinage_____matrice_d_inertie_du__fond,cy,cx) ,MUL2(SOUS(Y,ASD1(Iremplissage_voisinage_____centre_de_gravite_du__fond,y)) ,SOUS(X,ASD1(Iremplissage_voisinage_____centre_de_gravite_du__fond,x)) ) ); /* On notera que les moments {cx,cy} et {cy,cx} sont evidemment egaux, mais qu'on les */ /* calcule malgre tout independemment l'un de l'autre pour des raisons de symetrie... */ INCR(ASD2(Iremplissage_voisinage_____matrice_d_inertie_du__fond,cy,cy) ,MUL2(SOUS(Y,ASD1(Iremplissage_voisinage_____centre_de_gravite_du__fond,y)) ,SOUS(Y,ASD1(Iremplissage_voisinage_____centre_de_gravite_du__fond,y)) ) ); Eblock ETes Eblock ATes Bblock Eblock ETes Eblock ATes Bblock Eblock ETes /* Puis, on passe aux voisins, suivant la regle de connexite demandee. */ MOVE_REMPLISSAGE(est_______,SUCX(X),NEUT(Y)); MOVE_REMPLISSAGE(nord______,NEUT(X),SUCY(Y)); MOVE_REMPLISSAGE(ouest_____,PREX(X),NEUT(Y)); MOVE_REMPLISSAGE(sud_______,NEUT(X),PREY(Y)); MOVE_REMPLISSAGE(nord_est__,SUCX(X),SUCY(Y)); MOVE_REMPLISSAGE(nord_ouest,PREX(X),SUCY(Y)); MOVE_REMPLISSAGE(sud_ouest_,PREX(X),PREY(Y)); MOVE_REMPLISSAGE(sud_est___,SUCX(X),PREY(Y)); Eblock ATes Bblock Test(IL_FAUT(Iremplissage_voisinage_____calculer_l_histogramme_du__bord)) Bblock INCR(ACCES_HISTOGRAMME(point),I); /* Le niveau 'point' fait partie du 'bord'... */ Eblock ATes Bblock Eblock ETes Eblock ETes Eblock ATes Bblock Eblock ETes Eblock ATes Bblock Eblock ETes RETU_ERROR; Eblock #undef MOVE_REMPLISSAGE #undef TEST_REMPLISSAGE_POINT_ISOLE EFonctionI /*===================================================================================================================================*/ /*************************************************************************************************************************************/ /* */ /* R E M P L I S S A G E R E C U R S I F D ' U N C O N T O U R D ' U N E I M A G E : */ /* */ /*************************************************************************************************************************************/ BFonctionP DEFV(Common,DEFV(Logical,SINT(Iremplissage_____editer_le_centre_de_gravite,FAUX))); /* Introduit le 20161105105224... */ DEFV(Common,DEFV(Logical,SINT(Iremplissage_____calculer_l_histogramme_du__bord,FAUX))); /* Introduit le 20230823132102... */ DEFV(Common,DEFV(Logical,SINT(Iremplissage_____editer_la_matrice_d_inertie,FAUX))); /* Introduit le 20230825094226... */ DEFV(Common,DEFV(FonctionP,POINTERp(Iremplissage(imageR ,imageA ,ARGUMENT_POINTERs(point_de_depart) ,ARGUMENT_POINTERs(coin_inferieur_gauche) ,ARGUMENT_POINTERs(coin_superieur_droite) ,fond,bord ,est_______,nord______,ouest_____,sud_______ ,nord_est__,nord_ouest,sud_ouest_,sud_est___ ,niveau_de_remplissage ) ) ) ) DEFV(Argument,DEFV(image,imageR)); /* Image Resultat contenant le remplissage du contour Argument. */ DEFV(Argument,DEFV(image,imageA)); /* Image Argument. */ DEFV(Argument,DEFV(pointF_2D,POINTERs(point_de_depart))); /* Coordonnees du point de depart de remplissage exprimees dans des */ /* unites telles que l'unite vaut respectivement [Xmin,Xmax] et */ /* [Ymin,Ymax]. */ DEFV(Argument,DEFV(pointF_2D,POINTERs(coin_inferieur_gauche))); /* Le remplissage ne sera fait qu'a l'interieur d'un "cadre" que l'on */ /* definit par son coin inferieur gauche, */ DEFV(Argument,DEFV(pointF_2D,POINTERs(coin_superieur_droite))); /* Definit par son coin superieur droit ; ainsi, on pourra remplir */ /* des contours ouverts dont le "cadre" proviendra du "cadre" defini */ /* lors du trace des vecteurs 2D. */ DEFV(Argument,DEFV(Logical,DTb1(fond,COULEURS))); /* Definit ainsi pour chaque niveau s'il appartient ('VRAI') ou pas */ /* ('FAUX') au fond, c'est-a-dire a ce que l'on doit remplir. */ DEFV(Argument,DEFV(Logical,DTb1(bord,COULEURS))); /* Definit ainsi pour chaque niveau s'il appartient ('VRAI') ou pas */ /* ('FAUX') au bord, c'est-a-dire a ce qui delimite le contour. */ DEFV(Argument,DEFV(Logical,est_______)); /* Variable logique indiquant si l'on doit emprunter la direction 'est' */ /* ('VRAI') ou pas ('FAUX') lors du parcours recursif de l'interieur */ /* du contour. */ DEFV(Argument,DEFV(Logical,nord______)); /* Variable logique indiquant si l'on doit emprunter la direction 'nord' */ /* ('VRAI') ou pas ('FAUX') lors du parcours recursif de l'interieur */ /* du contour. */ DEFV(Argument,DEFV(Logical,ouest_____)); /* Variable logique indiquant si l'on doit emprunter la direction 'ouest' */ /* ('VRAI') ou pas ('FAUX') lors du parcours recursif de l'interieur */ /* du contour. */ DEFV(Argument,DEFV(Logical,sud_______)); /* Variable logique indiquant si l'on doit emprunter la direction 'sud' */ /* ('VRAI') ou pas ('FAUX') lors du parcours recursif de l'interieur */ /* du contour. */ DEFV(Argument,DEFV(Logical,nord_est__)); /* Variable logique indiquant si l'on doit emprunter la direction 'nord_est' */ /* ('VRAI') ou pas ('FAUX') lors du parcours recursif de l'interieur */ /* du contour. */ DEFV(Argument,DEFV(Logical,nord_ouest)); /* Variable logique indiquant si l'on doit emprunter la direction 'nord_ouest' */ /* ('VRAI') ou pas ('FAUX') lors du parcours recursif de l'interieur */ /* du contour. */ DEFV(Argument,DEFV(Logical,sud_ouest_)); /* Variable logique indiquant si l'on doit emprunter la direction 'sud_ouest' */ /* ('VRAI') ou pas ('FAUX') lors du parcours recursif de l'interieur */ /* du contour. */ DEFV(Argument,DEFV(Logical,sud_est___)); /* Variable logique indiquant si l'on doit emprunter la direction 'sud_est' */ /* ('VRAI') ou pas ('FAUX') lors du parcours recursif de l'interieur */ /* du contour. */ DEFV(Argument,DEFV(genere_p,niveau_de_remplissage)); /* Niveau a utiliser pour remplir le contour Argument. */ /*-----------------------------------------------------------------------------------------------------------------------------------*/ Bblock DEFV(Int,INIT(X,UNDEF)); DEFV(Int,INIT(Y,UNDEF)); /* Coordonnees entieres 'X' et 'Y'. */ /*..............................................................................................................................*/ BoIn(niveau,NOIR,BLANC,PAS_COULEURS) Bblock Test(IFEQ(ITb1(bord,INDX(niveau,NOIR)),ITb1(fond,INDX(niveau,NOIR)))) Bblock PRINT_ERREUR("un niveau ne peut appartenir a la fois au 'bord' et au 'fond'"); CAL1(Prer1("ce niveau est %08X\n",niveau)); Eblock ATes Bblock Eblock ETes Eblock EBoI Test(IL_FAUT(Iremplissage_____calculer_l_histogramme_du__bord)) /* Possibilite introduite le 20230823132102... */ Bblock BoIn(niveau,NOIR,BLANC,PAS_COULEURS) Bblock CLIR(ACCES_HISTOGRAMME(niveau)); Eblock EBoI Eblock ATes Bblock Eblock ETes EGAL(Iremplissage_voisinage_____niveau_maximal_d_un_point_isole,F_MOINS_L_INFINI); /* Afin de calculer le niveau maximal du fond (introduit le 20230827092529), si besoin est. */ BSaveModifyVariable(Logical ,Iremplissage_voisinage_____calculer_l_histogramme_du__bord ,Iremplissage_____calculer_l_histogramme_du__bord ); /* Pour des raisons d'imbrication, ce 'BSaveModifyVariable(...)' ne peut pas etre situe */ /* dans le 'Test(IL_FAUT(Iremplissage_____calculer_l_histogramme_du__bord))' precedent... */ MARQUAGE_VALIDATION_ET_INITIALISATION; /* On verifie que le marquage est possible... */ EGAL(X,_cDENORMALISE_OX(ASI1(point_de_depart,x))); EGAL(Y,_cDENORMALISE_OY(ASI1(point_de_depart,y))); /* Recuperation des coordonnees du point de depart, et mise dans */ /* les coordonnees de l'image. */ Test(IL_FAUT(Iremplissage_voisinage_____calculer_la_matrice_d_inertie_du__fond)) Bblock Test(IZEQ(Iremplissage_voisinage_____nombre_de_points_du__fond)) Bblock PRINT_ERREUR("la matrice d'inertie ne peut etre calculee tant que le centre de gravite n'est pas connu"); EGAL(Iremplissage_voisinage_____calculer_la_matrice_d_inertie_du__fond,FAUX); Eblock ATes Bblock Eblock ETes Eblock ATes Bblock Eblock ETes Test(IL_NE_FAUT_PAS(Iremplissage_voisinage_____calculer_la_matrice_d_inertie_du__fond)) /* Ce test ne peut etre combine au precedent car, en effet, le test precedent peut modifier */ /* l'indicateur 'Iremplissage_voisinage_____calculer_la_matrice_d_inertie_du__fond'... */ Bblock CLIR(Iremplissage_voisinage_____nombre_de_points_du__fond); CLIR(ASD1(Iremplissage_voisinage_____centre_de_gravite_du__fond,x)); CLIR(ASD1(Iremplissage_voisinage_____centre_de_gravite_du__fond,y)); /* Initialisations diverses... */ Eblock ATes Bblock CLIR(ASD2(Iremplissage_voisinage_____matrice_d_inertie_du__fond,cx,cx)); CLIR(ASD2(Iremplissage_voisinage_____matrice_d_inertie_du__fond,cx,cy)); CLIR(ASD2(Iremplissage_voisinage_____matrice_d_inertie_du__fond,cy,cx)); CLIR(ASD2(Iremplissage_voisinage_____matrice_d_inertie_du__fond,cy,cy)); /* Initialisations diverses... */ Eblock ETes CALS(Iremplissage_voisinage(imageR ,imageA ,X,Y ,_cDENORMALISE_OX(ASI1(coin_inferieur_gauche,x)),_cDENORMALISE_OX(ASI1(coin_superieur_droite,x)) ,_cDENORMALISE_OY(ASI1(coin_inferieur_gauche,y)),_cDENORMALISE_OY(ASI1(coin_superieur_droite,y)) ,fond,bord ,est_______,nord______,ouest_____,sud_______ ,nord_est__,nord_ouest,sud_ouest_,sud_est___ ,CASP_Float(niveau_de_remplissage) ) ); /* Et remplissage recursif, voisinage par voisinage a partir */ /* du point de depart argument... */ /* */ /* La procedure 'CASP_Float(...)' a remplace un 'CASP(genere_Float,...)' le 20090331104759. */ Test(IZNE(Iremplissage_voisinage_____nombre_de_points_du__fond)) Bblock Test(IL_NE_FAUT_PAS(Iremplissage_voisinage_____calculer_la_matrice_d_inertie_du__fond)) Bblock EGAL(ASD1(Iremplissage_voisinage_____centre_de_gravite_du__fond,x) ,DIVI(ASD1(Iremplissage_voisinage_____centre_de_gravite_du__fond,x) ,FLOT(Iremplissage_voisinage_____nombre_de_points_du__fond) ) ); EGAL(ASD1(Iremplissage_voisinage_____centre_de_gravite_du__fond,y) ,DIVI(ASD1(Iremplissage_voisinage_____centre_de_gravite_du__fond,y) ,FLOT(Iremplissage_voisinage_____nombre_de_points_du__fond) ) ); /* Calcul "final" du centre de gravite (introduit le 20161105103427). */ Test(IL_FAUT(Iremplissage_____editer_le_centre_de_gravite)) Bblock CAL3(Prme1("NombreDePoints=%d\n" ,Iremplissage_voisinage_____nombre_de_points_du__fond ) ); CAL3(Prme2("XG=%+.^^^ YG=%+.^^^\n" ,ASD1(Iremplissage_voisinage_____centre_de_gravite_du__fond,x) ,ASD1(Iremplissage_voisinage_____centre_de_gravite_du__fond,y) ) ); /* Edition introduite le 20161105105224... */ Eblock ATes Bblock Eblock ETes Eblock ATes Bblock EGAL(ASD2(Iremplissage_voisinage_____matrice_d_inertie_du__fond,cx,cx) ,DIVI(ASD2(Iremplissage_voisinage_____matrice_d_inertie_du__fond,cx,cx) ,FLOT(Iremplissage_voisinage_____nombre_de_points_du__fond) ) ); EGAL(ASD2(Iremplissage_voisinage_____matrice_d_inertie_du__fond,cx,cy) ,DIVI(ASD2(Iremplissage_voisinage_____matrice_d_inertie_du__fond,cx,cy) ,FLOT(Iremplissage_voisinage_____nombre_de_points_du__fond) ) ); EGAL(ASD2(Iremplissage_voisinage_____matrice_d_inertie_du__fond,cy,cx) ,DIVI(ASD2(Iremplissage_voisinage_____matrice_d_inertie_du__fond,cy,cx) ,FLOT(Iremplissage_voisinage_____nombre_de_points_du__fond) ) ); EGAL(ASD2(Iremplissage_voisinage_____matrice_d_inertie_du__fond,cy,cy) ,DIVI(ASD2(Iremplissage_voisinage_____matrice_d_inertie_du__fond,cy,cy) ,FLOT(Iremplissage_voisinage_____nombre_de_points_du__fond) ) ); /* Calcul "final" de la matrice d'inertie (introduit le 20230825094226). */ Test(IL_FAUT(Iremplissage_____editer_la_matrice_d_inertie)) Bblock CAL3(Prme1("NombreDePoints=%d\n" ,Iremplissage_voisinage_____nombre_de_points_du__fond ) ); CAL3(Prme4("MatriceInertie={{%+.^^^,%+.^^^},{%+.^^^,%+.^^^}}\n" ,ASD2(Iremplissage_voisinage_____matrice_d_inertie_du__fond,cx,cx) ,ASD2(Iremplissage_voisinage_____matrice_d_inertie_du__fond,cx,cy) ,ASD2(Iremplissage_voisinage_____matrice_d_inertie_du__fond,cy,cx) ,ASD2(Iremplissage_voisinage_____matrice_d_inertie_du__fond,cy,cy) ) ); /* Edition introduite le 20230825094226... */ Eblock ATes Bblock Eblock ETes Eblock ETes Eblock ATes Bblock EGAL(ASD1(Iremplissage_voisinage_____centre_de_gravite_du__fond,x),FLOT(X)); EGAL(ASD1(Iremplissage_voisinage_____centre_de_gravite_du__fond,y),FLOT(Y)); /* Dans ce cas, le centre de gravite (qui n'existe en fait pas) est le point de depart */ /* {X,Y} (introduit le 20161105120709...). */ Eblock ETes ESaveModifyVariable(Logical ,Iremplissage_voisinage_____calculer_l_histogramme_du__bord ); /* Pour des raisons d'imbrication, ce 'ESaveModifyVariable(...)' ne peut pas etre situe */ /* dans un 'Test(IL_FAUT(Iremplissage_____calculer_l_histogramme_du__bord))'... */ RETI(imageR); Eblock EFonctionP /*===================================================================================================================================*/ /*************************************************************************************************************************************/ /* */ /* E X T R A C T I O N D E T O U S L E S P O I N T S D E D E P A R T P O T E N T I E L S */ /* D ' U N R E M P L I S S A G E D E C O N T O U R A L ' E X C L U S I O N D ' U N */ /* N I V E A U D I T D E ' N O N M A R Q U A G E ' : */ /* */ /*************************************************************************************************************************************/ BFonctionI DEFV(Common,DEFV(FonctionI,Ipoints_de_depart(liste_des_points_de_depart ,zones_remplies ,imageA ,est_______,nord______,ouest_____,sud_______ ,nord_est__,nord_ouest,sud_ouest_,sud_est___ ,largeur_de_bande ,niveau_de_non_marquage ) ) ) DEFV(Argument,DEFV(image,liste_des_points_de_depart)); /* Image Resultat contenant les points de depart des remplissage. */ DEFV(Argument,DEFV(image,zones_remplies)); /* Image Resultat contenant les remplissages generes... */ DEFV(Argument,DEFV(image,imageA)); /* Image Argument. */ DEFV(Argument,DEFV(Logical,est_______)); /* Variable logique indiquant si l'on doit emprunter la direction 'est' */ /* ('VRAI') ou pas ('FAUX') lors du parcours recursif de l'interieur */ /* du contour. */ DEFV(Argument,DEFV(Logical,nord______)); /* Variable logique indiquant si l'on doit emprunter la direction 'nord' */ /* ('VRAI') ou pas ('FAUX') lors du parcours recursif de l'interieur */ /* du contour. */ DEFV(Argument,DEFV(Logical,ouest_____)); /* Variable logique indiquant si l'on doit emprunter la direction 'ouest' */ /* ('VRAI') ou pas ('FAUX') lors du parcours recursif de l'interieur */ /* du contour. */ DEFV(Argument,DEFV(Logical,sud_______)); /* Variable logique indiquant si l'on doit emprunter la direction 'sud' */ /* ('VRAI') ou pas ('FAUX') lors du parcours recursif de l'interieur */ /* du contour. */ DEFV(Argument,DEFV(Logical,nord_est__)); /* Variable logique indiquant si l'on doit emprunter la direction 'nord_est' */ /* ('VRAI') ou pas ('FAUX') lors du parcours recursif de l'interieur */ /* du contour. */ DEFV(Argument,DEFV(Logical,nord_ouest)); /* Variable logique indiquant si l'on doit emprunter la direction 'nord_ouest' */ /* ('VRAI') ou pas ('FAUX') lors du parcours recursif de l'interieur */ /* du contour. */ DEFV(Argument,DEFV(Logical,sud_ouest_)); /* Variable logique indiquant si l'on doit emprunter la direction 'sud_ouest' */ /* ('VRAI') ou pas ('FAUX') lors du parcours recursif de l'interieur */ /* du contour. */ DEFV(Argument,DEFV(Logical,sud_est___)); /* Variable logique indiquant si l'on doit emprunter la direction 'sud_est' */ /* ('VRAI') ou pas ('FAUX') lors du parcours recursif de l'interieur */ /* du contour. */ DEFV(Argument,DEFV(Int,largeur_de_bande)); /* Lorsque l'on trouve un point {X,Y} non encore marque (dans 'zones_remplies'), on */ /* l'utilise comme point de depart pour un remplissage de contour ; sont consideres */ /* comme a remplir, les points dont les niveaux sont dans l'intervalle [N-L,N+L], */ /* ou 'N' designe le niveau du point {X,Y} dans 'imageA', et 'L' la */ /* 'largeur_de_bande' ('ZERO' donnera le plus de finesse...). */ DEFV(Argument,DEFV(genere_p,niveau_de_non_marquage)); /* Niveau destine a marquer dans 'zones_remplies' les points non encore */ /* rencontres ; il correspond aussi aux points de 'imageA' qui sont ignores. */ /*-----------------------------------------------------------------------------------------------------------------------------------*/ Bblock INIT_ERROR; /* ATTENTION : 'INIT_ERROR' est mis en tete des variables locales au cas ou des couples */ /* ('BDEFV','EDEFV') suivraient... */ DEFV(genere_p,INIT(niveau_du_point_courant,NIVEAU_UNDEF)); /* Niveau du point courant {X,Y}. */ DEFV(pointF_2D,point_de_depart); DEFV(pointF_2D,coin_inferieur_gauche); /* Coin inferieur gauche de la zone de remplissage, */ DEFV(pointF_2D,coin_superieur_droite); /* Coin superieur droite de la zone de remplissage. */ DEFV(Logical,DTb1(fond,COULEURS)); /* Pour definir le fond courant, et */ DEFV(Logical,DTb1(bord,COULEURS)); /* Pour definir le bord courant. */ /*..............................................................................................................................*/ MISE_A_L_ETAT_INITIAL_LISTE_DE_SUBSTITUTION; /* Lorsque la liste de substitution n'a pas ete encore initialisee, */ /* on le fait avant la validation... */ CALS(Inoir(liste_des_points_de_depart)); /* Nettoyage de la liste des points de depart. */ PUSH_FILTRAGE; /* Sauvegarde de l'etat courant du filtrage des niveaux. */ SET_FILTRAGE(ACTIF); /* On autorise tous les filtrages afin d'avoir la 'SUBSTITUTION'. */ PUSH_SUBSTITUTION; /* Sauvegarde de la substitution courante. */ BoIn(index_des_listes,NOIR,BLANC,PAS_COULEURS) Bblock Test(IFNE(index_des_listes,niveau_de_non_marquage)) Bblock Test(IFEQ(Nsubstitution(GENP(index_des_listes)),niveau_de_non_marquage)) Bblock PRINT_ERREUR("le 'niveau_de_non_marquage' et la 'liste de substitution' courante sont incompatibles"); Eblock ATes Bblock Eblock ETes Eblock ATes Bblock Eblock ETes Eblock EBoI PULL_SUBSTITUTION; PULL_FILTRAGE; /* Et restauration des conditions initiales... */ CALS(Iinitialisation(zones_remplies,niveau_de_non_marquage)); /* On n'a encore marque aucun point... */ INITIALISATION_POINT_2D(coin_inferieur_gauche ,CADRE_GAUCHE ,CADRE_INFERIEUR ); /* Definition du coin inferieur gauche de remplissage, */ INITIALISATION_POINT_2D(coin_superieur_droite ,CADRE_DROITE ,CADRE_SUPERIEUR ); /* Definition du coin superieur droite de remplissage. */ begin_image Bblock Test(IFEQ(load_point(zones_remplies,X,Y),niveau_de_non_marquage)) Bblock /* On ne s'interesse qu'au point qui n'ont pas ete atteint lors d'un */ /* remplissage avec un point de depart anterieur... */ EGAL(niveau_du_point_courant,load_point(imageA,X,Y)); /* Recuperation du niveau du point courant dans l'image Argument. */ Test(IFNE(niveau_du_point_courant,niveau_de_non_marquage)) Bblock /* On ne s'interesse qu'au point de 'imageA' qui sont non marques, et ce */ /* afin que les tests qui sont faits dans 'zones_remplies' fonctionnent */ /* correctement... */ store_point(niveau_du_point_courant,liste_des_points_de_depart,X,Y,FVARIABLE); /* Et on memorise ce point... */ INITIALISATION_POINT_2D(point_de_depart ,_____cNORMALISE_OX(X) ,_____cNORMALISE_OY(Y) ); /* Et il devient un nouveau point de depart. ATTENTION, avant le 19990602152323, il y avait */ /* ici pour des raisons obscures (et en fait surement historiques) : */ /* */ /* INITIALISATION_POINT_2D(point_de_depart */ /* ,DIVI(FLOT(X),FLOT(dimX)) */ /* ,DIVI(FLOT(Y),FLOT(dimY)) */ /* ) */ /* */ BoIn(index_des_listes,NOIR,BLANC,PAS_COULEURS) Bblock EGAL(ITb1(fond,INDX(index_des_listes,NOIR)),FAUX); EGAL(ITb1(bord,INDX(index_des_listes,NOIR)),VRAI); /* Reinitialisation des listes 'fond' et 'bord'. */ Eblock EBoI BoIn(index_des_listes ,MAX2(NOIR,SOUS(niveau_du_point_courant,largeur_de_bande)) ,MIN2(BLANC,ADD2(niveau_du_point_courant,largeur_de_bande)) ,I ) Bblock EGAL(ITb1(fond,INDX(index_des_listes,NOIR)),VRAI); EGAL(ITb1(bord,INDX(index_des_listes,NOIR)),FAUX); /* On considere que "tout" est du "bord", sauf evidemment les points */ /* qui ont le meme niveau que le point courant (a 'largeur_de_bande' pres), */ /* et qui forment le "fond". */ Eblock EBoI CALS(Iremplissage(zones_remplies ,imageA ,ADRESSE(point_de_depart) ,ADRESSE(coin_inferieur_gauche) ,ADRESSE(coin_superieur_droite) ,fond,bord ,est_______,nord______,ouest_____,sud_______ ,nord_est__,nord_ouest,sud_ouest_,sud_est___ ,niveau_du_point_courant ) ); /* Marquage des points par lesquels on est passe... */ Eblock ATes Bblock Eblock ETes Eblock ATes Bblock Eblock ETes Eblock end_image RETU_ERROR; Eblock EFonctionI _______________________________________________________________________________________________________________________________________ _______________________________________________________________________________________________________________________________________ /*===================================================================================================================================*/ /*************************************************************************************************************************************/ /* */ /* R E M P L I S S A G E D U V O I S I N A G E D ' U N P O I N T D ' U N A L B U M : */ /* */ /*************************************************************************************************************************************/ BFonctionI DEFV(Common,DEFV(Float,SINT(Aremplissage_voisinage_____increment_recursif_du_niveau_de_remplissage,FZERO))); /* Cet increment (ou decrement, suivant son signe...) permet de changer le niveau de */ /* remplissage a chaque nouveau niveau de recursivite... */ DEFV(Common,DEFV(Logical,SINT(Aremplissage_voisinage_____calculer_l_histogramme_du__bord,FAUX))); /* Cet indicateur permet de calculer l'histogramme du 'bord' en particulier pour savoir */ /* quel est son niveau majoritaire... */ DEFV(Common,DEFV(Int,SINT(Aremplissage_voisinage_____nombre_de_points_du__fond,ZERO))); DEFV(Common,DEFV(pointF_3D,Aremplissage_voisinage_____centre_de_gravite_du__fond)); DEFV(Common,DEFV(Logical,SINT(Aremplissage_voisinage_____rechercher_le_niveau_maximal_d_un_point_isole,FAUX))); DEFV(Common,DEFV(genere_Float,SINT(Aremplissage_voisinage_____niveau_maximal_d_un_point_isole,F_MOINS_L_INFINI))); /* Afin de calculer le niveau maximal du fond. On notera l'usage de 'genere_Float' et non */ /* pas de 'genere_p' afin de faciliter la recherche de ce maximum... */ #define TEST_REMPLISSAGE_POINT_ISOLE(direction,x,y,z) \ Bblock \ Test(IL_FAUT(direction)) \ Bblock \ Test(TEST_DANS_L_ALBUM(x,y,z)) \ Bblock \ DEFV(genere_p,INIT(voisin,Aload_point(albumA,x,y,z))); \ /* Recuperation du niveau du point courant. */ \ \ INCR(nombre_de_voisins_total,I); \ \ Test(EST_VRAI(ITb1(fond,INDX(voisin,NOIR)))) \ Bblock \ INCR(nombre_de_voisins_appartenant_au_fond,I); \ Eblock \ ATes \ Bblock \ Eblock \ ETes \ Eblock \ ATes \ Bblock \ Eblock \ ETes \ Eblock \ ATes \ Bblock \ Eblock \ ETes \ Eblock #define MOVE_REMPLISSAGE(direction,x,y,z) \ Bblock \ Test(IL_FAUT(direction)) \ Bblock \ CALS(Aremplissage_voisinage(albumR \ ,albumA \ ,AlbumMarqueur \ ,x,y,z \ ,coin_gauche,coin_droite \ ,coin_inferieur,coin_superieur \ ,coin_avant,coin_arriere \ ,fond,bord \ ,dc__6 \ ,dc__5 \ ,dc_4_ \ ,dc_46 \ ,dc_45 \ ,dc_2_ \ ,dc_26 \ ,dc_25 \ ,dc3__ \ ,dc3_6 \ ,dc3_5 \ ,dc34_ \ ,dc346 \ ,dc345 \ ,dc32_ \ ,dc326 \ ,dc325 \ ,dc1__ \ ,dc1_6 \ ,dc1_5 \ ,dc14_ \ ,dc146 \ ,dc145 \ ,dc12_ \ ,dc126 \ ,dc125 \ ,ADD2(niveau_de_remplissage \ ,Aremplissage_voisinage_____increment_recursif_du_niveau_de_remplissage \ ) \ ) \ ); \ Eblock \ ATes \ Bblock \ Eblock \ ETes \ Eblock \ /* Fonction de test de la necessite de faire un deplacement dans */ \ /* une 'direction' argument, et si oui, donc, remplir le voisinage */ \ /* du point courant dans cette direction. */ DEFV(Local,DEFV(FonctionI,Aremplissage_voisinage(albumR ,albumA ,AlbumMarqueur ,X,Y,Z ,coin_gauche,coin_droite ,coin_inferieur,coin_superieur ,coin_avant,coin_arriere ,fond,bord ,dc__6 ,dc__5 ,dc_4_ ,dc_46 ,dc_45 ,dc_2_ ,dc_26 ,dc_25 ,dc3__ ,dc3_6 ,dc3_5 ,dc34_ ,dc346 ,dc345 ,dc32_ ,dc326 ,dc325 ,dc1__ ,dc1_6 ,dc1_5 ,dc14_ ,dc146 ,dc145 ,dc12_ ,dc126 ,dc125 ,niveau_de_remplissage ) ) ) /* Fonction introduite le 20231201121707... */ DEFV(Argument,DEFV(album,albumR)); /* Album Resultat contenant le remplissage du contour Argument. */ DEFV(Argument,DEFV(album,albumA)); /* Album Argument. */ DEFV(Argument,DEFV(album,AlbumMarqueur)); /* Album de marquage (introduit le 20231202121504)... */ DEFV(Argument,DEFV(Int,X)); DEFV(Argument,DEFV(Int,Y)); DEFV(Argument,DEFV(Int,Z)); /* Coordonnees entieres 'X', 'Y' et 'Z'. */ DEFV(Argument,DEFV(Int,coin_gauche)); DEFV(Argument,DEFV(Int,coin_droite)); DEFV(Argument,DEFV(Int,coin_inferieur)); DEFV(Argument,DEFV(Int,coin_superieur)); DEFV(Argument,DEFV(Int,coin_avant)); DEFV(Argument,DEFV(Int,coin_arriere)); /* Definition du cadre a l'interieur duquel se fait le remplissage. */ DEFV(Argument,DEFV(Logical,DTb1(fond,COULEURS))); /* Definit ainsi pour chaque niveau s'il appartient ('VRAI') ou pas */ /* ('FAUX') au fond, c'est-a-dire a ce que l'on doit remplir. */ DEFV(Argument,DEFV(Logical,DTb1(bord,COULEURS))); /* Definit ainsi pour chaque niveau s'il appartient ('VRAI') ou pas */ /* ('FAUX') au bord, c'est-a-dire a ce qui delimite le contour. */ DEFV(Argument,DEFV(Logical,dc__6)); DEFV(Argument,DEFV(Logical,dc__5)); DEFV(Argument,DEFV(Logical,dc_4_)); DEFV(Argument,DEFV(Logical,dc_46)); DEFV(Argument,DEFV(Logical,dc_45)); DEFV(Argument,DEFV(Logical,dc_2_)); DEFV(Argument,DEFV(Logical,dc_26)); DEFV(Argument,DEFV(Logical,dc_25)); DEFV(Argument,DEFV(Logical,dc3__)); DEFV(Argument,DEFV(Logical,dc3_6)); DEFV(Argument,DEFV(Logical,dc3_5)); DEFV(Argument,DEFV(Logical,dc34_)); DEFV(Argument,DEFV(Logical,dc346)); DEFV(Argument,DEFV(Logical,dc345)); DEFV(Argument,DEFV(Logical,dc32_)); DEFV(Argument,DEFV(Logical,dc326)); DEFV(Argument,DEFV(Logical,dc325)); DEFV(Argument,DEFV(Logical,dc1__)); DEFV(Argument,DEFV(Logical,dc1_6)); DEFV(Argument,DEFV(Logical,dc1_5)); DEFV(Argument,DEFV(Logical,dc14_)); DEFV(Argument,DEFV(Logical,dc146)); DEFV(Argument,DEFV(Logical,dc145)); DEFV(Argument,DEFV(Logical,dc12_)); DEFV(Argument,DEFV(Logical,dc126)); DEFV(Argument,DEFV(Logical,dc125)); /* Definition des Dimensions Cardinales a utiliser.... */ DEFV(Argument,DEFV(genere_Float,niveau_de_remplissage)); /* Niveau a utiliser pour remplir le contour Argument. */ /*-----------------------------------------------------------------------------------------------------------------------------------*/ Bblock INIT_ERROR; /* ATTENTION : 'INIT_ERROR' est mis en tete des variables locales au cas ou des couples */ /* ('BDEFV','EDEFV') suivraient... */ /*..............................................................................................................................*/ Test(IFET(TEST_DANS_L_ALBUM(X,Y,Z) ,I3ET(INCLff(X,coin_gauche,coin_droite) ,INCLff(Y,coin_inferieur,coin_superieur) ,INCLff(Z,coin_avant,coin_arriere) ) ) ) Bblock Test(gTEST_POINT_ALBUM_NON_MARQUE(AlbumMarqueur,X,Y,Z)) Bblock /* On ne traite que les points sur lesquels on n'est pas encore passe ; on */ /* notera qu'il serait imprudent de tester 'NIVEAU_DE_MARQUAGE' avec */ /* un 'IFEQ' a cause des problemes lies aux 'liste de substitution'. */ DEFV(genere_p,INIT(point,Aload_point(albumA,X,Y,Z))); /* Recuperation du niveau du point courant. */ Test(IL_FAUT(Aremplissage_voisinage_____rechercher_le_niveau_maximal_d_un_point_isole)) Bblock Test(EST_FAUX(ITb1(fond,INDX(point,NOIR)))) Bblock DEFV(Int,INIT(nombre_de_voisins_total,ZERO)); DEFV(Int,INIT(nombre_de_voisins_appartenant_au_fond,ZERO)); TEST_REMPLISSAGE_POINT_ISOLE(dc__6,NEUT(X),NEUT(Y),PREZ(Z)); TEST_REMPLISSAGE_POINT_ISOLE(dc__5,NEUT(X),NEUT(Y),SUCZ(Z)); TEST_REMPLISSAGE_POINT_ISOLE(dc_4_,NEUT(X),PREY(Y),NEUT(Z)); TEST_REMPLISSAGE_POINT_ISOLE(dc_46,NEUT(X),PREY(Y),PREZ(Z)); TEST_REMPLISSAGE_POINT_ISOLE(dc_45,NEUT(X),PREY(Y),SUCZ(Z)); TEST_REMPLISSAGE_POINT_ISOLE(dc_2_,NEUT(X),SUCY(Y),NEUT(Z)); TEST_REMPLISSAGE_POINT_ISOLE(dc_26,NEUT(X),SUCY(Y),PREZ(Z)); TEST_REMPLISSAGE_POINT_ISOLE(dc_25,NEUT(X),SUCY(Y),SUCZ(Z)); TEST_REMPLISSAGE_POINT_ISOLE(dc3__,PREX(X),NEUT(Y),NEUT(Z)); TEST_REMPLISSAGE_POINT_ISOLE(dc3_6,PREX(X),NEUT(Y),PREZ(Z)); TEST_REMPLISSAGE_POINT_ISOLE(dc3_5,PREX(X),NEUT(Y),SUCZ(Z)); TEST_REMPLISSAGE_POINT_ISOLE(dc34_,PREX(X),PREY(Y),NEUT(Z)); TEST_REMPLISSAGE_POINT_ISOLE(dc346,PREX(X),PREY(Y),PREZ(Z)); TEST_REMPLISSAGE_POINT_ISOLE(dc345,PREX(X),PREY(Y),SUCZ(Z)); TEST_REMPLISSAGE_POINT_ISOLE(dc32_,PREX(X),SUCY(Y),NEUT(Z)); TEST_REMPLISSAGE_POINT_ISOLE(dc326,PREX(X),SUCY(Y),PREZ(Z)); TEST_REMPLISSAGE_POINT_ISOLE(dc325,PREX(X),SUCY(Y),SUCZ(Z)); TEST_REMPLISSAGE_POINT_ISOLE(dc1__,SUCX(X),NEUT(Y),NEUT(Z)); TEST_REMPLISSAGE_POINT_ISOLE(dc1_6,SUCX(X),NEUT(Y),PREZ(Z)); TEST_REMPLISSAGE_POINT_ISOLE(dc1_5,SUCX(X),NEUT(Y),SUCZ(Z)); TEST_REMPLISSAGE_POINT_ISOLE(dc14_,SUCX(X),PREY(Y),NEUT(Z)); TEST_REMPLISSAGE_POINT_ISOLE(dc146,SUCX(X),PREY(Y),PREZ(Z)); TEST_REMPLISSAGE_POINT_ISOLE(dc145,SUCX(X),PREY(Y),SUCZ(Z)); TEST_REMPLISSAGE_POINT_ISOLE(dc12_,SUCX(X),SUCY(Y),NEUT(Z)); TEST_REMPLISSAGE_POINT_ISOLE(dc126,SUCX(X),SUCY(Y),PREZ(Z)); TEST_REMPLISSAGE_POINT_ISOLE(dc125,SUCX(X),SUCY(Y),SUCZ(Z)); /* Ce qui precede a ete obtenu a l'aide du programme '$c' suivant : */ /* */ /* */ /* #include <stdio.h> */ /* */ /* #define X1(x) (((x)>0) ? '1' : (((x)<0) ? '3' : '_')) */ /* #define Y1(y) (((y)>0) ? '2' : (((y)<0) ? '4' : '_')) */ /* #define Z1(z) (((z)>0) ? '5' : (((z)<0) ? '6' : '_')) */ /* */ /* #define X2(x) (((x)>0) ? "SUCX(X)" : (((x)<0) ? "PREX(X)" : "NEUT(X)")) */ /* #define Y2(y) (((y)>0) ? "SUCY(Y)" : (((y)<0) ? "PREY(Y)" : "NEUT(Y)")) */ /* #define Z2(z) (((z)>0) ? "SUCZ(Z)" : (((z)<0) ? "PREZ(Z)" : "NEUT(Z)")) */ /* */ /* main() */ /* { */ /* int x,y,z; */ /* */ /* for (x=-1 ; x<=+1 ; x++) */ /* { */ /* for (y=-1 ; y<=+1 ; y++) */ /* { */ /* for (z=-1 ; z<=+1 ; z++) */ /* { */ /* if ((x==0) && (y==0) & (z==0)) */ /* { */ /* } */ /* else */ /* { */ /* printf("procedure("); */ /* printf("dc%c%c%c",X1(x),Y1(y),Z1(z)); */ /* printf(","); */ /* printf("%s,%s,%s",X2(x),Y2(y),Z2(z)); */ /* printf(");\n"); */ /* } */ /* } */ /* } */ /* } */ /* } */ /* */ /* */ /* (voir 'v $xtc/DirectionsCardinales.01$c' a ce propos). */ Test(IFEQ(nombre_de_voisins_appartenant_au_fond,nombre_de_voisins_total)) /* Le point courant {X,Y} n'est pas du 'fond' et n'a pas de voisin, il est donc isole : */ Bblock EGAL(Aremplissage_voisinage_____niveau_maximal_d_un_point_isole ,MAX2(Aremplissage_voisinage_____niveau_maximal_d_un_point_isole,FLOT(point)) ); Eblock ATes Bblock Eblock ETes Eblock ATes Bblock Eblock ETes Eblock ATes Bblock Eblock ETes Test(EST_FAUX(ITb1(bord,INDX(point,NOIR)))) Bblock gMARQUAGE_POINT_ALBUM(AlbumMarqueur,X,Y,Z); /* Marquage systematique des points qui ne sont pas au bord dans une album */ /* de travail, afin d'eviter des "trous" crees par exemple lorsque les */ /* listes de "bord" et de "fond" ne sont pas complementaires. */ Test(EST_VRAI(ITb1(fond,INDX(point,NOIR)))) Bblock /* Traitement des points qui n'appartiennent pas au "bord", et */ /* qui appartiennent au "fond". */ Astore_point(GENP(TRNP(niveau_de_remplissage)),albumR,X,Y,Z); /* Finalement, remplissage du point courant {X,Y} qui appartient au "fond", */ /* n'appartient pas au "bord" et n'est pas masque (ou bien l'est, mais */ /* est compatible avec le seuil et la portee du masquage...). */ INCR(Aremplissage_voisinage_____nombre_de_points_du__fond,I); /* Comptage des points. */ INCR(ASD1(Aremplissage_voisinage_____centre_de_gravite_du__fond,x),FLOT(X)); INCR(ASD1(Aremplissage_voisinage_____centre_de_gravite_du__fond,y),FLOT(Y)); INCR(ASD1(Aremplissage_voisinage_____centre_de_gravite_du__fond,y),FLOT(Z)); /* Calcul "iteratif" du centre de gravite. */ Eblock ATes Bblock Eblock ETes /* Puis, on passe aux voisins, suivant la regle de connexite demandee : */ MOVE_REMPLISSAGE(dc__6,NEUT(X),NEUT(Y),PREZ(Z)); MOVE_REMPLISSAGE(dc__5,NEUT(X),NEUT(Y),SUCZ(Z)); MOVE_REMPLISSAGE(dc_4_,NEUT(X),PREY(Y),NEUT(Z)); MOVE_REMPLISSAGE(dc_46,NEUT(X),PREY(Y),PREZ(Z)); MOVE_REMPLISSAGE(dc_45,NEUT(X),PREY(Y),SUCZ(Z)); MOVE_REMPLISSAGE(dc_2_,NEUT(X),SUCY(Y),NEUT(Z)); MOVE_REMPLISSAGE(dc_26,NEUT(X),SUCY(Y),PREZ(Z)); MOVE_REMPLISSAGE(dc_25,NEUT(X),SUCY(Y),SUCZ(Z)); MOVE_REMPLISSAGE(dc3__,PREX(X),NEUT(Y),NEUT(Z)); MOVE_REMPLISSAGE(dc3_6,PREX(X),NEUT(Y),PREZ(Z)); MOVE_REMPLISSAGE(dc3_5,PREX(X),NEUT(Y),SUCZ(Z)); MOVE_REMPLISSAGE(dc34_,PREX(X),PREY(Y),NEUT(Z)); MOVE_REMPLISSAGE(dc346,PREX(X),PREY(Y),PREZ(Z)); MOVE_REMPLISSAGE(dc345,PREX(X),PREY(Y),SUCZ(Z)); MOVE_REMPLISSAGE(dc32_,PREX(X),SUCY(Y),NEUT(Z)); MOVE_REMPLISSAGE(dc326,PREX(X),SUCY(Y),PREZ(Z)); MOVE_REMPLISSAGE(dc325,PREX(X),SUCY(Y),SUCZ(Z)); MOVE_REMPLISSAGE(dc1__,SUCX(X),NEUT(Y),NEUT(Z)); MOVE_REMPLISSAGE(dc1_6,SUCX(X),NEUT(Y),PREZ(Z)); MOVE_REMPLISSAGE(dc1_5,SUCX(X),NEUT(Y),SUCZ(Z)); MOVE_REMPLISSAGE(dc14_,SUCX(X),PREY(Y),NEUT(Z)); MOVE_REMPLISSAGE(dc146,SUCX(X),PREY(Y),PREZ(Z)); MOVE_REMPLISSAGE(dc145,SUCX(X),PREY(Y),SUCZ(Z)); MOVE_REMPLISSAGE(dc12_,SUCX(X),SUCY(Y),NEUT(Z)); MOVE_REMPLISSAGE(dc126,SUCX(X),SUCY(Y),PREZ(Z)); MOVE_REMPLISSAGE(dc125,SUCX(X),SUCY(Y),SUCZ(Z)); Eblock ATes Bblock Test(IL_FAUT(Aremplissage_voisinage_____calculer_l_histogramme_du__bord)) Bblock INCR(ACCES_HISTOGRAMME(point),I); /* Le niveau 'point' fait partie du 'bord'... */ Eblock ATes Bblock Eblock ETes Eblock ETes Eblock ATes Bblock Eblock ETes Eblock ATes Bblock Eblock ETes RETU_ERROR; Eblock #undef MOVE_REMPLISSAGE #undef TEST_REMPLISSAGE_POINT_ISOLE EFonctionI /*===================================================================================================================================*/ /*************************************************************************************************************************************/ /* */ /* R E M P L I S S A G E R E C U R S I F D ' U N C O N T O U R D ' U N A L B U M : */ /* */ /*************************************************************************************************************************************/ BFonctionP DEFV(Common,DEFV(Logical,SINT(Aremplissage_____editer_le_centre_de_gravite,FAUX))); DEFV(Common,DEFV(Logical,SINT(Aremplissage_____calculer_l_histogramme_du__bord,FAUX))); DEFV(Common,DEFV(FonctionP,POINTERp(Aremplissage(albumR ,albumA ,AlbumMarqueur ,ARGUMENT_POINTERs(point_de_depart) ,ARGUMENT_POINTERs(coin_inferieur_gauche_avant) ,ARGUMENT_POINTERs(coin_superieur_droite_arriere) ,fond,bord ,dc__6 ,dc__5 ,dc_4_ ,dc_46 ,dc_45 ,dc_2_ ,dc_26 ,dc_25 ,dc3__ ,dc3_6 ,dc3_5 ,dc34_ ,dc346 ,dc345 ,dc32_ ,dc326 ,dc325 ,dc1__ ,dc1_6 ,dc1_5 ,dc14_ ,dc146 ,dc145 ,dc12_ ,dc126 ,dc125 ,niveau_de_remplissage ) ) ) ) /* Fonction introduite le 20231201121707... */ DEFV(Argument,DEFV(album,albumR)); /* Image Resultat contenant le remplissage du contour Argument. */ DEFV(Argument,DEFV(album,albumA)); /* Image Argument. */ DEFV(Argument,DEFV(album,AlbumMarqueur)); /* Album de marquage (introduit le 20231202121504)... */ DEFV(Argument,DEFV(pointF_3D,POINTERs(point_de_depart))); /* Coordonnees du point de depart de remplissage exprimees dans des */ /* unites telles que l'unite vaut respectivement [Xmin,Xmax] et */ /* [Ymin,Ymax]. */ DEFV(Argument,DEFV(pointF_3D,POINTERs(coin_inferieur_gauche_avant))); /* Le remplissage ne sera fait qu'a l'interieur d'un "cadre" que l'on */ /* definit par son coin inferieur gauche, */ DEFV(Argument,DEFV(pointF_3D,POINTERs(coin_superieur_droite_arriere))); /* Definit par son coin superieur droit ; ainsi, on pourra remplir */ /* des contours ouverts dont le "cadre" proviendra du "cadre" defini */ /* lors du trace des vecteurs 3D. */ DEFV(Argument,DEFV(Logical,DTb1(fond,COULEURS))); /* Definit ainsi pour chaque niveau s'il appartient ('VRAI') ou pas */ /* ('FAUX') au fond, c'est-a-dire a ce que l'on doit remplir. */ DEFV(Argument,DEFV(Logical,DTb1(bord,COULEURS))); /* Definit ainsi pour chaque niveau s'il appartient ('VRAI') ou pas */ /* ('FAUX') au bord, c'est-a-dire a ce qui delimite le contour. */ DEFV(Argument,DEFV(Logical,dc__6)); DEFV(Argument,DEFV(Logical,dc__5)); DEFV(Argument,DEFV(Logical,dc_4_)); DEFV(Argument,DEFV(Logical,dc_46)); DEFV(Argument,DEFV(Logical,dc_45)); DEFV(Argument,DEFV(Logical,dc_2_)); DEFV(Argument,DEFV(Logical,dc_26)); DEFV(Argument,DEFV(Logical,dc_25)); DEFV(Argument,DEFV(Logical,dc3__)); DEFV(Argument,DEFV(Logical,dc3_6)); DEFV(Argument,DEFV(Logical,dc3_5)); DEFV(Argument,DEFV(Logical,dc34_)); DEFV(Argument,DEFV(Logical,dc346)); DEFV(Argument,DEFV(Logical,dc345)); DEFV(Argument,DEFV(Logical,dc32_)); DEFV(Argument,DEFV(Logical,dc326)); DEFV(Argument,DEFV(Logical,dc325)); DEFV(Argument,DEFV(Logical,dc1__)); DEFV(Argument,DEFV(Logical,dc1_6)); DEFV(Argument,DEFV(Logical,dc1_5)); DEFV(Argument,DEFV(Logical,dc14_)); DEFV(Argument,DEFV(Logical,dc146)); DEFV(Argument,DEFV(Logical,dc145)); DEFV(Argument,DEFV(Logical,dc12_)); DEFV(Argument,DEFV(Logical,dc126)); DEFV(Argument,DEFV(Logical,dc125)); DEFV(Argument,DEFV(genere_p,niveau_de_remplissage)); /* Niveau a utiliser pour remplir le contour Argument. */ /*-----------------------------------------------------------------------------------------------------------------------------------*/ Bblock DEFV(Int,INIT(X,UNDEF)); DEFV(Int,INIT(Y,UNDEF)); DEFV(Int,INIT(Z,UNDEF)); /* Coordonnees entieres 'X', 'Y' et 'Z'. */ /*..............................................................................................................................*/ BoIn(niveau,NOIR,BLANC,PAS_COULEURS) Bblock Test(IFEQ(ITb1(bord,INDX(niveau,NOIR)),ITb1(fond,INDX(niveau,NOIR)))) Bblock PRINT_ERREUR("un niveau ne peut appartenir a la fois au 'bord' et au 'fond'"); CAL1(Prer1("ce niveau est %08X\n",niveau)); Eblock ATes Bblock Eblock ETes Eblock EBoI Test(IL_FAUT(Aremplissage_____calculer_l_histogramme_du__bord)) Bblock BoIn(niveau,NOIR,BLANC,PAS_COULEURS) Bblock CLIR(ACCES_HISTOGRAMME(niveau)); Eblock EBoI Eblock ATes Bblock Eblock ETes EGAL(Aremplissage_voisinage_____niveau_maximal_d_un_point_isole,F_MOINS_L_INFINI); /* Afin de calculer le niveau maximal du fond, si besoin est. */ BSaveModifyVariable(Logical ,Aremplissage_voisinage_____calculer_l_histogramme_du__bord ,Aremplissage_____calculer_l_histogramme_du__bord ); /* Pour des raisons d'imbrication, ce 'BSaveModifyVariable(...)' ne peut pas etre situe */ /* dans le 'Test(IL_FAUT(Aremplissage_____calculer_l_histogramme_du__bord))' precedent... */ CALS(dAinitialisation(AlbumMarqueur,NIVEAU_DE_NON_MARQUAGE)); /* On verifie que le marquage est possible... */ EGAL(X,_cDENORMALISE_OX(ASI1(point_de_depart,x))); EGAL(Y,_cDENORMALISE_OY(ASI1(point_de_depart,y))); EGAL(Z,_cDENORMALISE_OZ(ASI1(point_de_depart,z))); /* Recuperation des coordonnees du point de depart, et mise dans */ /* les coordonnees de l'album. */ CLIR(Aremplissage_voisinage_____nombre_de_points_du__fond); CLIR(ASD1(Aremplissage_voisinage_____centre_de_gravite_du__fond,x)); CLIR(ASD1(Aremplissage_voisinage_____centre_de_gravite_du__fond,y)); CLIR(ASD1(Aremplissage_voisinage_____centre_de_gravite_du__fond,z)); /* Initialisations diverses... */ CALS(Aremplissage_voisinage(albumR ,albumA ,AlbumMarqueur ,X,Y,Z ,_cDENORMALISE_OX(ASI1(coin_inferieur_gauche_avant,x)) ,_cDENORMALISE_OX(ASI1(coin_superieur_droite_arriere,x)) ,_cDENORMALISE_OY(ASI1(coin_inferieur_gauche_avant,y)) ,_cDENORMALISE_OY(ASI1(coin_superieur_droite_arriere,y)) ,_cDENORMALISE_OZ(ASI1(coin_inferieur_gauche_avant,z)) ,_cDENORMALISE_OZ(ASI1(coin_superieur_droite_arriere,z)) ,fond,bord ,dc__6 ,dc__5 ,dc_4_ ,dc_46 ,dc_45 ,dc_2_ ,dc_26 ,dc_25 ,dc3__ ,dc3_6 ,dc3_5 ,dc34_ ,dc346 ,dc345 ,dc32_ ,dc326 ,dc325 ,dc1__ ,dc1_6 ,dc1_5 ,dc14_ ,dc146 ,dc145 ,dc12_ ,dc126 ,dc125 ,CASP_Float(niveau_de_remplissage) ) ); /* Et remplissage recursif, voisinage par voisinage a partir */ /* du point de depart argument... */ Test(IZNE(Aremplissage_voisinage_____nombre_de_points_du__fond)) Bblock EGAL(ASD1(Aremplissage_voisinage_____centre_de_gravite_du__fond,x) ,DIVI(ASD1(Aremplissage_voisinage_____centre_de_gravite_du__fond,x) ,FLOT(Aremplissage_voisinage_____nombre_de_points_du__fond) ) ); EGAL(ASD1(Aremplissage_voisinage_____centre_de_gravite_du__fond,y) ,DIVI(ASD1(Aremplissage_voisinage_____centre_de_gravite_du__fond,y) ,FLOT(Aremplissage_voisinage_____nombre_de_points_du__fond) ) ); EGAL(ASD1(Aremplissage_voisinage_____centre_de_gravite_du__fond,z) ,DIVI(ASD1(Aremplissage_voisinage_____centre_de_gravite_du__fond,z) ,FLOT(Aremplissage_voisinage_____nombre_de_points_du__fond) ) ); /* Calcul "final" du centre de gravite. */ Test(IL_FAUT(Aremplissage_____editer_le_centre_de_gravite)) Bblock CAL3(Prme1("NombreDePoints=%d\n" ,Aremplissage_voisinage_____nombre_de_points_du__fond ) ); CAL3(Prme3("XG=%+.^^^ YG=%+.^^^ ZG=%+.^^^\n" ,ASD1(Aremplissage_voisinage_____centre_de_gravite_du__fond,x) ,ASD1(Aremplissage_voisinage_____centre_de_gravite_du__fond,y) ,ASD1(Aremplissage_voisinage_____centre_de_gravite_du__fond,z) ) ); Eblock ATes Bblock Eblock ETes Eblock ATes Bblock EGAL(ASD1(Aremplissage_voisinage_____centre_de_gravite_du__fond,x),FLOT(X)); EGAL(ASD1(Aremplissage_voisinage_____centre_de_gravite_du__fond,y),FLOT(Y)); EGAL(ASD1(Aremplissage_voisinage_____centre_de_gravite_du__fond,z),FLOT(Z)); /* Dans ce cas, le centre de gravite (qui n'existe en fait pas) est le point de depart */ /* {X,Y}. */ Eblock ETes ESaveModifyVariable(Logical ,Aremplissage_voisinage_____calculer_l_histogramme_du__bord ); /* Pour des raisons d'imbrication, ce 'ESaveModifyVariable(...)' ne peut pas etre situe */ /* dans un 'Test(IL_FAUT(Aremplissage_____calculer_l_histogramme_du__bord))'... */ RETI(albumR); Eblock EFonctionP _______________________________________________________________________________________________________________________________________ _______________________________________________________________________________________________________________________________________ /*===================================================================================================================================*/ /*************************************************************************************************************************************/ /* */ /* E X T R A C T I O N D ' U N C O N T O U R D ' U N E I M A G E : */ /* */ /*************************************************************************************************************************************/ BFonctionP #define gALLER_A_GAUCHE \ Bblock \ SWAP(pas_horizontal,pas_vertical); \ EGAL(pas_horizontal,NEGA(pas_horizontal)); \ Eblock #define ALLER_A_GAUCHE \ Bblock \ Test(IL_NE_FAUT_PAS(inverser_les_conventions_DROITE_GAUCHE)) \ Bblock \ gALLER_A_GAUCHE; \ Eblock \ ATes \ Bblock \ gALLER_A_DROITE; \ Eblock \ ETes \ Eblock /* Rotation de PI/2 du nombre complexe (pas_horizontal,pas_vertical). */ #define gALLER_A_DROITE \ Bblock \ SWAP(pas_horizontal,pas_vertical); \ EGAL(pas_vertical,NEGA(pas_vertical)); \ Eblock #define ALLER_A_DROITE \ Bblock \ Test(IL_NE_FAUT_PAS(inverser_les_conventions_DROITE_GAUCHE)) \ Bblock \ gALLER_A_DROITE; \ Eblock \ ATes \ Bblock \ gALLER_A_GAUCHE; \ Eblock \ ETes \ Eblock /* Rotation de 3xPI/2 du nombre complexe (pas_horizontal,pas_vertical). */ #define DEPLACEMENT_POINT \ Bblock \ INCR(ASD1(point_courant,x),pas_horizontal); \ INCR(ASD1(point_courant,y),pas_vertical); \ Eblock \ /* Deplacement du point courant suivant (pas_horizontal,pas_vertical). */ #define LE_POINT_VOISIN_EST_IL_A_L_INTERIEUR \ Bblock \ Test(EST_VRAI(ITb1(interieur,INDX(load_point_valide(imageA,ASD1(point_courant,x),ASD1(point_courant,y)),NOIR)))) \ Bblock \ EGAL(on_a_trouve_au_moins_un_voisin_a_l_interieur_du_contour,VRAI); \ /* Ainsi, on memorise que l'on a trouve au moins un voisin au point courant */ \ /* qui soit a la fois a sa gauche, et a l'interieur du contour... */ \ Eblock \ ATes \ Bblock \ Eblock \ ETes \ Eblock \ /* Le point courant est-il a l'interieur (procedure introduite le 20070214144219) ? */ #define SEND_CONTOUR(point) \ Bblock \ Test(IL_FAUT(emission_des_points)) \ Bblock \ Test(IFET(IFEQ(ASD1(point,x),COORDONNEE_CORRESPONDANT_A_UN_CONTOUR_VIDE) \ ,IFEQ(ASD1(point,y),COORDONNEE_CORRESPONDANT_A_UN_CONTOUR_VIDE) \ ) \ ) \ /* Test introduit le 20051207143533... */ \ Bblock \ SEND_F(INDIRECT(processus_recepteur),FLOT(ASD1(point,x))); \ SEND_F(INDIRECT(processus_recepteur),FLOT(ASD1(point,y))); \ /* Cas d'un contour vide... */ \ Eblock \ ATes \ Bblock \ SEND_F(INDIRECT(processus_recepteur),_____cNORMALISE_OX(ASD1(point,x))); \ SEND_F(INDIRECT(processus_recepteur),_____cNORMALISE_OY(ASD1(point,y))); \ /* Cas d'un contour non vide... */ \ Eblock \ ETes \ \ SEND_L(INDIRECT(processus_recepteur),fin_de_contour); \ /* Envoi du point... */ \ \ EGAL(un_point_au_moins_a_ete_emis,VRAI); \ /* Et ainsi, on sait qu'au moins un point a ete emis... */ \ Eblock \ ATes \ Bblock \ Eblock \ ETes \ Eblock \ /* Envoi, lorsque cela est demande, des coordonnee de 'point' a un processus recepteur. */ DEFV(Common,DEFV(Logical,SINT(Iextraction_contour_____compatibilite_20070213,FAUX))); /* Indicateur introduit le 20070213135810 et permettant de controler la memorisation des */ /* points du contour. En effet, avant cette date, les points hors-images etaient marques */ /* sur la bordure de l'image ce qui etait la source d'artefacts ainsi que cela s'est vu */ /* dans 'v $xiirk/.DIFF.11.1.$U$INUTILE .xci.contours.11.X'. Il a donc etait de ne plus */ /* marquer, par defaut, les points hors-images... */ DEFV(Common,DEFV(Positive,SINT(Iextraction_contour_____nombre_minimal_de_points_du_contour,UN))); /* Parametre introduit le 20070215125214 pour resoudre (provisoirement ?) le probleme des */ /* impasses ('v $xiii/contours$FON 20070214153034'). La valeur par defaut garantit la */ /* compatibilite anterieure. On pourra voir une application de cela, par exemple, dans le */ /* programme 'v $xiirk/.DIFF.11.2.$U nombre_minimal_de_points'... */ DEFV(Common,DEFV(Logical,SINT(Iextraction_contour_____compatibilite_20070407,FAUX))); /* Indicateur introduit le 20070407170648 et permettant d'eviter de se retrouver pieger */ /* a l'interieur d'un contour a trou ('v $xiii/contours$FON 20070407163803')... */ DEFV(Common,DEFV(FonctionP,POINTERp(Iextraction_contour(imageR ,imageA ,ARGUMENT_POINTERs(point_de_depart) ,exterieur,interieur ,niveau_de_marquage_du_contour ,emission_des_points ,ARGUMENT_FACULTATIF(ARGUMENT_POINTERs(processus_recepteur)) ) ) ) ) DEFV(Argument,DEFV(image,imageR)); /* Image Resultat contenant le contour extrait depuis l'image Argument. */ DEFV(Argument,DEFV(image,imageA)); /* Image Argument. */ DEFV(Argument,DEFV(pointF_2D,POINTERs(point_de_depart))); /* Coordonnees du point de depart d'extraction du contour exprimees */ /* dans des unites telles que l'unite vaut respectivement [Xmin,Xmax] et */ /* [Ymin,Ymax]. */ DEFV(Argument,DEFV(Logical,DTb1(exterieur,COULEURS))); /* Definit ainsi pour chaque niveau s'il appartient ('VRAI') ou pas */ /* ('FAUX') a l'exterieur du contour a extraire. */ DEFV(Argument,DEFV(Logical,DTb1(interieur,COULEURS))); /* Definit ainsi pour chaque niveau s'il appartient ('VRAI') ou pas */ /* ('FAUX') a l'interieur du contour a extraire. */ DEFV(Argument,DEFV(genere_p,niveau_de_marquage_du_contour)); /* Niveau a utiliser pour remplir le contour Argument. */ DEFV(Argument,DEFV(Logical,emission_des_points)); /* Indique si les points extraits du contour doivent etre transmis ('VRAI') */ /* ou pas ('FAUX') au 'processus_recepteur'. */ DEFV(Argument,DEFV(processus,POINTERs(processus_recepteur))); /* Description du processus auquel transmettre les coordonnees dans [0,1] */ /* des points extraits du contour. */ /*-----------------------------------------------------------------------------------------------------------------------------------*/ Bblock DEFV(Int,INIT(nombre_de_points,ZERO)); /* Compteur des points traites sur une spirale ; on peut ainsi detecter */ /* les cas ou il n'y a aucun contour a extraire... */ SPIRALE_DEFINITION /* Donnees de generation d'une spirale de parcours d'une image. */ DEFV(pointI_2D,point_courant); /* Point courant lors de la recherche du vrai point de depart, puis lors */ /* de l'extraction du contour. Il appartient a l'exterieur du contour. */ DEFV(Logical,INIT(un_point_au_moins_a_ete_emis,FAUX)); /* Cet indicateur logique a ete ajoute le 19990603092111 afin de detecter les cas ou alors */ /* qu'il faut emettre, rien ne l'a ete en fait (suite a une erreur...). */ DEFV(Logical,INIT(fin_de_contour,LUNDEF)); /* Cet indicateur logique permet de transmettre (eventuellement) s'il s'agit */ /* du dernier point du contour ('VRAI') ou pas ('FAUX'). */ /*..............................................................................................................................*/ SPIRALE_VALIDATION; /* Validation des pas de parcours (pasX,pasY) des images. */ Test(IFNE(pasX,pasY)) Bblock PRINT_ERREUR("'pasX' et 'pasY' doivent etre egaux afin de rechercher correctement les voisins"); Eblock ATes Bblock Eblock ETes BoIn(niveau,NOIR,BLANC,PAS_COULEURS) Bblock Test(IFEQ(ITb1(interieur,INDX(niveau,NOIR)),ITb1(exterieur,INDX(niveau,NOIR)))) Bblock PRINT_ERREUR("un niveau ne peut appartenir a la fois aux listes 'interieur' et 'exterieur'"); CAL1(Prer1("ce niveau est %08X\n",niveau)); Eblock ATes Bblock Eblock ETes Eblock EBoI Test(IL_FAUT(Iextraction_contour_____compatibilite_20070213)) Bblock Test(IFOU(EST_VRAI(ITb1(interieur,INDX(Niveau____hors_image,NOIR))) ,EST_FAUX(ITb1(exterieur,INDX(Niveau____hors_image,NOIR))) ) ) Bblock PRINT_ERREUR("le 'Niveau____hors_image' doit faire partie de l'exterieur du contour"); Eblock ATes Bblock Eblock ETes Eblock ATes Bblock Eblock ETes INITIALISATION_POINT_2D(point_courant ,_cDENORMALISE_OX(ASI1(point_de_depart,x)) ,_cDENORMALISE_OY(ASI1(point_de_depart,y)) ); /* Recuperation des coordonnees du point courant, et mise dans les */ /* coordonnees de l'image pour la recherche du vrai point de depart. */ Test(TEST_HORS_IMAGE(ASD1(point_courant,x),ASD1(point_courant,y))) Bblock PRINT_ERREUR("le point de depart est hors de l'image"); CAL1(Prer2("(le point de depart est {%d,%d})\n" ,ASD1(point_courant,x) ,ASD1(point_courant,y) ) ); /* Introduit le 20190321122059 lors de la mise au point de 'v $xrc/julia.82$K E_DEPART_'... */ Eblock ATes Bblock Test(EST_VRAI(ITb1(interieur,INDX(load_point_valide(imageA,ASD1(point_courant,x),ASD1(point_courant,y)),NOIR)))) Bblock PRINT_ERREUR("le point de depart est a l'interieur du contour"); CAL1(Prer2("(le point de depart est {%d,%d})\n" ,ASD1(point_courant,x) ,ASD1(point_courant,y) ) ); Eblock ATes Bblock begin_image Bblock Test(EST_VRAI(ITb1(interieur,INDX(load_point(imageA,X,Y),NOIR)))) Bblock INCR(nombre_de_points,I); /* Comptage des points susceptibles d'etre a l'interieur du contour a extraire. */ Eblock ATes Bblock Eblock ETes Eblock end_image Test(IZEQ(nombre_de_points)) Bblock PRINT_ERREUR("il n'y a pas de contour repondant aux specifications"); INITIALISATION_POINT_2D(point_courant ,COORDONNEE_CORRESPONDANT_A_UN_CONTOUR_VIDE ,COORDONNEE_CORRESPONDANT_A_UN_CONTOUR_VIDE ); /* Ces coordonnees particulieres ont ete introduites le 20051207143533 pour pouvoir tester */ /* ce cas au retour ('v $xci/contours.11$K COORDONNEE_CORRESPONDANT_A_UN_CONTOUR_VIDE'). */ Eblock ATes Bblock DEFV(Logical,INIT(premier_tour,LUNDEF)); /* Cet indicateur logique permet d'effectuer au moins une fois la boucle */ /* d'extraction de contour. */ DEFV(pointI_2D,vrai_point_de_depart); /* Coordonnees du vrai point de depart d'extraction du contour exprimees */ /* dans [Xmin,Xmax][Ymin,Ymax]. */ DEFV(pointI_2D,dernier_point_exterieur); /* Coordonnees du dernier point exterieur rencontre exprimees */ /* dans [Xmin,Xmax][Ymin,Ymax] (introduit le 20070407170648...). */ DEFV(Logical,INIT(inverser_les_conventions_DROITE_GAUCHE,FAUX)); /* Introduit le 20070214153034 afin de faire des tests lies a un probleme de contours qui */ /* ne sont pas extraits car quasiment immediatement le point courant repasse par le point */ /* de depart. Cette situation se rencontre quand le point de depart est en quelques sorte */ /* a l'interieur ou a l'entree d'une impasse ; en effet, pour ressortir d'une impasse, il */ /* faut necessairement repasser par l'entree... */ DEFV(Int,INIT(pas_horizontal,CHOI(pasX,pasY))); DEFV(Int,INIT(pas_vertical,ZERO)); /* Pas horizontaux et verticaux de recherche ; on va partir horizontalement vers la droite. */ DEFV(Int,INIT(EnTete_de_sauvegardM ## pas_horizontal,UNDEF)); DEFV(Int,INIT(EnTete_de_sauvegardM ## pas_vertical,UNDEF)); /* Sauvegarde des pas horizontaux et verticaux lors de l'examen des trois */ /* voisins de gauche. */ DEFV(Int,INIT(EnTete_de_sauvegardM ## pas_horizontal_initial,UNDEF)); DEFV(Int,INIT(EnTete_de_sauvegardM ## pas_vertical_initial,UNDEF)); /* Sauvegarde des pas horizontaux et verticaux a l'instant initial. On notera qu'a la fin */ /* du parcours d'un contour,{pas_horizontal,pas_vertical} ne se retrouvent pas a l'etat */ /* initiale {SavM_____pas_horizontal_initial,SavM_____pas_vertical_initial} ainsi qu'on */ /* pourrait le croire naivement... */ DEFV(Positive,INIT(nombre_de_points_du_contour,ZERO)); /* Introduit le 20070215125214... */ Tant(IFOU(TEST_HORS_IMAGE(ASD1(point_courant,x),ASD1(point_courant,y)) ,EST_VRAI(ITb1(exterieur ,INDX(load_point_valide(imageA,ASD1(point_courant,x),ASD1(point_courant,y)),NOIR) ) ) ) ) Bblock /* Ainsi, on cherche "en spirale" le premier point interieur au */ /* contour et qui existe (DANS_L_IMAGE). */ TRANSFERT_POINT_2D(dernier_point_exterieur,point_courant); /* A priori, on memorise le point exterieur courant, qui a la fin sera le dernier... */ SPIRALE_INITIALISATION; /* Initialisation dynamique de 'spirale_nombre_de_points_a_traiter'. */ SPIRALE_DEPLACEMENT(ASD1(point_courant,x),ASD1(point_courant,y)); /* Deplacement du point courant de la spirale... */ /* ATTENTION : on n'utilise pas 'SPIRALE_DEPLACEMENT_ET_PARCOURS(...)' afin de garantir la */ /* terminaison du processus 'Tant(...)'. */ SPIRALE_PARCOURS; /* Parcours de la spirale avec rotation eventuelle de PI/2 du bras courant... */ Eblock ETan SPIRALE_REINITIALISATION_BRAS; /* Reinitialisation de la spirale en son centre, sans reinitialiser la direction */ /* et le sens du bras courant... */ /* On notera, que (spirale_delta_horizontal,spirale_delta_vertical) n'est pas */ /* reinitialise afin de continuer dans la meme direction... */ Test(IL_FAUT(Iextraction_contour_____compatibilite_20070407)) Bblock Tant(IFOU(TEST_HORS_IMAGE(ASD1(point_courant,x),ASD1(point_courant,y)) ,EST_VRAI(ITb1(interieur ,INDX(load_point_valide(imageA,ASD1(point_courant,x),ASD1(point_courant,y)),NOIR) ) ) ) ) Bblock /* Ainsi, on cherche "en spirale" le premier point exterieur au */ /* contour et qui existe (DANS_L_IMAGE) a partir du premier point */ /* interieur trouve dans la boucle 'Tant' precedente. */ SPIRALE_INITIALISATION; /* Initialisation dynamique de 'spirale_nombre_de_points_a_traiter'. */ SPIRALE_DEPLACEMENT(ASD1(point_courant,x),ASD1(point_courant,y)); /* Deplacement du point courant de la spirale... */ /* ATTENTION : on n'utilise pas 'SPIRALE_DEPLACEMENT_ET_PARCOURS(...)' afin de garantir la */ /* terminaison du processus 'Tant(...)'. */ SPIRALE_PARCOURS; /* Parcours de la spirale avec rotation eventuelle de PI/2 du bras courant... */ Eblock ETan Eblock ATes Bblock TRANSFERT_POINT_2D(point_courant,dernier_point_exterieur); /* Repositionnement sur le dernier point exterieur (introduit le 20070407170648)... */ Eblock ETes TRANSFERT_POINT_2D(vrai_point_de_depart,point_courant); /* Recuperation des coordonnees du point de depart en tant que dernier */ /* point de l'exterieur rencontre avant un point de l'interieur du */ /* contour a extraire (ces deux points devant etre dans l'image...). */ EGAL(premier_tour,VRAI); /* Afin de faire au moins la sequence d'extraction une fois... */ EGAL(fin_de_contour,FAUX); /* On n'en n'est pas encore la... */ EGAL(EnTete_de_sauvegardM ## pas_horizontal_initial,pas_horizontal); EGAL(EnTete_de_sauvegardM ## pas_vertical_initial,pas_vertical); /* Sauvegarde de l'etat initial de l'orientation des deplacements (ceci fut introduit */ /* le 20070214173007...). */ Tant(I3OU(EST_VRAI(premier_tour) ,IFOU(IFNE(ASD1(vrai_point_de_depart,x),ASD1(point_courant,x)) ,IFNE(ASD1(vrai_point_de_depart,y),ASD1(point_courant,y)) ) ,I3ET(IFET(IFEQ(ASD1(vrai_point_de_depart,x),ASD1(point_courant,x)) ,IFEQ(ASD1(vrai_point_de_depart,y),ASD1(point_courant,y)) ) ,IFOU(IFNE(pas_horizontal,EnTete_de_sauvegardM ## pas_horizontal_initial) ,IFNE(pas_vertical,EnTete_de_sauvegardM ## pas_vertical_initial) ) ,IFLT(nombre_de_points_du_contour,Iextraction_contour_____nombre_minimal_de_points_du_contour) ) /* Cette condition a ete introduite le 20070215125214 pour resoudre (provisoirement ?) */ /* le probleme des impasses ('v $xiii/contours$FON 20070214153034'). Ainsi, si l'on est */ /* de retour au point de depart sans etre dans la meme direction qu'initialement (en effet */ /* dans le cas contraire, on referait exactement la meme extraction) et si le contour est */ /* trop petit (critere arbitraire...), on poursuit l'extraction. Cette situation d'impasse */ /* se rencontre, par exemple, ainsi : */ /* */ /* */ /* | | | | */ /* -+----+----+----+- */ /* |////|////|////| */ /* |////|////|////| */ /* |////|////|////| */ /* -+----+----+----+- */ /* |////| |////| */ /* |////| /\ |////| */ /* |////| || |////| */ /* -+----+-||-+----+- */ /* | | |////| */ /* | | De |////| */ /* | | |////| */ /* -+----+----+----+- */ /* | | | | */ /* */ /* */ /* La case marquee 'De' correspond au point de depart d'extraction du contour. L'exploration */ /* monte et penetre dans l'impasse superieure. La seule facon d'en sortir est de parcourir */ /* le chemin aller a l'envers. Alors on repasse necessairement par la case 'De'... */ ) ) Bblock DEFV(pointI_2D,save1_point_courant); /* Sauvegarde du point courant lors de l'extraction du contour. Il appartient a l'exterieur */ /* du contour. */ DEFV(Logical,INIT(on_a_trouve_au_moins_un_voisin_a_l_interieur_du_contour,LUNDEF)); /* Indicateur montrant si au moins un voisin a gauche a ete rencontre. */ Test(IFOU(TEST_DANS_L_IMAGE(ASD1(point_courant,x),ASD1(point_courant,y)) ,IFET(TEST_HORS_IMAGE(ASD1(point_courant,x),ASD1(point_courant,y)) ,IL_FAUT(Iextraction_contour_____compatibilite_20070213) ) ) ) Bblock SEND_CONTOUR(point_courant); /* Lorsque cela est demande, on transmet les coordonnees {x,y} du point */ /* courant (et du point de depart la premiere fois) du contour. */ Eblock ATes Bblock Eblock ETes EGAL(on_a_trouve_au_moins_un_voisin_a_l_interieur_du_contour,FAUX); /* A priori, on n'a pas encore trouve de voisin a gauche du point courant... */ TRANSFERT_POINT_2D(save1_point_courant,point_courant); /* Sauvegarde du point courant au debut de la recherche des voisins. */ ALLER_A_GAUCHE; DEPLACEMENT_POINT; /* Et on tourne a gauche initialement. */ Tant(EST_FAUX(on_a_trouve_au_moins_un_voisin_a_l_interieur_du_contour)) Bblock DEFV(pointI_2D,save2_point_courant); /* Sauvegarde du point courant lors de l'examen des trois voisins de gauche. Il appartient */ /* a l'exterieur du contour. */ DEFV(Int,INIT(compteur_des_voisins,ZERO)); /* Compteur des voisins destines a verifier qu'il y en a trois au plus... */ DEFV(Logical,INIT(chercher_un_point_courant_a_l_exterieur_du_contour,VRAI)); /* Indicateur controlant la recherche d'un point courant a l'exterieur du contour... */ Tant(IL_FAUT(chercher_un_point_courant_a_l_exterieur_du_contour)) Bblock Test(TEST_DANS_L_IMAGE(ASD1(point_courant,x),ASD1(point_courant,y))) Bblock Test(EST_VRAI(ITb1(interieur ,INDX(load_point(imageA,ASD1(point_courant,x),ASD1(point_courant,y)),NOIR) ) ) ) Bblock /* Cas d'un point dans l'image et a l'interieur du contour : on continue la recherche... */ INCR(compteur_des_voisins,I); /* Comptage des voisins... */ Eblock ATes Bblock EGAL(chercher_un_point_courant_a_l_exterieur_du_contour,FAUX); /* Cas d'un point dans l'image et a l'exterieur du contour : on a trouve le point... */ Eblock ETes Eblock ATes Bblock /* Cas d'un point hors de l'image : */ Test(EST_VRAI(ITb1(interieur,INDX(Niveau____hors_image,NOIR)))) Bblock /* Cas d'un point hors de l'image, considere comme etant a l'interieur du contour : on */ /* continue la recherche... */ INCR(compteur_des_voisins,I); /* Comptage des voisins... */ Eblock ATes Bblock EGAL(chercher_un_point_courant_a_l_exterieur_du_contour,FAUX); /* Cas d'un point hors de l'image, considere comme etant a l'exterieur du contour : on a */ /* trouve le point... */ Eblock ETes Eblock ETes Test(IL_FAUT(chercher_un_point_courant_a_l_exterieur_du_contour)) Bblock Test(IFGT(compteur_des_voisins,TROIS)) /* Ce test a ete introduit le 20070406222210 dans le but de resoudre le cas suivant : */ /* */ /* */ /* | | | | */ /* -+----+----+----+- */ /* | |////| | */ /* | |////| | */ /* | |////| | */ /* -+----+----+----+- */ /* |////| |////| */ /* |////| PC |////| */ /* |////| |////| */ /* -+----+----+----+- */ /* | |////| | */ /* | |////| | */ /* | |////| | */ /* -+----+----+----+- */ /* | | | | */ /* */ /* */ /* (ou 'PC' designe 'save1_point_courant' qui est le point courant de l'exterieur ; les */ /* cases vides appartiennent a l'EXTERIEUR et les cases hachurees a l'INTERIEUR) qui a */ /* cette date conduit a un bouclage infini du 'Tant(...)' dans lequel nous sommes ici... */ /* */ /* En fait, le 20070407163803, je comprends que le probleme vient du fait que cette fonction */ /* 'Iextraction_contour(...)' fait l'hypothese implicite que le contour est plein. Or dans */ /* l'exemple ci-dessus, il contient des trous (en fait un seul, celui qui est marque 'PC'). */ /* L'extracteur de contour se retrouve piege a l'interieur, alors qu'il se croit situe a */ /* l'exterieur. Le scenario est le suivant : */ /* */ /* */ /* | | | | */ /* -+----+----+----+- */ /* | |////| | */ /* | |////| | */ /* | |////| | */ /* -+----+----+----+- */ /* |////| |////| */ /* |////| De |////| arret de la seconde boucle 'Tant(...)' */ /* |////| |////| */ /* -+----+----+----+- */ /* | |//\/| | */ /* | |/IN/| | arret de la premiere boucle 'Tant(...)' */ /* | |////| | */ /* -+----+----+----+- */ /* | | /\ | | */ /* | | EX | | */ /* | | | | */ /* -+----+----+----+- */ /* | | /\ | | */ /* | | EX | | */ /* | | | | */ /* -+----+----+----+- */ /* | | | | */ /* */ /* */ /* La boucle 'Tant(...)' qui recherche "le premier point interieur au contour" ci-dessus */ /* a parcouru les points exterieurs marques 'EX' et s'est arretee sur le premier point */ /* marque 'IN'. Ensuite, la boucle 'Tant(...)' qui recherche "le premier point exterieur au */ /* contour" a parcouru les points interieurs marques 'IN' (en fait un seul) et s'est arretee */ /* sur le premier point exterieur marque 'De'. Ce dernier est donc le point de depart qui */ /* est malheureusement piege a l'interieur... */ /* */ /* Le 20070407170648, grace a 'Iextraction_contour_____compatibilite_20070407' ce probleme */ /* fut resolu. La solution a consiste a supprimer, par defaut, la seconde boucle 'Tant(...)' */ /* et en revenant donc sur le dernier point marque 'EX' de la premiere boucle 'Tant(...)', */ /* qui devient donc le point de depart 'De' : */ /* */ /* */ /* | | | | */ /* -+----+----+----+- */ /* | |////| | */ /* | |////| | */ /* | |////| | */ /* -+----+----+----+- */ /* |////| |////| */ /* |////| |////| */ /* |////| |////| */ /* -+----+----+----+- */ /* | |//\/| | */ /* | |/IN/| | arret de la premiere boucle 'Tant(...)' */ /* | |////| | */ /* -+----+----+----+- */ /* | | /\ | | */ /* | | De | | */ /* | | | | */ /* -+----+----+----+- */ /* | | /\ | | */ /* | | EX | | */ /* | | | | */ /* -+----+----+----+- */ /* | | | | */ /* */ /* */ /* et le trou a l'interieur du contour est donc evite puisque l'on n'y penetre pas ... */ Bblock PRINT_ERREUR("trop de voisins a l'interieur ont ete trouve pour le point exterieur"); CAL1(Prer2("(le point exterieur est {%d,%d})\n" ,ASD1(save1_point_courant,x) ,ASD1(save1_point_courant,y) ) ); Eblock ATes Bblock Eblock ETes TRANSFERT_POINT_2D(point_courant,save1_point_courant); /* On retourne sur le point courant de debut de la recherche courante, */ ALLER_A_DROITE; DEPLACEMENT_POINT; /* Et on tourne a droite. */ Eblock ATes Bblock Eblock ETes Eblock ETan TRANSFERT_POINT_2D(save2_point_courant,point_courant); EGAL(EnTete_de_sauvegardM ## pas_horizontal,pas_horizontal); EGAL(EnTete_de_sauvegardM ## pas_vertical,pas_vertical); /* Sauvegardes du point courant et de la direction courante de */ /* deplacement avant de regarder les trois voisins de gauche (c'est-a-dire */ /* celui qui est en arriere-gauche, celui qui est a gauche et enfin celui */ /* qui est en avant-gauche. */ ALLER_A_GAUCHE; DEPLACEMENT_POINT; /* Test du voisin de gauche : */ LE_POINT_VOISIN_EST_IL_A_L_INTERIEUR; /* Est-il interieur ? */ ALLER_A_GAUCHE; DEPLACEMENT_POINT; /* Test du voisin d'arriere-gauche : */ LE_POINT_VOISIN_EST_IL_A_L_INTERIEUR; /* Est-il interieur ? */ ALLER_A_GAUCHE; ALLER_A_GAUCHE; DEPLACEMENT_POINT; DEPLACEMENT_POINT; /* Test du voisin d'avant-gauche : */ LE_POINT_VOISIN_EST_IL_A_L_INTERIEUR; /* Est-il interieur ? */ TRANSFERT_POINT_2D(point_courant,save2_point_courant); EGAL(pas_horizontal,EnTete_de_sauvegardM ## pas_horizontal); EGAL(pas_vertical,EnTete_de_sauvegardM ## pas_vertical); /* Et les conditions initiales sont restaurees : le point courant et la direction */ /* courante de deplacement. */ /* */ /* Le 20070214150322 je note que cette restauration semble inutile car, en effet, ayant */ /* effectue quatre fois {ALLER_A_GAUCHE;DEPLACEMENT_POINT}, on a finalement tourne de */ /* quatre fois pi/2 et on est donc retombe sur nos pas. Malgre tout, dans le doute, je */ /* m'abstiens de la supprimer... */ Test(EST_FAUX(on_a_trouve_au_moins_un_voisin_a_l_interieur_du_contour)) Bblock TRANSFERT_POINT_2D(point_courant,save1_point_courant); /* Lorsqu'aucun voisin a gauche n'a ete trouve, on retourne sur */ /* le point courant de debut de la recherche courante. */ ALLER_A_DROITE; DEPLACEMENT_POINT; /* Et on tourne a droite. */ Eblock ATes Bblock Eblock ETes Eblock ETan INCR(nombre_de_points_du_contour,I); /* Comptage des points du contour introduit le 20070215125214... */ Test(IL_NE_FAUT_PAS(Iextraction_contour_____compatibilite_20070213)) Bblock store_point_valide(niveau_de_marquage_du_contour ,imageR ,ASD1(point_courant,x) ,ASD1(point_courant,y) ,FVARIABLE ); /* Et on ne marque que les points du contour qui sont dans l'image... */ Eblock ATes Bblock store_point(niveau_de_marquage_du_contour ,imageR ,TRON(ASD1(point_courant,x),Xmin,Xmax) ,TRON(ASD1(point_courant,y),Ymin,Ymax) ,FVARIABLE ); /* Et on marque le contour de facon que les points hors-ecran apparaissent */ /* marques sur la bordure de l'image... */ Eblock ETes EGAL(premier_tour,FAUX); /* Ainsi, on sait que l'on a effectue la boucle au moins une fois... */ Eblock ETan EGAL(fin_de_contour,VRAI); /* Ca y est, on est au bout... */ SEND_CONTOUR(point_courant); /* Lorsque cela est demande, on transmet les coordonnees {x,y} du point */ /* d'arrivee du contour qui est aussi le vrai point de depart... */ Eblock ETes Eblock ETes Eblock ETes Test(IFOU(EST_FAUX(fin_de_contour) ,EST_FAUX(un_point_au_moins_a_ete_emis) ) ) Bblock EGAL(fin_de_contour,VRAI); SEND_CONTOUR(point_courant); /* Le 19990603092111 ce dispositif a ete ajoute afin d'eviter le blocage de l'eventuel */ /* processus 'processus_recepteur' si 'IL_FAUT(emission_des_points)' dans le cas ou une */ /* erreur se serait produite (par exemple, pour inexistence du contour). */ Eblock ATes Bblock Eblock ETes RETI(imageR); Eblock #undef SEND_CONTOUR #undef LE_POINT_VOISIN_EST_IL_A_L_INTERIEUR #undef DEPLACEMENT_POINT #undef ALLER_A_DROITE #undef gALLER_A_DROITE #undef ALLER_A_GAUCHE #undef gALLER_A_GAUCHE EFonctionP _______________________________________________________________________________________________________________________________________ _______________________________________________________________________________________________________________________________________ /*===================================================================================================================================*/ /*************************************************************************************************************************************/ /* */ /* E X T R A C T I O N D E T O U S L E S C O N T O U R S D ' U N E I M A G E : */ /* */ /*************************************************************************************************************************************/ BFonctionP #define SEUIL_DES_CONTOURS \ GRIS \ /* Pour la phase finale de binarisation... */ DEFV(Common,DEFV(FonctionP,POINTERp(Iextraction_contours(imageR,imageA,seuil_du_contour)))) DEFV(Argument,DEFV(image,imageR)); /* Image Resultat contenant le contour extrait depuis l'image Argument. */ DEFV(Argument,DEFV(image,imageA)); /* Image Argument. */ DEFV(Argument,DEFV(genere_p,seuil_du_contour)); /* Niveau definissant ce qui est a l'exterieur et ce qui est a l'interieur */ /* du contour : */ /* les points de niveau inferieur ou egal a 'seuil' sont exterieurs, et */ /* les points de niveau strictement superieur a 'seuil' sont interieurs. */ /*-----------------------------------------------------------------------------------------------------------------------------------*/ Bblock BDEFV(image,interieur); /* Image de type masque definissant l'interieur des contours. */ /*..............................................................................................................................*/ CALS(Ibinarisation(interieur,imageA,seuil_du_contour)); /* Recherche de l'interieur de tous les contours. */ CALS(Ijeu_de_la_vie_generalise(imageR,interieur)); /* Et extraction "douce" des contours... */ CALS(Ibinarisation(imageR,imageR,SEUIL_DES_CONTOURS)); /* Et enfin, binarisation du resultat... */ EDEFV(image,interieur); /* Image de type masque definissant l'interieur des contours. */ RETI(imageR); Eblock #undef SEUIL_DES_CONTOURS EFonctionP _______________________________________________________________________________________________________________________________________ _______________________________________________________________________________________________________________________________________ /*===================================================================================================================================*/ /*************************************************************************************************************************************/ /* */ /* E X T R A C T I O N D ' U N E L I G N E D E P L U S G R A N D E P E N T E : */ /* */ /*************************************************************************************************************************************/ BFonctionP #define NOMBRE_DE_POINTS_MAXIMAL \ EXP2(PAR1(DOUB(efficacite_de_l_effet_tunnel))) \ /* Nombre de points que l'on traitera au maximum sur une spirale ; ce */ \ /* parametre donne l'efficacite de l'"effet tunnel" qui permet de sortir */ \ /* certaines impasses... */ #define TEST_VOISINAGE(condition,direction,x,y) \ /* Cette procedure regarde si le point courant {x,y} est successeur possible */ \ /* au point courant de la ligne de plus grand pente ; celui-ci doit d'abord */ \ /* etre dans l'image, puis avoir un niveau inferieur a celui du point courant */ \ /* de la ligne de plus grande pente, et enfin etre possede le plus petit niveau */ \ /* du voisinage de ce fameux point courant. */ \ Bblock \ DEFV(Int,INIT(niveau_courant,NIVEAU_UNDEF)); \ /* Destine a contenir le niveau du point courant {x,y}. */ \ Test(IL_FAUT(direction)) \ Bblock \ Test(TEST_DANS_L_IMAGE(x,y)) \ Bblock \ Test(TEST_POINT_NON_MARQUE(x,y)) \ Bblock \ /* On ne traite que les points sur lesquels on n'est pas encore passe ; on */ \ /* notera qu'il serait imprudent de tester 'NIVEAU_DE_MARQUAGE' avec */ \ /* un 'IFEQ' a cause des problemes lies aux 'liste de substitution'. */ \ EGAL(niveau_courant,load_point(imageA,x,y)); \ /* Initialisation du niveau du point courant {x,y}. */ \ Test(IFET(condition(niveau_courant,niveau_courant_sur_la_ligne) \ ,condition(niveau_courant,niveau_courant_dans_le_voisinage) \ ) \ ) \ Bblock \ EGAL(X_voisin,x); \ EGAL(Y_voisin,y); \ EGAL(niveau_courant_dans_le_voisinage,niveau_courant); \ /* Lorsqu'on a trouve un point {x,y} dont le niveau est le plus petit de tous */ \ /* ceux du voisinage (et plus petit aussi que le point courant de la ligne, */ \ /* on le prend comme eventuel futur point "directeur" du point courant sur */ \ /* la ligne. */ \ EGAL(on_a_trouve_au_moins_un_voisin,VRAI); \ /* Et on memorise que l'on a trouve au moins un futur successeur... */ \ Eblock \ ATes \ Bblock \ Eblock \ ETes \ Eblock \ ATes \ Bblock \ Eblock \ ETes \ Eblock \ ATes \ Bblock \ Eblock \ ETes \ Eblock \ ATes \ Bblock \ Eblock \ ETes \ Eblock DEFV(Common,DEFV(FonctionP,POINTERp(Iextraction_ligne_de_plus_grande_pente(imageR ,ARGUMENT_POINTERs(point_d_arrivee) ,imageA ,ARGUMENT_POINTERs(point_de_depart) ,est_______,nord______,ouest_____,sud_______ ,nord_est__,nord_ouest,sud_ouest_,sud_est___ ,niveau_de_marquage_de_la_ligne ,nombre_de_points_maximal ,efficacite_de_l_effet_tunnel ) ) ) ) DEFV(Argument,DEFV(image,imageR)); /* Image Resultat contenant le contour extrait depuis l'image Argument. */ DEFV(Argument,DEFV(pointF_2D,POINTERs(point_d_arrivee))); /* Coordonnees du point d'arrivee d'extraction de la ligne de plus grande */ /* pente exprimees dans des unites telles que l'unite vaut respectivement */ /* [Xmin,Xmax] et [Ymin,Ymax] ; il s'agit en general d'une impasse, et donc */ /* en exploitant ce point et en utilisant le remplissage de contours progressif */ /* autour de lui, on peut "combler" le trou dans lequel on est tombe... */ DEFV(Argument,DEFV(image,imageA)); /* Image Argument. */ DEFV(Argument,DEFV(pointF_2D,POINTERs(point_de_depart))); /* Coordonnees du point de depart d'extraction de la ligne de plus grande */ /* pente exprimees dans des unites telles que l'unite vaut respectivement */ /* [Xmin,Xmax] et [Ymin,Ymax]. */ DEFV(Argument,DEFV(Logical,est_______)); /* Variable logique indiquant si l'on doit emprunter la direction 'est' */ /* ('VRAI') ou pas ('FAUX') lors de l'exploration du vosinage du point courant. */ DEFV(Argument,DEFV(Logical,nord______)); /* Variable logique indiquant si l'on doit emprunter la direction 'nord' */ /* ('VRAI') ou pas ('FAUX') lors de l'exploration du vosinage du point courant. */ DEFV(Argument,DEFV(Logical,ouest_____)); /* Variable logique indiquant si l'on doit emprunter la direction 'ouest' */ /* ('VRAI') ou pas ('FAUX') lors de l'exploration du vosinage du point courant. */ DEFV(Argument,DEFV(Logical,sud_______)); /* Variable logique indiquant si l'on doit emprunter la direction 'sud' */ /* ('VRAI') ou pas ('FAUX') lors de l'exploration du vosinage du point courant. */ DEFV(Argument,DEFV(Logical,nord_est__)); /* Variable logique indiquant si l'on doit emprunter la direction 'nord_est' */ /* ('VRAI') ou pas ('FAUX') lors de l'exploration du vosinage du point courant. */ DEFV(Argument,DEFV(Logical,nord_ouest)); /* Variable logique indiquant si l'on doit emprunter la direction 'nord_ouest' */ /* ('VRAI') ou pas ('FAUX') lors de l'exploration du vosinage du point courant. */ DEFV(Argument,DEFV(Logical,sud_ouest_)); /* Variable logique indiquant si l'on doit emprunter la direction 'sud_ouest' */ /* ('VRAI') ou pas ('FAUX') lors de l'exploration du vosinage du point courant. */ DEFV(Argument,DEFV(Logical,sud_est___)); /* Variable logique indiquant si l'on doit emprunter la direction 'sud_est' */ /* ('VRAI') ou pas ('FAUX') lors de l'exploration du vosinage du point courant. */ DEFV(Argument,DEFV(genere_p,niveau_de_marquage_de_la_ligne)); /* Niveau a utiliser pour remplir le contour Argument. */ DEFV(Argument,DEFV(Int,nombre_de_points_maximal)); /* Nombre de points maximal demande sur la ligne de plus grande pente. */ DEFV(Argument,DEFV(Int,efficacite_de_l_effet_tunnel)); /* Ce parametre donne la demi-taille maximale du cote de la spirale ; plus */ /* il est grand et plus on pourra s'echapper des impasses... */ /*-----------------------------------------------------------------------------------------------------------------------------------*/ Bblock DEFV(Int,INIT(nombre_de_points_sur_la_ligne,ZERO)); /* Compteur des points generes sur la ligne de plus grande pente. */ DEFV(pointI_2D,point_courant_sur_la_ligne); /* Point courant de la ligne de plus grande pente dans [Xmin,Xmax][Ymin,Ymax]. */ DEFV(Logical,INIT(on_a_trouve_au_moins_un_successeur,FAUX)); /* Indicateur montrant si au moins un successeur a ete rencontre sur la ligne */ /* de plus grande pente. */ DEFV(genere_p,INIT(niveau_courant_sur_la_ligne,NIVEAU_UNDEF)); /* Niveau du point courant de la ligne de plus grande pente dans 'imageA' ; il */ /* sera initialise sur le point de depart, et la valeur qu'il contient ne peut */ /* theoriquement decroitre puisque l'on recherche la ligne de plus grande pente ; */ /* en fait, cela n'est pas tout a fait vrai, car pour eviter de tomber dans */ /* des "impasses", on met en place une sorte d'"effet tunnel"... */ SPIRALE_DEFINITION /* Donnees de generation d'une spirale de parcours d'une image. */ DEFV(pointI_2D,point_courant); /* Point courant sur la spirale ; le premier point traite n'est pas le */ /* centre afin d'etre sur de se deplacer. */ DEFV(Logical,INIT(on_a_trouve_au_moins_un_voisin,LUNDEF)); /* Indicateur montrant si au moins un voisin interessant a ete rencontre. */ DEFV(Int,INIT(X_voisin,UNDEF)); /* Abscisse d'un voisin interessant en tant que "direction" du futur successeur, */ DEFV(Int,INIT(Y_voisin,UNDEF)); /* Ordonnee d'un voisin interessant en tant que "direction" du futur successeur. */ DEFV(genere_p,INIT(niveau_courant_dans_le_voisinage,NIVEAU_UNDEF)); /* Niveau courant d'un point du voisinage du point_courant_sur_la_ligne. */ /*..............................................................................................................................*/ MARQUAGE_VALIDATION_ET_INITIALISATION; /* On verifie que le marquage est possible... */ SPIRALE_VALIDATION; /* Validation des pas de parcours (pasX,pasY) des images. */ INITIALISATION_POINT_2D(point_courant_sur_la_ligne ,_cDENORMALISE_OX(ASI1(point_de_depart,x)) ,_cDENORMALISE_OY(ASI1(point_de_depart,y)) ); /* Recuperation des coordonnees du point de depart demande, et mise dans les */ /* coordonnees de l'image, afin de d'initialiser le point courant sur la */ /* ligne de plus grande pente. */ Test(TEST_HORS_IMAGE(ASD1(point_courant_sur_la_ligne,x),ASD1(point_courant_sur_la_ligne,y))) Bblock PRINT_ERREUR("le point de depart est hors de l'image"); Eblock ATes Bblock EGAL(on_a_trouve_au_moins_un_successeur,VRAI); /* En fait, le premier successeur est le point de depart... */ Tant(EST_VRAI(on_a_trouve_au_moins_un_successeur)) Bblock EGAL(niveau_courant_sur_la_ligne ,load_point(imageA,ASD1(point_courant_sur_la_ligne,x),ASD1(point_courant_sur_la_ligne,y)) ); /* Initialisation du niveau du point courant sur la ligne de plus grande pente */ /* sur le point de depart la premiere fois, et sur le point courant de la ligne */ /* de plus grande pente les fois suivantes... */ MARQUAGE_POINT(ASD1(point_courant_sur_la_ligne,x),ASD1(point_courant_sur_la_ligne,y)); /* On memorise le passage par ce point... */ store_point(niveau_de_marquage_de_la_ligne ,imageR ,ASD1(point_courant_sur_la_ligne,x),ASD1(point_courant_sur_la_ligne,y) ,FVARIABLE ); /* Marquage du point courant... */ TRANSFERT_POINT_2D(point_courant,point_courant_sur_la_ligne); /* Definition du centre de la spirale de recherche de la direction du */ /* successeur du point courant ; cette spirale est destinee a voir dans */ /* quelle direction par rapport au point courant se trouve probablement */ /* la suite de la ligne de plus grande pente. */ EGAL(niveau_courant_dans_le_voisinage,BLANC); /* Les tests etants "stricts" ('IFLT'), on initialise sans probleme le plus */ /* petit niveau rencontre sur le plus grand possible ('BLANC'). */ EGAL(on_a_trouve_au_moins_un_voisin,FAUX); /* On indique ainsi que l'on a encore rencontre aucun voisin interessant... */ TEST_VOISINAGE(IFLT,est_______,SUCX(ASD1(point_courant,x)),NEUT(ASD1(point_courant,y))); TEST_VOISINAGE(IFLT,nord______,NEUT(ASD1(point_courant,x)),SUCY(ASD1(point_courant,y))); TEST_VOISINAGE(IFLT,ouest_____,PREX(ASD1(point_courant,x)),NEUT(ASD1(point_courant,y))); TEST_VOISINAGE(IFLT,sud_______,NEUT(ASD1(point_courant,x)),PREY(ASD1(point_courant,y))); TEST_VOISINAGE(IFLT,nord_est__,SUCX(ASD1(point_courant,x)),SUCY(ASD1(point_courant,y))); TEST_VOISINAGE(IFLT,nord_ouest,PREX(ASD1(point_courant,x)),SUCY(ASD1(point_courant,y))); TEST_VOISINAGE(IFLT,sud_ouest_,PREX(ASD1(point_courant,x)),PREY(ASD1(point_courant,y))); TEST_VOISINAGE(IFLT,sud_est___,SUCX(ASD1(point_courant,x)),PREY(ASD1(point_courant,y))); /* Ainsi, on examine exhaustivement le voisinage du point courant, afin de trouver */ /* s'il existe un "vrai" plus petit niveau voisin de celui-ci... */ Test(EST_FAUX(on_a_trouve_au_moins_un_voisin)) Bblock /* Lorsque celui-ci n'existe pas, on regarde alors a niveau constant ; pour */ /* des raisons liees aux tests de 'TEST_VOISINAGE' et a l'initialisation */ /* a 'BLANC' de 'niveau_courant_dans_le_voisinage', on utilise 'IFLE' et */ /* non pas 'IFEQ'... */ TEST_VOISINAGE(IFLE,est_______,SUCX(ASD1(point_courant,x)),NEUT(ASD1(point_courant,y))); TEST_VOISINAGE(IFLE,nord______,NEUT(ASD1(point_courant,x)),SUCY(ASD1(point_courant,y))); TEST_VOISINAGE(IFLE,ouest_____,PREX(ASD1(point_courant,x)),NEUT(ASD1(point_courant,y))); TEST_VOISINAGE(IFLE,sud_______,NEUT(ASD1(point_courant,x)),PREY(ASD1(point_courant,y))); TEST_VOISINAGE(IFLE,nord_est__,SUCX(ASD1(point_courant,x)),SUCY(ASD1(point_courant,y))); TEST_VOISINAGE(IFLE,nord_ouest,PREX(ASD1(point_courant,x)),SUCY(ASD1(point_courant,y))); TEST_VOISINAGE(IFLE,sud_ouest_,PREX(ASD1(point_courant,x)),PREY(ASD1(point_courant,y))); TEST_VOISINAGE(IFLE,sud_est___,SUCX(ASD1(point_courant,x)),PREY(ASD1(point_courant,y))); Test(EST_FAUX(on_a_trouve_au_moins_un_voisin)) Bblock /* Lorsque celui-ci n'existe pas, on regarde anarchiquement le voisinage, */ /* avec mise en place d'uune "effet tunnel" qui permet de franchir les */ /* barrieres de niveaux trop eleves... */ SPIRALE_REINITIALISATION_BRAS_ET_DELTAS; /* Reinitialisation de la spirale en son centre, sans reinitialiser la direction et le sens */ /* du bras courant. Puis, */ /* reinitialisation de (spirale_delta_horizontal,spirale_delta_vertical) qui donne la */ /* direction et le sens du bras courant de la spirale. */ SPIRALE_REINITIALISATION_COMPTAGE; /* Afin de compter les nombres de points de la spirale que l'on traite... */ Tant(IFET(EST_FAUX(on_a_trouve_au_moins_un_voisin) ,IFLT(nombre_de_points_sur_la_spirale,NOMBRE_DE_POINTS_MAXIMAL) ) ) Bblock /* Ainsi, on cherche "en spirale" le premier point qui donne la direction */ /* dans laquelle la densite des points semble diminuer... */ SPIRALE_INITIALISATION; /* Initialisation dynamique de 'spirale_nombre_de_points_a_traiter'. */ SPIRALE_DEPLACEMENT(ASD1(point_courant,x),ASD1(point_courant,y)); /* Et on deplace le point courant avant les tests sur le bras courant, et ce */ /* afin d'etre sur de se deplacer. */ /* ATTENTION : on n'utilise pas 'SPIRALE_DEPLACEMENT_ET_PARCOURS(...)' afin de garantir la */ /* terminaison du processus 'Tant(...)'. */ TEST_VOISINAGE(IFLT,VRAI,ASD1(point_courant,x),ASD1(point_courant,y)); /* Test du voisinage du point courant ; cette fonction 'TEST_VOISINAGE' est */ /* laissee la pour des raisons historiques : elles permettaient de choisir */ /* les directions de test (premier argument 'VRAI'). */ SPIRALE_PARCOURS; /* Parcours de la spirale avec rotation eventuelle de PI/2 du bras courant... */ SPIRALE_COMPTAGE; /* Et on calcule le nombre de points que l'on a traite (quel que soit leur etat). */ Eblock ETan Eblock ATes Bblock Eblock ETes Eblock ATes Bblock Eblock ETes Test(EST_VRAI(on_a_trouve_au_moins_un_voisin)) Bblock INCR(ASD1(point_courant_sur_la_ligne,x) ,COND(IFGT(X_voisin,ASD1(point_courant_sur_la_ligne,x)) ,pasX ,COND(IFLT(X_voisin,ASD1(point_courant_sur_la_ligne,x)) ,NEGA(pasX) ,ZERO ) ) ); INCR(ASD1(point_courant_sur_la_ligne,y) ,COND(IFGT(Y_voisin,ASD1(point_courant_sur_la_ligne,y)) ,pasY ,COND(IFLT(Y_voisin,ASD1(point_courant_sur_la_ligne,y)) ,NEGA(pasY) ,ZERO ) ) ); /* On a trouve un successeur, qui est en fait le "meilleur" voisin, c'est-a-dire */ /* celui qui est dans la direction d'un point eventuellement eloigne, et dont */ /* le niveau est le plus eloigne par valeur inferieure de celui du point */ /* courant... */ Eblock ATes Bblock Eblock ETes INCR(nombre_de_points_sur_la_ligne,I); /* Et on compte les points generes sur la ligne de plus grande pente... */ Test(IFOU(EST_FAUX(on_a_trouve_au_moins_un_voisin) ,IFGE(nombre_de_points_sur_la_ligne,nombre_de_points_maximal) ) ) Bblock EGAL(on_a_trouve_au_moins_un_successeur,FAUX); /* Lorsque l'on n'a trouve aucun voisin (ou que l'on a genere trop de */ /* points, ce nombre ne pouvant exceder le nombre de couleurs puisque */ /* les tests sur les niveaux decroissent strictement), on s'arrete... */ Eblock ATes Bblock Eblock ETes Eblock ETan EGAL(ASI1(point_d_arrivee,x),_____cNORMALISE_OX(ASD1(point_courant_sur_la_ligne,x))); EGAL(ASI1(point_d_arrivee,y),_____cNORMALISE_OY(ASD1(point_courant_sur_la_ligne,y))); /* Renvoi des coordonnees du point d'arrivee de la ligne de plus grande pente... */ Eblock ETes RETI(imageR); Eblock #undef TEST_VOISINAGE #undef NOMBRE_DE_POINTS_MAXIMAL EFonctionP _______________________________________________________________________________________________________________________________________ _______________________________________________________________________________________________________________________________________ /*===================================================================================================================================*/ /*************************************************************************************************************************************/ /* */ /* C A L C U L D E S D I S T A N C E S A U X B O R D S D ' U N E I M A G E : */ /* */ /* */ /* Principe : */ /* */ /* Cette fonction est destinee a calculer */ /* les distances respectives aux quatre bords */ /* de l'image. */ /* */ /* */ /* bord du haut */ /* Ymax -------------------------------------- */ /* | . | */ /* | . niveaux<=seuil | */ /* | . | */ /* | Dh. *** | */ /* | . ** *** | */ /* | . ** **** | */ /* | . *** ***** Dd | */ /* | *** *..........| */ /* bord de gauche | ** * | bord de droite */ /* | * ** | */ /* | Dg * ** | */ /* |.........** ** | */ /* | **** *** | */ /* | *** **** | */ /* | ***** niveaux<=seuil| */ /* | . | */ /* | niveaux<=seuil .Db | */ /* | . | */ /* Ymin -------------------------------------- */ /* Xmin bord du bas Xmax */ /* */ /* */ /*************************************************************************************************************************************/ BFonctionP #define NIVEAU_DE_MARQUAGE_DU_BAS \ GRIS_1 \ /* Niveau de generation des points du bas dans 'imageR', */ #define NIVEAU_DE_MARQUAGE_DU_HAUT \ GRIS_3 \ /* Niveau de generation des points du haut dans 'imageR'. */ #define NIVEAU_DE_MARQUAGE_DE_LA_GAUCHE \ GRIS_5 \ /* Niveau de generation des points de la gauche dans 'imageR', */ #define NIVEAU_DE_MARQUAGE_DE_LA_DROITE \ GRIS_7 \ /* Niveau de generation des points de la droite dans 'imageR'. */ DEFV(Common,DEFV(FonctionP,POINTERp(Icalcul_des_distances_aux_bords(imageR ,bord_du_bas ,bord_du_haut ,bord_de_gauche ,bord_de_droite ,imageA ,seuil_du_contour ) ) ) ) DEFV(Argument,DEFV(image,imageR)); /* Image Resultat dans laquelle on porte les points extraits. */ DEFV(Argument,DEFV(ligneF,bord_du_bas)); /* Distances flottantes dans [0,1] au bord du bas des premiers points */ /* de niveau superieur ou egal au seuil argument, */ DEFV(Argument,DEFV(ligneF,bord_du_haut)); /* Distances flottantes dans [0,1] au bord du haut des premiers points */ /* de niveau superieur ou egal au seuil argument. */ DEFV(Argument,DEFV(colonneF,bord_de_gauche)); /* Distances flottantes dans [0,1] au bord de gauche des premiers points */ /* de niveau superieur ou egal au seuil argument, */ DEFV(Argument,DEFV(colonneF,bord_de_droite)); /* Distances flottantes dans [0,1] au bord de droite des premiers points */ /* de niveau superieur ou egal au seuil argument. */ DEFV(Argument,DEFV(image,imageA)); /* Image Argument. */ DEFV(Argument,DEFV(genere_p,seuil_du_contour)); /* Niveau definissant ce qui est a l'exterieur et ce qui est a l'interieur */ /* du pseudo contour que l'on recherche ainsi : */ /* les points de niveau inferieur ou egal a 'seuil' sont exterieurs, et */ /* les points de niveau strictement superieur a 'seuil' sont interieurs. */ /*-----------------------------------------------------------------------------------------------------------------------------------*/ Bblock /*..............................................................................................................................*/ begin_ligne Bblock EGAL(LIGNE(bord_du_haut,X,Ymin),_____cNORMALISE_OY(PREY(Ymin))); EGAL(LIGNE(bord_du_bas,X,Ymin),_____cNORMALISE_OY(SUCY(Ymax))); /* Initialisation du haut et du bas pour la verticale 'X' courante. */ begin_colonne Bblock Test(IFGT(load_point(imageA,X,Y),seuil_du_contour)) Bblock EGAL(LIGNE(bord_du_haut,X,Y),MAX2(_____cNORMALISE_OY(Y),LIGNE(bord_du_haut,X,Y))); EGAL(LIGNE(bord_du_bas,X,Y),MIN2(_____cNORMALISE_OY(Y),LIGNE(bord_du_bas,X,Y))); /* Calcul du haut et du bas pour la verticale 'X' courante */ /* lorsque le niveau du point courant {X,Y} depasse le seuil. */ Eblock ATes Bblock Eblock ETes Eblock end_colonne store_point_valide(NIVEAU_DE_MARQUAGE_DU_BAS ,imageR ,X,_cDENORMALISE_OY(LIGNE(bord_du_bas,X,Ymin)) ,FVARIABLE ); store_point_valide(NIVEAU_DE_MARQUAGE_DU_HAUT ,imageR ,X,_cDENORMALISE_OY(LIGNE(bord_du_haut,X,Ymin)) ,FVARIABLE ); Eblock end_ligne begin_colonne Bblock EGAL(COLONNE(bord_de_droite,Xmin,Y),_____cNORMALISE_OX(PREX(Xmin))); EGAL(COLONNE(bord_de_gauche,Xmin,Y),_____cNORMALISE_OX(SUCX(Xmax))); /* Initialisation de la droite et de la gauche pour l'horizontale 'Y' courante. */ begin_ligne Bblock Test(IFGT(load_point(imageA,X,Y),seuil_du_contour)) Bblock EGAL(COLONNE(bord_de_droite,X,Y),MAX2(_____cNORMALISE_OX(X),COLONNE(bord_de_droite,X,Y))); EGAL(COLONNE(bord_de_gauche,X,Y),MIN2(_____cNORMALISE_OX(X),COLONNE(bord_de_gauche,X,Y))); /* Calcul de la droite et de la gauche pour l'horizontale 'Y' courante */ /* lorsque le niveau du point courant {X,Y} depasse le seuil. */ Eblock ATes Bblock Eblock ETes Eblock end_ligne store_point_valide(NIVEAU_DE_MARQUAGE_DE_LA_DROITE ,imageR ,_cDENORMALISE_OX(COLONNE(bord_de_droite,Xmin,Y)),Y ,FVARIABLE ); store_point_valide(NIVEAU_DE_MARQUAGE_DE_LA_GAUCHE ,imageR ,_cDENORMALISE_OX(COLONNE(bord_de_gauche,Xmin,Y)),Y ,FVARIABLE ); Eblock end_colonne RETI(imageR); Eblock #undef NIVEAU_DE_MARQUAGE_DE_LA_DROITE #undef NIVEAU_DE_MARQUAGE_DE_LA_GAUCHE #undef NIVEAU_DE_MARQUAGE_DU_HAUT #undef NIVEAU_DE_MARQUAGE_DU_BAS EFonctionP _______________________________________________________________________________________________________________________________________