#include <stdlib.h>
#include "math.h"
#include "image.h"
#include "canal.h"
#include "grille.h"
#include "r.h"
#include "c.h"
#include "fourier.h"
#include "ondel.h"


static void filtreDirect(Reel *sigS, Reel *sigD, Reel *filtre, int n, int nf,int d);
static void filtreInverse(Reel *sigS, Reel *sigD, Reel *filtre, int n, int nf, int d);
static int filtreHGdirect(Image imS, Image imD, Reel *fh, Reel *fg, int n, int df, int dg);
static int filtreHGinverse(Image imS, Image imD, Reel *fh, Reel *fg, int n, int df, int dg);

static int zeroV(Image imS, Image imD);
static int zeroH(Image imS, Image imD);
static int zeroD(Image imS, Image imD);
static int maxH(Image imS, Image imD);
static int maxV(Image imS, Image imD);
static int maxMH(Image imS, Image imD);
static int maxMV(Image imS, Image imD);

//Transformée en ondelette continue
static int ondelContinueC(Image imS, Image imOnd);


static void filtreDirect(Reel *sigS, Reel *sigD, Reel *filtre, int n, int nf,int d)
/***********************************************************************/

{
int i,j,i1,ii,j0;
Reel sd;

i1=n/2;

for (i=0;i<i1;i++)
	 {
	 sd=0;
	ii=i+i;
	 j0=ii-d+1;
	 for (j=j0-nf;j<j0;j++)
		  sd+=sigS[(n+j%n)%n]*filtre[ii-j-d];
	 sigD[i]=sd;
	 }
}



static void filtreInverse(Reel *sigS, Reel *sigD, Reel *filtre, int n, int nf, int d)
/************************************************************************/

{
int i,j,i1,j0,j1;
Reel sd;

i1=2*n;

for (i=0;i<i1;i++)
	 {
	sd=0;
	j0=(i<-d-1)?(i+d)/2:(i+d+1)/2;
	 j1=(i+d+1+nf)/2;
	 for (j=j0; j<j1 ;j++)
		sd+=sigS[(n+j%n)%n]*filtre[2*j-i-d];
	 sigD[i]=sd;
	 }

}

static int filtreHGdirect(Image imS, Image imD, Reel *fh, Reel *fg, int n, int df, int dg)
/*******************************************************************/

{
Canal canL;
int i,j,x,y;
Reel *bufL, *bufE, **grille;

LitTailleFenetre(imS, &x, &y);
if (x%2) return(1);
if ( (y!=1) && (y%2) ) return(1);

if ( (bufL=(Reel*)calloc(x,sizeof(Reel)))==NULL) return(1);
if ( (bufE=(Reel*)calloc(x,sizeof(Reel)))==NULL) return(1);
if ( (grille=(Reel**)CreeGrille(imD,Z_FENETRE))==NULL) return(1);
if ( (canL=CreeCanal(imS,T_REEL,B_LIGNE,Z_FENETRE))==NULL) return(1);

for (i=0;i<y;i++)
	 {
	 LitCanal(canL,bufL);
	 filtreDirect(bufL,bufE,fh,x,n,df);
	 filtreDirect(bufL,&bufE[x/2],fg,x,n,dg);
	 for (j=0;j<x;j++) grille[i][j]=bufE[j];
	 }
EcritTailleFenetre(imD,x/2,y);
if (y>1)
	 {
	 if (y>x)
		  {
		  if ( (bufL=(Reel*)realloc(bufL,y*sizeof(Reel)))==NULL) return(1);
		  if ( (bufE=(Reel*)realloc(bufE,y*sizeof(Reel)))==NULL) return(1);
		  }
	 for(j=0;j<x;j++)
		  {
		  for (i=0;i<y;i++) bufL[i]=grille[i][j];
		  filtreDirect(bufL,bufE,fh,y,n,df);
		  filtreDirect(bufL,&bufE[y/2],fg,y,n,dg);
		  for (i=0;i<y;i++) grille[i][j]=bufE[i];
		  }
	 EcritTailleFenetre(imD,x/2,y/2);
	 }

LibereCanal(canL);
LibereGrille(grille);
free(bufE);
free(bufL);
return(0);
}



static int filtreHGinverse(Image imS, Image imD, Reel *fh, Reel *fg, int n, int df, int dg)
/********************************************************************/

