/* Segmentation à partir d'un ensemble de germes. Pour chaque germe, on fait
   croitre la région correspondante jusqu'à rencontrer des niveaux supérieurs
   à une fraction de l'amplitude du germe
*/

#include "image.h"
#include "grille.h"
#include "r.h"
#include "fourier.h"
#include "ondel.h"
#include "dev.h"

typedef struct p
	{
	int			xcoord;
	int			ycoord;
	struct p  * pt;
	} poin ;
static poin   *	tete, *queue, *poi;
static void		Empiler ( int x, int y );
static poin   * Depiler ( void );


 static void Empiler ( int x, int y )
/***********************************/
// Empile en queue de liste
{
 poin	*	ptemp;

 ptemp            = calloc(1,sizeof(poin));
 ptemp -> xcoord  = x;
 ptemp -> ycoord  = y;
 ptemp -> pt      = NULL;
 if (tete == NULL)
      tete = ptemp;
 else
	  queue -> pt = ptemp;
 queue       = ptemp;
}


 static poin  * Depiler ( void )
/******************************/
{
// Dépile la queue de la liste
 poin  *ptdep, *pt1, *pt2;

 ptdep = NULL;
 if (tete != NULL)
      {
      pt1 = tete;
      pt2 = pt1 -> pt;
      if (pt2 == NULL)
	   {
           ptdep = tete;
           tete  = NULL;
	   queue = NULL;
           }
      else
           {
           while (pt2 != queue)
		{
		pt1 = pt2;
                pt2 = pt2 -> pt;
                }
           queue    = pt1;
           ptdep     = pt2;
           pt1 -> pt = NULL;
           }
      }
 return(ptdep);
}



Image RempliRegionR(Image imaS,Image imaD, int germex,int germey, Reel seuil, Reel niv)
/*******************************************************************************/
/*  Même fonction que RempliR avec prise en compte de l'image source et
    remplissage des niveaux supérieurs au seuil.
    Remplissage d'une région avec le niveau  niv définie à
    partir des coordonnées d'un germe et d'un niveau seuil

    imaS : image initiale
    imaD : image contenant la région remplie avec le niveau niv
    germex,germey : coordonnées relatives du germe
    seuil : remplissage de tous les pixels de imS de niveau > seuil
    niv : niveau de remplissage de la région
*/
{

int xs,ys,x, y, xg, xd, xx, yy, xanc;
Reel **grille,**grD;
Image imT=imaS;

if (imaS==NULL) return(NULL);
imaD=CreeImageDest(imaS,imaD,T_REEL);
if (imaS->type!=T_REEL) imT=TransfereR(imaS,NULL);
grille=(Reel **)CreeGrille(imT,Z_FENETRE);
grD=(Reel **)CreeGrille(imaD,Z_FENETRE);

if (imaD && imT && grille && grD)
 {
 LitTailleFenetre(imaS,&xs,&ys);

 x=germex; y=germey;

 tete=NULL;
 Empiler(x,y);

 while (tete!=NULL)        // tant que la pile n'est pas vide
    {
	 poi=Depiler();
	 x = poi -> xcoord;
    y = poi -> ycoord;
    free(poi);
	 if ((grille[y][x] >seuil)&&(grD[y][x]!=niv))
	  {                                          // Remplir la ligne à droite
	  xx=x;
	  while ((xx<xs) && (grille[y][xx] > seuil)&&(grD[y][xx]!=niv))
	    {  grD[y][xx++]=niv; }
	  xd=xx-1;
	  xx=x-1;                                    // Remplir la ligne à gauche
	  while((xx>=0) && (grille[y][xx] >  seuil)&&(grD[y][xx]!=niv))
	    {  grD[y][xx--]=niv; }
	  xg=xx+1;

 	  if (y-1>=0)             // Empiler les germes de la ligne précédente
	     {
	     yy=y-1; xx=xg;
	     while (xx<=xd)
		    {
          while((xx<=xd)&&((grille[yy][xx]<=seuil)||(grD[yy][xx]==niv)))xx++;
		    if (xx<=xd)
		     {
		     Empiler(xx,yy);
		     while((xx<=xd)&&(grille[yy][xx]>seuil)&&(grD[yy][xx]!=niv)) xx++;
		     }
          }
	     }

     if (y+1<ys)            // Empiler les germes de la ligne suivante
	     {
	     yy=y+1; xx=xg;
	     while(xx<=xd)
		    {
          xanc=xx;
		    while((xx<=xd)&&((grille[yy][xx]<=seuil)||(grD[yy][xx]==niv)))xx++;
  		    if (xx<=xd)
		     {
   		  Empiler(xx,yy);
           while((xx<=xd)&&(grille[yy][xx]>seuil)&&(grD[yy][xx]!=niv))
			  xx++;
		     }
		    if(xanc==xx) return(NULL);
		    }
        } // fin if
	  } // fin if
    }  // fin while
 }  // fin if
LibereGrille(grD);
LibereGrille(grille);
if (imT!=imaS) LibereImage(imT);
return(imaD);
}

