/* ---------------------------------------------------------------------------- Filename: pyramidtools.h Author: Daniel Sage Swiss Federal Institute of Technology - Lausanne Biomedical Imaging Group EPFL/DMT/IOA, BM-Ecublens, CH-1015 Lausanne, Switzerland Date: 17 March 1999 Purpose: Basic functions reduce and expand by factors of 2 in 1D signal or in 2D signal. Includes the standard pyramid and the centered pyramid. References: [1] M. Unser, "Splines: a perfect fit for signal and image processing," IEEE Signal Processing Magazine, 1999. [2] M. Unser, A. Aldroubi and M. Eden, "B-spline signal processing: Part II‹efficient design and applications," IEEE Trans. Signal Processing, vol. 41, no. 2, pp. 834-848, February 1993. [3] M. Unser, A. Aldroubi and M. Eden, "The L2 polynomial spline pyramid," IEEE Trans. Pattern Anal. Mach. Intell., vol. 15, no. 4, pp. 364-379, April 1993. [4] P. Brigger, F. Müller, K. Illgner and M. Unser, "Centered pyramids," IEEE Trans. Image Processing, vol. 6, no. 9, pp. 1254-1264, September 1999. [5] P.J. Burt and E.H. Adelson, "The Laplacian pyramid as a compact code," IEEE Trans. Commun., vol. COM-31, no. 4, pp. 337-345, April 1983. ---------------------------------------------------------------------------- */ /* --- System includes --- */ #include #include #include #include /* --- Private includes --- */ #include "configs.h" #include "messagedisplay.h" #include "pyramidtools.h" #include "pyramidfilters.h" /* ------------------------------------------------------------------------- */ /* Declaration of static procedures */ /* ------------------------------------------------------------------------- */ static void ExpandStandard_1D( double In[], long NxIn, double Out[], double w[], long nw ); static void ReduceStandard_1D( double In[], long NxIn, double Out[], double w[], long nw ); static void ExpandCentered_1D( double In[], long NxIn, double Out[], double w[], long nw ); static void ReduceCentered_1D( double In[], long NxIn, double Out[], double w[], long nw ); static void GetRow( float *Image, long Nx, long Ny, long RowNb, double *Row, long RowSize ); static void GetColumn( float *Image, long Nx, long Ny, long ColumnNb, double *Column, long ColumnSize ); static void PutRow( float *Image, long Nx, long Ny, long RowNb, double *Row, long RowSize ); static void PutColumn( float *Image, long Nx, long Ny, long ColumnNb, double *Column, long ColumnSize ); /* ---------------------------------------------------------------------------- Function: GetPyramidFilter Purpose: Get the coefficients of the filter (reduce and expand filter) Return the coefficients in g[ng] and in h[nh] Convention: g[ng] for the reduce filter h[nh] for the expansion filter Parameters: Filter is the name of the filter Order is the order for the filters based on splines For the "Spline" filter, Order is 0, 1, 2 or 3 For the "Spline L2" filter, Order is 0, 1, 3 or 5 For the "Centered Spline" filter, Order is 0, 1, 2, 3 or 4 For the "Centered Spline L2" filter, Order is 0, 1, 2, 3 or 4 IsCentered is a return value indicates if the filter is a centered filter TRUE if it is a centered filter FALSE if it is not a centered filter ---------------------------------------------------------------------------- */ extern int GetPyramidFilter( char *Filter, long Order, double g[], long *ng, double h[], long *nh, short *IsCentered) { ng[0] = -1L; nh[0] = -1L; *IsCentered = FALSE; if ( !strcmp(Filter, "Spline")) { PyramidFilterSplinel2(g, ng, h, nh, Order); *IsCentered = FALSE; } if ( !strcmp(Filter, "Spline L2")) { PyramidFilterSplineL2(g, ng, h, nh, Order); *IsCentered = FALSE; } if ( !strcmp(Filter, "Centered Spline")) { PyramidFilterCentered(g, ng, h, nh, Order); *IsCentered = TRUE; } if ( !strcmp(Filter, "Centered Spline L2")) { PyramidFilterCenteredL2(g, ng, h, nh, Order); *IsCentered = TRUE; } if ( ng[0] == -1L && nh[0] == -1L) { MessageDisplay( "This familly filters is unknown"); return(ERROR); } return( !ERROR); } /* ---------------------------------------------------------------------------- Function: Reduce_2D Purpose: Reduces an image by a factor of two in each dimension. Note: Expects the output array (Out) to be allocated. Parameters: Input image: In[NxIn*NyIn] Output image: Out[NxIn/2*NyIn/2] Filter: g[ng] coefficients of the filter ---------------------------------------------------------------------------- */ extern int Reduce_2D( float *In, long NxIn, long NyIn, float *Out, double g[], long ng, short IsCentered ) { float *Tmp; double *InBuffer; /* Input buffer to 1D process */ double *OutBuffer; /* Output buffer to 1D process */ long kx, ky; long NxOut; long NyOut; /* --- Define dimension of the output --- */ NxOut = NxIn/2L; if (NxOut < 1L) NxOut = 1L; NyOut = NyIn/2L; if (NyOut < 1L) NyOut = 1L; /* --- Allocate a temporary image --- */ Tmp = (float *)malloc((size_t)(NxOut*NyIn*(long)sizeof(float))); if (Tmp == (float *)NULL) { MessageDisplay("Unable to allocate memory"); return(ERROR); } /* --- X processing --- */ if (NxIn > 1L) { InBuffer = (double *)malloc((size_t)(NxIn*(long)sizeof(double))); if (InBuffer == (double *)NULL) { free(Tmp); MessageDisplay("Unable to allocate memory"); return(ERROR); } OutBuffer = (double *)malloc((size_t)(NxOut*(long)sizeof(double))); if (OutBuffer == (double *)NULL) { free(Tmp); free(InBuffer); MessageDisplay("Unable to allocate memory"); return(ERROR); } for (ky=0L; ky 1L) { InBuffer = (double *)malloc((size_t)(NyIn*(long)sizeof(double))); if (InBuffer == (double *)NULL) { MessageDisplay("Unable to allocate memory"); return(ERROR); } OutBuffer = (double *)malloc((size_t)(NyOut*(long)sizeof(double))); if (OutBuffer == (double *)NULL) { free(InBuffer); MessageDisplay("Unable to allocate memory"); return(ERROR); } for (kx=0L; kx 1L) { InBuffer = (double *)malloc((size_t)(NxIn*(long)sizeof(double))); if (InBuffer == (double *)NULL) { MessageDisplay("Unable to allocate memory"); return(ERROR); } OutBuffer = (double *)malloc((size_t)(NxOut*(long)sizeof(double))); if (OutBuffer == (double *)NULL) { free(InBuffer); MessageDisplay("Unable to allocate memory"); return(ERROR); } for (ky=0L; ky 1L) { InBuffer = (double *)malloc((size_t)(NyIn*(long)sizeof(double))); if (InBuffer == (double *)NULL) { MessageDisplay("Unable to allocate memory"); return(ERROR); } OutBuffer = (double *)malloc((size_t)(NyOut*(long)sizeof(double))); if (OutBuffer == (double *)NULL) { free(InBuffer); MessageDisplay("Unable to allocate memory"); return(ERROR); } for (kx=0L; kx n-1L) i2 = kn-i2; Out[kk] = (In[k]+In[i2])/2.; } } else { for (kk=0L; kk n-1) i1=kn-i1; } if (i2 > n-1L) { i2 = i2 % kn; if (i2 > n-1L) i2=kn-i2; } Out[kk] = Out[kk] + g[i]*(In[i1]+In[i2]); } } } } /* ---------------------------------------------------------------------------- Function: ExpandStandard_1D Purpose: Basic function to expand a 1D signal Parameters: In[NxIn] is the input signal (NxIn should be greater than 1) Out[NxIn*2] is the output signal w[nw] is an array that contains the coefficients of the filter Author: Michael Unser, NIH, BEIP, June 1994 Daniel Sage, EPFL, Biomedical Imaging Group, April 1999 ---------------------------------------------------------------------------- */ static void ExpandStandard_1D( double In[], long NxIn, double Out[], double h[], long nh) { long k, j, i, i1, i2; long kn, nexp, n; nexp = NxIn*2L; n = NxIn; kn = n-1; if (nh < 2L) { for (i=0L; i kn) i1=kn-i1; } Out[i] = Out[i] + h[k]*In[i1]; } for (k=2L-(i % 2L); k kn) { i2 = i2 % kn; i2 = kn-i2; if (i2 > kn) i2 = kn-i2; } Out[i] = Out[i] + h[k]*In[i2]; } } } } /* ---------------------------------------------------------------------------- Function: ReduceCentered_1D Purpose: Reduces an image by a factor of two The reduced image grid is between the finer grid Parameters: In[NxIn] is the input signal (NxIn should be greater than 2 and even) Out[NxIn/2] is the output signal g[ng] is an array that contains the coefficients of the filter Author: Michael Unser, NIH, BEIP, June 1994 Patrick Brigger, NIH, BEIP, May 1996, modified Daniel Sage, EPFL, Biomedical Imaging Group, April 1999 ---------------------------------------------------------------------------- */ extern void ReduceCentered_1D( double In[], long NxIn, double Out[], double g[], long ng) { double *y_tmp; long k, i, i1, i2; long kk, kn, nred, n; nred = NxIn/2L; n = nred*2L; kn = 2L*n; /* --- Allocated memory for a temporary buffer --- */ y_tmp = (double *)malloc( (size_t)(n*(long)sizeof(double))); if ( y_tmp == (double *)NULL) { MessageDisplay("Out of memory in reduce_centered!"); return; } /* --- Apply the symmetric filter to all the coefficients --- */ for (k=0L; k= n) i1 = kn-i1-1L; } if (i2 > (n-1L)) { i2 = i2 % kn; if (i2 >= n) i2 = kn-i2-1L; } y_tmp[k] = y_tmp[k] + g[i]*(In[i1]+In[i2]); } } /* --- Now apply the Haar and perform downsampling --- */ for(kk=0L; kk pseudo mirror image */ if (i1 >= n) i1=kn-i1-1L; } if (i2 >= n) { i2= (i2) % kn; if (i2 >= n) i2=kn-i2-1L; } Out[j] = Out[j] + h[k]*(In[i1]+In[i2]); } Out[j+1] = 0.; for (k=-k0; k n-1) i1 = kn-i1-1L; } if (i1 >= n) { i1 = (i1) % kn; if (i1 >= n) i1=kn-i1-1; } Out[j+1L] = Out[j+1L] + h[kk]*In[i1]; } } /* Now apply the Haar[-x] and */ for (j=nexp-1L; j>0L; j--) Out[j] = (Out[j] + Out[j-1])/2.0; Out[0] /= 2.0; } /* ---------------------------------------------------------------------------- Function: GetRow Purpose: Get a row from an image Parameters: Image[Nx*Ny] is the input image RowNb is the number of the row Row[RowSize] is the output signal ---------------------------------------------------------------------------- */ static void GetRow( float *Image, long Nx, long Ny, long RowNb, double *Row, long RowSize ) { int i; int BaseIndex; (void) Ny; BaseIndex = RowNb*Nx; for (i=0L; i