_______________________________________________________________________________________________________________________________________
/*************************************************************************************************************************************/
/* */
/* 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
_______________________________________________________________________________________________________________________________________