Image RempliRegionV8R(Image imaS,Image imaD, int germex,int germey, Reel seuil, Reel niv)
/*******************************************************************************/
/*  Même fonction que RempliR avec prise en compte de l'image source et
    remplissage des niveaux supérieurs au seuil, avec propagation des germes
    sur un V8.
    Remplissage d'une région avec le niveau  niv définie à
    partir des coordonnées d'un germe et d'un niveau seuil

    imaS : image initiale
    imaD : image contenant la région remplie avec le niveau niv
    germex,germey : coordonnées relatives du germe
    seuil : remplissage de tous les pixels de imS de niveau > seuil
    niv : niveau de remplissage de la région

    !! Remplissage d'une zone **supérieure** au seuil
    !! Bug de l'image source corrigé dans cette version
*/
{

int xs,ys,x, y, xg, xd, xx, yy, xanc;
Reel **grille,**grD;
Image imT=imaS;

if (imaS==NULL) return(NULL);
imaD=CreeImageDest(imaS,imaD,T_REEL);
if (imaS->type!=T_REEL) imT=TransfereR(imaS,NULL);
grille=(Reel **)CreeGrille(imT,Z_FENETRE);
grD=(Reel **)CreeGrille(imaD,Z_FENETRE);

if (imaD && imT && grille && grD)
 {
 LitTailleFenetre(imaS,&xs,&ys);

 x=germex; y=germey;

 tete=NULL;
 Empiler(x,y);

 while (tete!=NULL)        // tant que la pile n'est pas vide
    {
	 poi=Depiler();
	 x = poi -> xcoord;
    y = poi -> ycoord;
    free(poi);
	 if ((grille[y][x] >seuil)&&(grD[y][x]!=niv))
	  {                                          // Remplir la ligne à droite
	  xx=x;
	  while ((xx<xs) && (grille[y][xx] > seuil)&&(grD[y][xx]!=niv))
	    {  grD[y][xx++]=niv; }
	  if (xx==xs) xd=xx-1;
    else xd=xx;
	  xx=x-1;                                    // Remplir la ligne à gauche
	  while((xx>=0) && (grille[y][xx] >  seuil)&&(grD[y][xx]!=niv))
	    {  grD[y][xx--]=niv; }
	  if (xx<0) xg=xx+1;
    else xg=xx;

 	  if (y-1>=0)             // Empiler les germes de la ligne précédente
	     {
	     yy=y-1; xx=xg;
	     while (xx<=xd)
		    {
          while((xx<=xd)&&((grille[yy][xx]<=seuil)||(grD[yy][xx]==niv)))xx++;
		    if (xx<=xd)
		     {
		     Empiler(xx,yy);
		     while((xx<=xd)&&(grille[yy][xx]>seuil)&&(grD[yy][xx]!=niv)) xx++;
		     }
          }
	     }

     if (y+1<ys)            // Empiler les germes de la ligne suivante
	     {
	     yy=y+1; xx=xg;
	     while(xx<=xd)
		    {
          xanc=xx;
		    while((xx<=xd)&&((grille[yy][xx]<=seuil)||(grD[yy][xx]==niv)))xx++;
  		    if (xx<=xd)
		     {
   		  Empiler(xx,yy);
           while((xx<=xd)&&(grille[yy][xx]>seuil)&&(grD[yy][xx]!=niv))
			  xx++;
		     }
		    if(xanc==xx) return(NULL);
		    }
        } // fin if
	  } // fin if
    }  // fin while
 }  // fin if
LibereGrille(grD);
LibereGrille(grille);
if (imT!=imaS) LibereImage(imT);
return(imaD);
}