{
int i,j,x,y;
Reel *bufL, *bufE1, *bufE2, **grille;

LitTailleFenetre(imS, &x, &y);
x*=2;
if (imS->taille.y>1) y*=2;
if (x>imS->taille.x-imS->fenetre.origine.x) return(1);
if (y>imS->taille.y-imS->fenetre.origine.y) return(1);
if (x>imD->taille.x-imD->fenetre.origine.x) return(1);
if (y>imD->taille.y-imD->fenetre.origine.y) return(1);
EcritTailleFenetre(imS,x,y);
EcritTailleFenetre(imD,x,y);

if ( (bufL=(Reel*)calloc(y,sizeof(Reel)))==NULL) return(1);
if ( (bufE1=(Reel*)calloc(y,sizeof(Reel)))==NULL) return(1);
if ( (bufE2=(Reel*)calloc(y,sizeof(Reel)))==NULL) return(1);
if ( (grille=(Reel**)CreeGrille(imD,Z_FENETRE))==NULL) return(1);

if (y>1)
    {
    for(j=0;j<x;j++)
        {
		  for (i=0;i<y;i++) bufL[i]=grille[i][j];
        filtreInverse(bufL,bufE1,fh,y/2,n, df);
		  filtreInverse(&bufL[y/2],bufE2,fg,y/2,n, dg);
        for (i=0;i<y;i++) grille[i][j]=2*bufE1[i]+2*bufE2[i];
        }
    }
if (x>y)
    {
    if ( (bufE1=(Reel*)realloc(bufE1,x*sizeof(Reel)))==NULL) return(1);
    if ( (bufE2=(Reel*)realloc(bufE2,x*sizeof(Reel)))==NULL) return(1);
    }
for (i=0;i<y;i++)
	 {
    filtreInverse(grille[i],bufE1,fh,x/2,n,df);
    filtreInverse(&grille[i][x/2],bufE2,fg,x/2,n,dg);
    for (j=0;j<x;j++) grille[i][j]=2*bufE1[j]+2*bufE2[j];
    }

LibereGrille(grille);
free(bufE2);
free(bufE1);
free(bufL);
return(0);
}



static int zeroV(Image imS, Image imD)
/************************************/

{
int i,j,x,y;
Reel **grilleS, **grilleD, v, v1;

if ( (grilleS=(Reel**)CreeGrille(imS,Z_FENETRE))==NULL) return(1);
if ( (grilleD=(Reel**)CreeGrille(imD,Z_FENETRE))==NULL) return(1);
LitTailleFenetre(imS,&x,&y);

for(j=0;j<x;j++)
    {
    v=grilleS[0][j];
    for (i=0;i<y-1;i++)
        {
        v1=grilleS[i+1][j];
		  if (v*v1<=0)
            {
            v=v1;
            grilleD[i][j]=fabs(v1-grilleS[i][j]);
            }
        else grilleD[i][j]=0;
        }
	 grilleD[y-1][j]=0;
    }

LibereGrille(grilleD);
LibereGrille(grilleS);

return(0);
}


static int zeroH(Image imS, Image imD)
/************************************/

{
int i,j,x,y;
Reel **grilleS, **grilleD, v, v1;

if ( (grilleS=(Reel**)CreeGrille(imS,Z_FENETRE))==NULL) return(1);
if ( (grilleD=(Reel**)CreeGrille(imD,Z_FENETRE))==NULL) return(1);
LitTailleFenetre(imS,&x,&y);

for(i=0;i<y;i++)
    {
	 v=grilleS[i][0];
    for (j=0;j<x-1;j++)
		  {
        v1=grilleS[i][j+1];
        if (v*v1<=0)
            {
            v=v1;
            grilleD[i][j]=fabs(v1-grilleS[i][j]);
            }
        else grilleD[i][j]=0;
        }
	 grilleD[i][x-1]=0;
    }

LibereGrille(grilleD);
LibereGrille(grilleS);

return(0);
}



static int zeroD(Image imS, Image imD)
/************************************/

{
int i,j,x,y;
Reel **grilleS, **grilleD, v, v1, v2, d, d1;

if ( (grilleS=(Reel**)CreeGrille(imS,Z_FENETRE))==NULL) return(1);
if ( (grilleD=(Reel**)CreeGrille(imD,Z_FENETRE))==NULL) return(1);
LitTailleFenetre(imS,&x,&y);

for(i=0;i<y-1;i++)
	 {
    grilleD[i][0]=0;
	 for (j=1;j<x-1;j++)
        {
        d=0;
        v=grilleS[i][j];
        v1=grilleS[i+1][j-1];
        v2=grilleS[i+1][j+1];
        if (v*v1<=0) d=fabs(v-v1);
        if (v*v2<=0)
            {
				d1=fabs(v-v2);
				if (d<d1) d=d1;
				}
        grilleD[i][j]=d;
        }
	 grilleD[i][x-1]=0;
    }
for (j=0;j<x;j++) grilleD[y-1][j]=0;

LibereGrille(grilleD);
LibereGrille(grilleS);

return(0);
}


static int maxH(Image imS, Image imD)
/***********************************/

{
int i,j,x,y;
Complexe **grilleD,zeroc={0,0};
Reel v,v0,v1;
Canal canL;

if ( (grilleD=(Complexe**)CreeGrille(imD,Z_FENETRE))==NULL) return(1);
if ( (canL=CreeCanal(imS,T_COMPLEXE,B_LIGNE,Z_FENETRE))==NULL) return(1);
LitTailleFenetre(imS,&x,&y);

for(i=0;i<y;i++)
	{
	LitCanal(canL,grilleD[i]);
	v=fabs(grilleD[i][0].x);
	if (x>1)
		{
		v1=fabs(grilleD[i][1].x);
		if (v<v1) grilleD[i][0]=zeroc;
		for (j=1;j<x-1;j++)
			{
			v0=v;
			v=v1;
			v1=fabs(grilleD[i][j+1].x);
			if ((v<v1)||(v<v0)) grilleD[i][j]=zeroc;
			}
		if (v1<v) grilleD[i][x-1]=zeroc;
		}
	}

LibereCanal(canL);
LibereGrille(grilleD);

return(0);
}


static int maxV(Image imS, Image imD)
/***********************************/

{
int i,j,x,y;
Complexe **grilleD,**grilleS,zeroc={0,0};
Reel v,v0,v1;

if ( (grilleD=(Complexe**)CreeGrille(imD,Z_FENETRE))==NULL) return(1);
if ( (grilleS=(Complexe**)CreeGrille(imS,Z_FENETRE))==NULL) return(1);
LitTailleFenetre(imS,&x,&y);

for(j=0;j<x;j++)
	{
	v=fabs(grilleS[0][j].y);
	if (y>1)
		{
		v1=fabs(grilleS[1][j].y);
		if (v>=v1) grilleD[0][j]=grilleS[0][j];
		else grilleD[0][j]=zeroc;
		for (i=1;i<y-1;i++)
			{
			v0=v;
			v=v1;
			v1=fabs(grilleS[i+1][j].y);
			if ((v>=v1)&&(v>=v0)) grilleD[i][j]=grilleS[i][j];
			else grilleD[i][j]=zeroc;
			}
		if (v1>=v)  grilleD[y-1][j]=grilleS[y-1][j];
		else grilleD[y-1][j]=zeroc;
		}
	else grilleD[0][j]=grilleS[0][j];
	}

LibereGrille(grilleS);
LibereGrille(grilleD);

return(0);
}



static int maxMH(Image imS, Image imD)
/************************************/

{
int i,j,x,y;
Complexe **grilleD,zeroc={0,0};
Reel v,v0,v1,xx,yy;
Canal canL;

if ( (grilleD=(Complexe**)CreeGrille(imD,Z_FENETRE))==NULL) return(1);
if ( (canL=CreeCanal(imS,T_COMPLEXE,B_LIGNE,Z_FENETRE))==NULL) return(1);
LitTailleFenetre(imS,&x,&y);

for(i=0;i<y;i++)
	{
	LitCanal(canL,grilleD[i]);
	xx=grilleD[i][0].x;
	yy=grilleD[i][0].y;
	v=xx*xx+yy*yy;
	if (x>1)
		{
		xx=grilleD[i][1].x;
		yy=grilleD[i][1].y;
		v1=xx*xx+yy*yy;
		if (v<v1) grilleD[i][0]=zeroc;
		for (j=1;j<x-1;j++)
			{
			v0=v;
			v=v1;
			xx=grilleD[i][j+1].x;
			yy=grilleD[i][j+1].y;
			v1=xx*xx+yy*yy;
			if ((v<v1)||(v<v0)) grilleD[i][j]=zeroc;
			}
		if (v1<v) grilleD[i][x-1]=zeroc;
		}
	}

LibereCanal(canL);
LibereGrille(grilleD);

return(0);
}


static int maxMV(Image imS, Image imD)
/************************************/

{
int i,j,x,y;
Complexe **grilleD,**grilleS,zeroc={0,0};
Reel v,v0,v1,xx,yy;

if ( (grilleD=(Complexe**)CreeGrille(imD,Z_FENETRE))==NULL) return(1);
if ( (grilleS=(Complexe**)CreeGrille(imS,Z_FENETRE))==NULL) return(1);
LitTailleFenetre(imS,&x,&y);

for(j=0;j<x;j++)
	{
	xx=grilleS[0][j].x;
	yy=grilleS[0][j].y;
	v=xx*xx+yy*yy;
	if (y>1)
		{
		xx=grilleS[1][j].x;
		yy=grilleS[1][j].y;
		v1=xx*xx+yy*yy;
		if (v>=v1) grilleD[0][j]=grilleS[0][j];
		else grilleD[0][j]=zeroc;
		for (i=1;i<y-1;i++)
			{
			v0=v;
			v=v1;
			xx=grilleS[i+1][j].x;
			yy=grilleS[i+1][j].y;
			v1=xx*xx+yy*yy;
			if ((v>=v1)&&(v>=v0)) grilleD[i][j]=grilleS[i][j];
			else grilleD[i][j]=zeroc;
			}
		if (v1>=v)  grilleD[y-1][j]=grilleS[y-1][j];
		else grilleD[y-1][j]=zeroc;
		}
	else grilleD[0][j]=grilleS[0][j];
	}

LibereGrille(grilleS);
LibereGrille(grilleD);

return(0);
}




Image TransfereOndelC(Image imS, Image imD, int ordre)
/****************************************************/