/*
Enregistreur->Ajoute(*new MFct5Arg<MImage,MImage,MImage,MRImage,MFloat,MFloat,Image(*)(Image,Image,Image,Reel,Reel)>(
	"SeuilParGermesR",SeuilParGermesR,"imS","imG","imD","seuilRel","niv"));
*/

Image SeuilParGermesR(Image imS,Image imG,Image imD,Reel seuilRel,Reel niv)
/************************************************************************/
/* Segmentation à partir d'un ensemble de germes. Pour chaque germe, on fait
   croitre la région correspondante jusqu'à rencontrer des niveaux inférieurs
   à une fraction de l'amplitude du germe
   imS : image initiale
   imG : image contenant les germes, chaque germe a une amplitude ampl
   imD : image contenant le résultat
   seuilRel : remplissage de tous les pixels de imS de niveau > seuilRel*ampl
   niv : niveau de remplissage des régions
*/
{
Canal can;
Reel *val;
int i,j,x,y;

if (TesteFenetre(imS,imG)) return(NULL);
imD=CreeImageDest(imS,imD,T_REEL);
can=CreeCanal(imG,T_REEL,B_LIGNE,Z_FENETRE);
LitTailleFenetre(imG,&x,&y);
val=(Reel *)calloc(x,sizeof(Reel));

if (imD && can && val)
  {
  for(i=0;i<y;i++)
    {
    LitCanal(can,val);
    for (j=0;j<x;j++)
      if (val[j]!=0) RempliRegionR(imS,imD,j,i,seuilRel*val[j],niv);
    }
  }
free(val);
LibereCanal(can);
return(imD);
}


Image SeuilParGermesV8R(Image imS,Image imG,Image imD,Reel seuilRel,Reel niv)
/************************************************************************/
/*Idem SeuilParGermesR, mais la croissance de région est en V8
  Segmentation à partir d'un ensemble de germes. Pour chaque germe, on fait
   croitre la région correspondante jusqu'à rencontrer des niveaux inférieurs
   à une fraction de l'amplitude du germe
   imS : image initiale
   imG : image contenant les germes, chaque germe a une amplitude ampl
   imD : image contenant le résultat
   seuilRel : remplissage de tous les pixels de imS de niveau > seuilRel*ampl
   niv : niveau de remplissage des régions
*/
{
Canal can;
Reel *val;
int i,j,x,y;

if (TesteFenetre(imS,imG)) return(NULL);
imD=CreeImageDest(imS,imD,T_REEL);
can=CreeCanal(imG,T_REEL,B_LIGNE,Z_FENETRE);
LitTailleFenetre(imG,&x,&y);
val=(Reel *)calloc(x,sizeof(Reel));

if (imD && can && val)
  {
  for(i=0;i<y;i++)
    {
    LitCanal(can,val);
    for (j=0;j<x;j++)
      if (val[j]!=0) RempliRegionV8R(imS,imD,j,i,seuilRel*val[j],niv);
    }
  }
free(val);
LibereCanal(can);
return(imD);
}



Image SeuilLaplGermesR(Image imS,Image imD,Reel echLapl,Reel seuilLapl,Reel seuilGerme)
/*************************************************************************************/
/* Segmentation par germes sur le laplacien. On calcule le laplacien,
   on cherche les max locaux du laplacien supérieurs à seuilLapl, puis on seuil
   par germes sur l'image de laplacien
   echLapl : échelle de calcul du laplacien (valeur typique 1)
   seuilLapl : niveau de seuil du laplacien
   seuilGerme : remplissage de tous les pixels du laplacien
                de niveau > seuilGerme*ampl (valeur typique 0.3)
*/
{
Image imTF,imOnd,imLapl,imG;

imTF=TFRDirecteC(imS,NULL);
imOnd=OndelContChapeauMexicC(imTF,NULL,echLapl,1);
LibereImage(imTF);
imLapl=TransfereR(imOnd,NULL);
LibereImage(imOnd);
ConstMultR(imLapl,imLapl,-1);
imG=Max4DirR(imLapl,NULL);
SeuilleInfR(imG,imG,seuilLapl,0);
imD=SeuilParGermesR(imLapl,imG,imD,seuilGerme,1);
LibereImage(imG);
LibereImage(imLapl);
return(imD);
}