{
int x,y,ox,oy,ox1,oy1,x1,y1;
Image imSb;

if (imS==NULL) return(NULL);
if ((imSb=(Image)malloc(sizeof(*imSb)))==NULL) return(NULL);
*imSb=*imS;

LitTailleFenetre(imS,&x,&y);
LitOrigineFenetre(imS,&ox,&oy);
x1=x>>ordre;
ox1=ox+x1;
if (y>1)
	{
	y1=y>>ordre;
	oy1=oy+y1;
	}
else
	{
	y1=1;
	oy1=oy;
	}

EcritTailleFenetre(imS,x1,y1);
EcritTailleFenetre(imSb,x1,y1);
EcritOrigineFenetre(imS,ox1,oy);
EcritOrigineFenetre(imSb,ox,oy1);
if ((imD=CreeImageSimple(imD,T_COMPLEXE,V_CARTE,x1,y1))==NULL) return(NULL);
if (TransfereXYC(imS,imSb,imD)==NULL) return(NULL);

EcritOrigineFenetre(imS,ox,oy);
EcritTailleFenetre(imS,x,y);
free(imSb);
return(imD);
}


Image MaxAbsLocalC(Image imS, Image imD)
/**************************************/

{
Image imT;

if ((imD=CreeImageDest(imS,imD,T_COMPLEXE))==NULL) return(NULL);
if ((imT=TransfereC(imS,NULL))==NULL) return(NULL);
if (maxH(imS,imD)) return(NULL);
if (maxV(imT,imT)) return(NULL);
if (OuEtenduC(imD,imT,imD)==NULL) return(NULL);

LibereImage(imT);
return(imD);
}


Image MaxModLocalC(Image imS, Image imD)
/**************************************/

{
Image imT;

if ((imD=CreeImageDest(imS,imD,T_COMPLEXE))==NULL) return(NULL);
if ((imT=TransfereC(imS,NULL))==NULL) return(NULL);
if (maxMH(imS,imD)) return(NULL);
if (maxMV(imT,imT)) return(NULL);
if (OuEtenduC(imD,imT,imD)==NULL) return(NULL);

LibereImage(imT);
return(imD);
}

Image MaxOndelC(Image imS,Image imD,int ordre)
/********************************************/

{
if ((imD=TransfereOndelC(imS,imD,ordre))==NULL) return(NULL);
if (MaxAbsLocalC(imD,imD)==NULL) return(NULL);
return(imD);
}



Image MaxModOndelC(Image imS,Image imD,int ordre)
/***********************************************/

{
if ((imD=TransfereOndelC(imS,imD,ordre))==NULL) return(NULL);
if (MaxModLocalC(imD,imD)==NULL) return(NULL);
return(imD);
}



Image MaxMod1DOndelC(Image imS,Image imD,int ordre)
/************************************************/

{
if ((imD=TransfereOndelC(imS,imD,ordre))==NULL) return(NULL);
if (MaxMod1DirC(imD,imD)==NULL) return(NULL);
return(imD);
}


Image MaxMod2DOndelC(Image imS,Image imD,int ordre)
/************************************************/

{
if ((imD=TransfereOndelC(imS,imD,ordre))==NULL) return(NULL);
if (MaxMod2DirC(imD,imD)==NULL) return(NULL);
return(imD);
}


Image OndelDirecteR(Image imS, Image h, Image imD, int ordre, int ech)
/*********************************************************************/

{
Canal canL;
Reel *fh, *fg, rd2, s1, s2, f2;
int x,y,xh,yh,i,nm1,sgn,df,dg;
Complexe *fhh;

if ((imS==NULL)||(h==NULL)) return(NULL);
LitTailleFenetre(imS,&x,&y);
LitTailleFenetre(h,&xh,&yh);
if (yh>1) return(NULL);
if ( (imD=CreeImageDest(imS,imD,T_REEL))==NULL) return(NULL);
if ( (fh=(Reel*)calloc(xh,sizeof(Reel)))==NULL) return(NULL);
if ( (fg=(Reel*)calloc(xh,sizeof(Reel)))==NULL) return(NULL);
if ( (fhh=(Complexe*)calloc(xh,sizeof(Complexe)))==NULL) return(NULL);

if ( (canL=CreeCanal(h,T_COMPLEXE,B_LIGNE,Z_FENETRE))==NULL) return(NULL);
LitCanal(canL,fhh);
LibereCanal(canL);
if ( (h->type!=T_COMPLEXE)&&(h->type!=T_COMPLEXEL))
	for (i=0;i<xh;i++) fhh[i].y=fhh[i].x;
for (i=0;i<xh;i++) fh[i]=fhh[i].x;

if (ech==1) rd2=sqrt(2);
else rd2=1;
s1=s2=0;
for (i=0;i<xh;i++)
    {
    fh[i]/=rd2;
    f2=fh[i]*fh[i];
    s1+=i*f2;
    s2+=f2;
    }
s1/=s2;
df=-(int)s1;
dg=-xh+2-df;

nm1=xh-1;
sgn=(dg%2)?-1:1;
for (i=0;i<xh;i++)
    {
    fg[i]=sgn*fhh[nm1-i].y/rd2;
    sgn=-sgn;
    }

if (filtreHGdirect(imS, imD, fh, fg, xh, df, dg)) return(NULL);
for (i=1;i<ordre;i++)
    filtreHGdirect(imD, imD, fh, fg, xh, df, dg);

free(fhh);
free(fh);
free(fg);
EcritTailleFenetre(imD,x,y);
return(imD);
}


Image OndelInverseR(Image imS, Image h, Image imD, int ordre)
/************************************************************/

{
Canal canL;
Reel *fh, *fg, rd2, s1, s2, f2;
int x0,y0,x,y,xh,yh,i,nm1,sgn,df,dg;
Complexe *fhh;

if ((imS==NULL)||(h==NULL)) return(NULL);
LitTailleFenetre(imS,&x,&y);
LitTailleFenetre(h,&xh,&yh);
if (yh>1) return(NULL);
if ( (imD=TransfereR(imS,imD))==NULL) return(NULL);
if ( (fh=(Reel*)calloc(xh,sizeof(Reel)))==NULL) return(NULL);
if ( (fg=(Reel*)calloc(xh,sizeof(Reel)))==NULL) return(NULL);
if ( (fhh=(Complexe*)calloc(xh,sizeof(Complexe)))==NULL) return(NULL);

if ( (canL=CreeCanal(h,T_COMPLEXE,B_LIGNE,Z_FENETRE))==NULL) return(NULL);
LitCanal(canL,fhh);
LibereCanal(canL);
if ( (h->type!=T_COMPLEXE)&&(h->type!=T_COMPLEXEL))
	for (i=0;i<xh;i++) fhh[i].y=fhh[i].x;
for (i=0;i<xh;i++) fh[i]=fhh[i].y;

rd2=sqrt(2);
s1=s2=0;
for (i=0;i<xh;i++)
    {
    fh[i]/=rd2;
    f2=fh[i]*fh[i];
    s1+=i*f2;
    s2+=f2;
    }
s1/=s2;
df=-(int)s1;
dg=-xh+2-df;

nm1=xh-1;
sgn=(dg%2)?-1:1;
for (i=0;i<xh;i++)
	 {
	fg[i]=sgn*fhh[nm1-i].x/rd2;
    sgn=-sgn;
    }
x0=x;
y0=y;
x>>=ordre;
if (y>1) y>>=ordre;
EcritTailleFenetre(imD,x,y);

for (i=0;i<ordre;i++)
    filtreHGinverse(imD, imD, fh, fg, xh, df, dg);

free(fhh);
free(fh);
free(fg);
EcritTailleFenetre(imD,x0,y0);
return(imD);
}


int FiltreOndelR(Image imS, int ordre, int proj)
/***********************************************/

{
int x,y,x0,y0,x1,y1,x2,y2;
Reel moy;

if (imS==NULL) return(1);

LitTailleFenetre(imS,&x,&y);
LitOrigineFenetre(imS,&x0,&y0);

x2=x>>ordre;
if (y>1) y2=y>>ordre;
else y2=1;
EcritTailleFenetre(imS,x2,y2);

switch (proj)
    {
    case 1:
     x1=x0+x2;
     y1=y0;
     EcritOrigineFenetre(imS,x1,y1);
     NiveauR(imS,imS,0);

     if (y>1)
         {
			y1=y0+y2;
         EcritOrigineFenetre(imS,x1,y1);
         NiveauR(imS,imS,0);
         x1=x0;
         EcritOrigineFenetre(imS,x1,y1);
         NiveauR(imS,imS,0);
			}
    break;
    case 0:
     MoyenneR(imS,&moy);
     NiveauR(imS,imS,moy);
    break;
    }

EcritOrigineFenetre(imS,x0,y0);
EcritTailleFenetre(imS,x,y);
return(0);
}



Image ZeroOndelR(Image imS, Image imD, int ordre)
/************************************************/

{
int x,y,x0,y0,i,x2,y2,x1,y1;
Image imDb;

if (imS==NULL) return(NULL);
if (imS->type!=T_REEL) return(NULL);

if ((imD=CreeImageDest(imS,imD,T_REEL))==NULL) return(NULL);
if ((imDb=(Image)malloc(sizeof(*imDb)))==NULL) return(NULL);
*imDb=*imD;

LitTailleFenetre(imS,&x,&y);
LitOrigineFenetre(imS,&x0,&y0);
x2=x;
y2=y;

for(i=0;i<ordre;i++)
    {
	 x2/=2;
    if (y>1) y2/=2;
    EcritTailleFenetre(imS,x2,y2);
    EcritTailleFenetre(imD,x2,y2);
    x1=x0+x2;
    y1=y0+y2;
	 EcritOrigineFenetre(imS,x1,y0);
    EcritOrigineFenetre(imD,x1,y0);
    zeroH(imS,imD);
    if (y>1)
        {
        EcritOrigineFenetre(imS,x1,y1);
        EcritOrigineFenetre(imD,x1,y1);
        zeroD(imS,imD);
        EcritOrigineFenetre(imS,x0,y1);
        EcritOrigineFenetre(imD,x0,y1);
        zeroV(imS,imD);

		  EcritTailleFenetre(imDb,x2,y2);
        EcritOrigineFenetre(imDb,x1,y1);
        MaxR(imDb,imD,imDb);
        EcritOrigineFenetre(imD,x1,y0);
		  MaxR(imDb,imD,imDb);
        }
    }

EcritOrigineFenetre(imS,x0,y0);
EcritTailleFenetre(imS,x,y);
EcritOrigineFenetre(imD,x0,y0);
EcritTailleFenetre(imD,x,y);
free(imDb);
return(imD);
}




Image SommeBandeR(Image imS, int b1, int b2)
/*******************************************/

{
int x,y,ox,oy,i,j,x1,y1,ox1,oy1,b,x2,y2,z;
Image imD;
Reel *val1, *val2;
Canal canL1,canL2,canE;

if (imS==NULL) return(NULL);
LitTailleFenetre(imS,&x,&y);
LitOrigineFenetre(imS,&ox,&oy);
x1=x>>b1;
if (y>1) y1=y>>b1;
else y1=1;
ox1=ox+x1;
if (y>1) oy1=oy+y1;
else oy1=oy;
EcritTailleFenetre(imS,x1,y1);
EcritOrigineFenetre(imS,ox1,oy1);
if ((imD=ExtraitFenetreR(imS,NULL))==NULL) return(NULL);
if ((val1=(Reel*)calloc(x1,sizeof(Reel)))==NULL) return(NULL);
if ((val2=(Reel*)calloc(x1/2,sizeof(Reel)))==NULL) return(NULL);
if ((canL1=CreeCanal(imD,T_REEL,B_LIGNE,Z_FENETRE))==NULL) return(NULL);
if ((canE=CreeCanal(imD,T_REEL,B_LIGNE,Z_FENETRE))==NULL) return(NULL);
x2=x1;
y2=y1;
z=1;

for(b=b1;b<b2;b++)
    {
    PoseCanal(canL1,0,0);
    PoseCanal(canE,0,0);
	 x2/=2;
    if (y>1) y2/=2;
	 z*=2;
    if (y>1) oy1=oy+y2;
    else oy1=oy;
    EcritTailleFenetre(imS,x2,y2);
    EcritOrigineFenetre(imS,ox+x2,oy1);
    if ((canL2=CreeCanal(imS,T_REEL,B_LIGNE,Z_FENETRE))==NULL) return(NULL);

    for (i=0;i<y1;i++)
        {
        if (i%z==0) LitCanal(canL2,val2);
        LitCanal(canL1,val1);
        for (j=0;j<x1;j++) val1[j]+=val2[j/z];
        EcritCanal(canE,val1);
        }
	 LibereCanal(canL2);
    }

LibereCanal(canE);
LibereCanal(canL1);
free(val2);
free(val1);
EcritOrigineFenetre(imS,ox,oy);
EcritTailleFenetre(imS,x,y);
return(imD);
}


Image AbsOndelR(Image imS, Image imD, int ordre)
/***********************************************/

{
int x,y,x0,y0,i,x2,y2,x1,y1;
Image imDb;

if (imS==NULL) return(NULL);
if (imS->type!=T_REEL) return(NULL);

if ((imD=CreeImageDest(imS,imD,T_REEL))==NULL) return(NULL);
if ((imDb=(Image)malloc(sizeof(*imDb)))==NULL) return(NULL);
*imDb=*imD;

LitTailleFenetre(imS,&x,&y);
LitOrigineFenetre(imS,&x0,&y0);
x2=x;
y2=y;

for(i=0;i<ordre;i++)
    {
    x2/=2;
    if (y>1) y2/=2;
    EcritTailleFenetre(imS,x2,y2);
    EcritTailleFenetre(imD,x2,y2);
    x1=x0+x2;
    y1=y0+y2;
	 EcritOrigineFenetre(imS,x1,y0);
    EcritOrigineFenetre(imD,x1,y0);
    AbsR(imS,imD);
    if (y>1)
        {
        EcritOrigineFenetre(imS,x1,y1);
        EcritOrigineFenetre(imD,x1,y1);
        AbsR(imS,imD);
		  EcritOrigineFenetre(imS,x0,y1);
        EcritOrigineFenetre(imD,x0,y1);
        AbsR(imS,imD);

        EcritTailleFenetre(imDb,x2,y2);
        EcritOrigineFenetre(imDb,x1,y1);
        AddR(imDb,imD,imDb);
        EcritOrigineFenetre(imD,x1,y0);
        AddR(imDb,imD,imDb);
        }
	 }

EcritOrigineFenetre(imS,x0,y0);
EcritTailleFenetre(imS,x,y);
EcritOrigineFenetre(imD,x0,y0);
EcritTailleFenetre(imD,x,y);
free(imDb);
return(imD);
}



// Transformée en ondelettes continue

Image TFOndelMorletC(Image imS, Image imD, Reel echelle, Reel angle, Reel w0, Reel excent)
/***************************************************************************************/

{
int i,j,x,y;
Complexe **grille;
ReelL w,cosO,sinO,cosE,sinE,xx,yy,xs2,ys2,xc,yc,norme,nb,moy;

if ((echelle==0)||(excent==0)) return(NULL);
if (imS==NULL) return(NULL);
LitTailleFenetre(imS,&x,&y);
if ((x!=y)&&(y>1)) return(NULL);
if ((imD=CreeImageDest(imS,imD,T_COMPLEXE))==NULL) return(NULL);
if ((grille=(Complexe **)CreeGrille(imD,Z_FENETRE))==NULL) return(NULL);

angle=angle*M_PI/180;
cosO=echelle*cos(angle);
sinO=echelle*sin(angle);
cosE=cosO*excent;
sinE=sinO*excent;
xs2=(double)x/2;
if (y>1)
	{
	ys2=(double)y/2;
	norme=2*sqrt(M_PI)*echelle*sqrt(excent);
	 }
else
	{
	ys2=0;
	norme=2*sqrt(M_PI)*sqrt(echelle)*sqrt(excent);
	 }
w=2*M_PI/x;

for (i=0;i<y;i++)
	for(j=0;j<x;j++)
		{
		xc=w*(j-xs2);
		yc=w*(i-ys2);
		xx=cosE*xc+sinE*yc-w0;
		yy=cosO*yc-sinO*xc;
		grille[i][j].x=(Reel)(exp(-(xx*xx+yy*yy)/2)*norme);
		grille[i][j].y=0;
		}

nb=(ReelL)x*y;
moy=grille[y/2][x/2].x/nb;
grille[y/2][x/2].x=0;
norme=1/sqrt(1-(2*nb-1)*moy*moy);
for (i=0;i<y;i++)
	for(j=0;j<x;j++)
		grille[i][j].x=(Reel) (grille[i][j].x*norme);

LibereGrille(grille);
return(imD);
}



Image TFOndelMorletIsoC(Image imS, Image imD, Reel echelle, Reel w0)
/******************************************************************/

{
int i,j,x,y;
Complexe **grille;
ReelL w,xs2,ys2,xc,yc,phase;

if (echelle==0) return(NULL);
if (imS==NULL) return(NULL);
LitTailleFenetre(imS,&x,&y);
if ((x!=y)&&(y>1)) return(NULL);
if ((imD=CreeImageDest(imS,imD,T_COMPLEXE))==NULL) return(NULL);
if ((grille=(Complexe **)CreeGrille(imD,Z_FENETRE))==NULL) return(NULL);

xs2=(double)x/2;
if (y>1) ys2=(double)y/2;
else ys2=0;
w=echelle*2*M_PI/x;
w0=fabs(w0);

for (i=0;i<y;i++)
	for(j=0;j<x;j++)
		{
		xc=w*(j-xs2);
		yc=w*(i-ys2);
		phase=sqrt(xc*xc+yc*yc)-w0;
		grille[i][j].x=(Reel) (echelle*exp(-(phase*phase)/2));
		grille[i][j].y=0;
		}

grille[y/2][x/2].x=0;
LibereGrille(grille);
return(imD);
}


Image TFOndelGaussDeriveC(Image imS, Image imD, Reel echelle, Reel angle)
/***********************************************************************/
{
int i,j,x,y;
Complexe **grille;
ReelL w,cosO,sinO,xx,xs2,ys2,xc,yc;

if (echelle==0) return(NULL);
if (imS==NULL) return(NULL);
LitTailleFenetre(imS,&x,&y);
if ((x!=y)&&(y>1)) return(NULL);
if ((imD=CreeImageDest(imS,imD,T_COMPLEXE))==NULL) return(NULL);
if ((grille=(Complexe **)CreeGrille(imD,Z_FENETRE))==NULL) return(NULL);

angle=angle*M_PI/180;
cosO=cos(angle);
sinO=sin(angle);
xs2=(double)x/2;
if (y>1) ys2=(double)y/2;
else ys2=0;
w=echelle*2*M_PI/x;

for (i=0;i<y;i++)
	for(j=0;j<x;j++)
		{
		xc=w*(j-xs2);
		yc=w*(i-ys2);
		xx=cosO*xc+sinO*yc;
		grille[i][j].x=0;
		grille[i][j].y=(Reel) (xx*exp(-(xc*xc+yc*yc)/2));
		}

LibereGrille(grille);
return(imD);
}

Image TFOndelGradC(Image imS, Image imD, Reel echelle, Reel angle)
/*******************************************************************/

{
int i,j,x,y;
Complexe **grille;
ReelL w,cosO,sinO,xx,yy,xs2,ys2,xc,yc,u;

if (echelle==0) return(NULL);
if (imS==NULL) return(NULL);
LitTailleFenetre(imS,&x,&y);
if ((x!=y)&&(y>1)) return(NULL);
if ((imD=CreeImageDest(imS,imD,T_COMPLEXE))==NULL) return(NULL);
if ((grille=(Complexe **)CreeGrille(imD,Z_FENETRE))==NULL) return(NULL);

angle=angle*M_PI/180;
cosO=cos(angle);
sinO=sin(angle);
xs2=(double)x/2;
if (y>1) ys2=(double)y/2;
else ys2=0;
w=echelle*2*M_PI/x;

for (i=0;i<y;i++)
	for(j=0;j<x;j++)
		{
		xc=w*(j-xs2);
		yc=w*(i-ys2);
		xx=cosO*xc+sinO*yc;
		yy=-sinO*xc+cosO*yc;
		u=(xc*xc+yc*yc)/2;
		grille[i][j].x=-(Reel)(yy*exp(-u));
		grille[i][j].y=(Reel) (xx*exp(-u));
		}

LibereGrille(grille);
return(imD);
}


Image TFOndelChapeauMexicC(Image imS, Image imD, Reel echelle, int nSur2)
/***********************************************************************/
{
int i,j,x,y,sgn;
Complexe **grille;
ReelL w,xs2,ys2,xc,yc,norme;

if (echelle==0) return(NULL);
if (imS==NULL) return(NULL);
LitTailleFenetre(imS,&x,&y);
if ((x!=y)&&(y>1)) return(NULL);
if ((imD=CreeImageDest(imS,imD,T_COMPLEXE))==NULL) return(NULL);
if ((grille=(Complexe **)CreeGrille(imD,Z_FENETRE))==NULL) return(NULL);

xs2=(double)x/2;
if (y>1) ys2=(double)y/2;
else ys2=0;
w=echelle*2*M_PI/x;
sgn=(nSur2%2)?-1:1;
norme=2*nSur2*sgn;

for (i=0;i<y;i++)
	for(j=0;j<x;j++)
		{
		xc=w*(j-xs2);
		yc=w*(i-ys2);
		grille[i][j].x=(Reel) (norme*pow(xc*xc+yc*yc,nSur2)*exp(-(xc*xc+yc*yc)/2));
		grille[i][j].y=0;
		}

LibereGrille(grille);
return(imD);
}


static int ondelContinueC(Image imS, Image imOnd)
/***********************************************/

{
if (MultC(imS,imOnd,imOnd)==NULL) return (1);
if (TFRInverseC(imOnd,imOnd)==NULL) return (1);
return (0);
}


Image OndelContMorletC(Image imS,Image imD,Reel echelle,Reel angle,Reel w0, Reel excent)
/******************************************************************************************/
{
Image imT=NULL;
if (imS==imD)
  {
  imT=TransfereC(imS,NULL);
  imS=imT;
  }
if ((imD=TFOndelMorletC(imS,imD,echelle,angle,w0,excent))==NULL) return (NULL);
ondelContinueC(imS,imD);
LibereImage(imT);
return(imD);
}


Image OndelContMorletIsoC(Image imS, Image imD, Reel echelle,	Reel w0)
/*********************************************************************/
{
Image imT=NULL;
if (imS==imD)
  {
  imT=TransfereC(imS,NULL);
  imS=imT;
  }
if ((imD=TFOndelMorletIsoC(imS,imD,echelle,w0))==NULL) return (NULL);
ondelContinueC(imS,imD);
LibereImage(imT);
return(imD);
}

Image OndelContGaussDeriveC(Image imS, Image imD, Reel echelle,Reel angle)
/************************************************************************/
{
Image imT=NULL;
if (imS==imD)
  {
  imT=TransfereC(imS,NULL);
  imS=imT;
  }
if ((imD=TFOndelGaussDeriveC (imS,imD,echelle,angle))==NULL) return (NULL);
ondelContinueC(imS,imD);
LibereImage(imT);
return(imD);
}

Image OndelContGradC(Image imS, Image imD, Reel echelle,Reel angle)
/*****************************************************************/
{
Image imT=NULL;
if (imS==imD)
  {
  imT=TransfereC(imS,NULL);
  imS=imT;
  }
if ((imD=TFOndelGradC (imS,imD,echelle,angle))==NULL) return (NULL);
ondelContinueC(imS,imD);
LibereImage(imT);
return(imD);
}


Image OndelContChapeauMexicC(Image imS, Image imD, Reel echelle,int nSur2)
/************************************************************************/
{
Image imT=NULL;
if (imS==imD)
  {
  imT=TransfereC(imS,NULL);
  imS=imT;
  }
if ((imD=TFOndelChapeauMexicC(imS,imD,echelle,nSur2))==NULL) return (NULL);
ondelContinueC(imS,imD);
LibereImage(imT);
return(imD);
}
