Linear Methods for Image Interpolation
lprefilt.c
Go to the documentation of this file.
00001 
00021 #include <stdlib.h>
00022 #include <math.h>
00023 #include <fftw3.h>
00024 #include "adaptlob.h"
00025 #include "lprefilt.h"
00026 
00027 
00048 static void PrefilterScan(float *Data, int Stride, int N, float alpha,
00049     boundaryhandling Boundary)
00050 {
00051     const float Eps = 1e-4;
00052     float Sum, Weight, Last;
00053     int i, iEnd, n0;
00054 
00055     n0 = (int)ceil(log(Eps)/log(fabs(alpha)));
00056 
00057     if(n0 > N)
00058         n0 = N;
00059 
00060     switch(Boundary)
00061     {
00062         case BOUNDARY_CONSTANT:
00063             Sum = Data[0]/(1 - alpha);
00064             break;
00065         case BOUNDARY_WSYMMETRIC:
00066             Sum = Data[0];
00067             Weight = 1;
00068             iEnd = n0*Stride;
00069 
00070             for(i = Stride; i < iEnd; i += Stride)
00071             {
00072                 Weight *= alpha;
00073                 Sum += Data[i]*Weight;
00074             }
00075             break;
00076         default: /* BOUNDARY_HSYMMETRIC */
00077             Sum = Data[0]*(1 + alpha);
00078             Weight = alpha;
00079             iEnd = n0*Stride;
00080 
00081             for(i = Stride; i < iEnd; i += Stride)
00082             {
00083                 Weight *= alpha;
00084                 Sum += Data[i]*Weight;
00085             }
00086             break;
00087     }
00088 
00089     Last = Data[0] = Sum;
00090     iEnd = (N - 1)*Stride;
00091 
00092     for(i = Stride; i < iEnd; i += Stride)
00093     {
00094         Data[i] += alpha*Last;
00095         Last = Data[i];
00096     }
00097 
00098     switch(Boundary)
00099     {
00100         case BOUNDARY_CONSTANT:
00101             Last = Data[iEnd] = (alpha*(-Data[iEnd] + (alpha - 1)*alpha*Last))
00102                 /((alpha - 1)*(alpha*alpha - 1));
00103             break;
00104         case BOUNDARY_HSYMMETRIC:
00105             Data[iEnd] += alpha*Last;
00106             Last = Data[iEnd] *= alpha/(alpha - 1);
00107             break;
00108         case BOUNDARY_WSYMMETRIC:
00109             Data[iEnd] += alpha*Last;
00110             Last = Data[iEnd] = (alpha/(alpha*alpha - 1))
00111                 * ( Data[iEnd] + alpha*Data[iEnd - Stride] );
00112             break;
00113     }
00114 
00115     for(i = iEnd - Stride; i >= 0; i -= Stride)
00116     {
00117         Data[i] = alpha*(Last - Data[i]);
00118         Last = Data[i];
00119     }
00120 }
00121 
00122 
00132 void PrefilterImage(float *Data, int Width, int Height, int NumChannels,
00133     const float *alpha, int NumFilterPairs, float ConstantFactor,
00134     boundaryhandling Boundary)
00135 {
00136     const int NumPixels = Width*Height;
00137     int k, x, y, Channel;
00138 
00139 
00140     /* Square the ConstantFactor for two spatial dimensions */
00141     ConstantFactor = ConstantFactor*ConstantFactor;
00142 
00143     for(Channel = 0; Channel < NumChannels; Channel++)
00144     {
00145         for(x = 0; x < Width; x++)
00146             for(k = 0; k < NumFilterPairs; k++)
00147                 PrefilterScan(Data + x, Width, Height, alpha[k], Boundary);
00148 
00149         for(y = 0; y < Height; y++)
00150             for(k = 0; k < NumFilterPairs; k++)
00151                 PrefilterScan(Data + Width*y, 1, Width, alpha[k], Boundary);
00152 
00153         for(k = 0; k < NumPixels; k++)
00154             Data[k] *= ConstantFactor;
00155 
00156         Data += NumPixels;
00157     }
00158 }
00159 
00160 
00161 typedef struct {
00162     float (*Kernel)(float);
00163     float KernelRadius;
00164     float (*Psf)(float, const void*);
00165     const void *PsfParams;
00166     float x;
00167 } convolutionparams;
00168 
00169 
00170 static float ConvIntegrand(float t, const void *Params)
00171 {
00172     float (*Kernel)(float) = ((convolutionparams*)Params)->Kernel;
00173     float (*Psf)(float, const void*) = ((convolutionparams*)Params)->Psf;
00174     const void *PsfParams = ((convolutionparams*)Params)->PsfParams;
00175     float x = ((convolutionparams*)Params)->x;
00176 
00177     return Kernel(t) * Psf(x - t, PsfParams);
00178 }
00179 
00180 
00181 static float ConvIntegrandNormalized(float t, const void *Params)
00182 {
00183     float (*Kernel)(float) = ((convolutionparams*)Params)->Kernel;
00184     const int R = 2*ceil(((convolutionparams*)Params)->KernelRadius);
00185     float (*Psf)(float, const void*) = ((convolutionparams*)Params)->Psf;
00186     const void *PsfParams = ((convolutionparams*)Params)->PsfParams;
00187     float Sum, x = ((convolutionparams*)Params)->x;
00188     int r;
00189 
00190     for(r = -R, Sum = 0; r <= R; r++)
00191         Sum += Kernel(t - r);
00192 
00193     return (Kernel(t)/Sum) * Psf(x - t, PsfParams);
00194 }
00195 
00196 
00214 void PsfConvCoeff(float *Coeff, int NumCoeffs,
00215     float (*Psf)(float, const void*), const void *PsfParams,
00216     float (*Kernel)(float), float KernelRadius, int KernelNormalize)
00217 {
00218     float (*ConvFun)(float, const void*) = ConvIntegrand;
00219     convolutionparams ConvParams;
00220     int m;
00221 
00222     ConvParams.Kernel = Kernel;
00223     ConvParams.KernelRadius = KernelRadius;
00224     ConvParams.Psf = Psf;
00225     ConvParams.PsfParams = PsfParams;
00226 
00227     if(KernelNormalize)
00228         ConvFun = ConvIntegrandNormalized;
00229 
00230     for(m = 0; m < NumCoeffs; m++)
00231     {
00232         ConvParams.x = m;
00233         Coeff[m] = AdaptLob(ConvFun, -KernelRadius, KernelRadius,
00234             1e-7f, (const void *)&ConvParams);
00235     }
00236 }
00237 
00238 
00266 static int PsfPreFilterScan(float *Data, int Stride, int ScanSize,
00267     int ScanStride, int NumScans, int ChannelStride, int NumChannels,
00268     const float *Coeff, int NumCoeffs, boundaryhandling Boundary)
00269 {
00270     const int PadCoeff = ScanSize + ((Boundary == BOUNDARY_HSYMMETRIC) ? 1:0);
00271     float *Buf = NULL, *CoeffDct = NULL;
00272     fftwf_plan Plan = 0;
00273     fftwf_iodim Dims[1], HowManyDims[2];
00274     fftw_r2r_kind Kind[1];
00275     int i, Scan, Channel, Success = 0;
00276 
00277 
00278     if((Boundary != BOUNDARY_HSYMMETRIC && Boundary != BOUNDARY_WSYMMETRIC)
00279         || !(Buf = (float *)fftwf_malloc(sizeof(float)*ScanSize*NumScans*NumChannels))
00280         || !(CoeffDct = (float *)fftwf_malloc(sizeof(float)*PadCoeff)))
00281         goto Catch;
00282 
00283     for(i = 0; i < NumCoeffs && i < PadCoeff; i++)
00284         Buf[i] = Coeff[i];
00285     for(; i < PadCoeff; i++)
00286         Buf[i] = 0;
00287 
00288     /* Perform DCT-I */
00289     if(!(Plan = fftwf_plan_r2r_1d(PadCoeff, Buf, CoeffDct,
00290         FFTW_REDFT00, FFTW_ESTIMATE | FFTW_DESTROY_INPUT)))
00291         goto Catch;
00292 
00293     fftwf_execute(Plan);
00294     fftwf_destroy_plan(Plan);
00295 
00296     /* Incorporate the normalization scale factor into the coefficients */
00297     for(i = 0; i < ScanSize; i++)
00298         CoeffDct[i] *= 2*(PadCoeff - 1);
00299 
00300     /* Forward transform of the image data */
00301     Dims[0].n = ScanSize;
00302     Dims[0].is = Stride;
00303     Dims[0].os = 1;
00304     HowManyDims[0].n = NumChannels;
00305     HowManyDims[0].is = ChannelStride;
00306     HowManyDims[0].os = ScanSize*NumScans;
00307     HowManyDims[1].n = NumScans;
00308     HowManyDims[1].is = ScanStride;
00309     HowManyDims[1].os = ScanSize;
00310 
00311     /* Use DCT-II for half-sample symmetric boundaries,
00312     DCT-I for whole-sample symmetric. */
00313     Kind[0] = (Boundary == BOUNDARY_HSYMMETRIC) ? FFTW_REDFT10 : FFTW_REDFT00;
00314 
00315     if(!(Plan = fftwf_plan_guru_r2r(1, Dims, 2, HowManyDims, Data,
00316         Buf, Kind, FFTW_ESTIMATE | FFTW_DESTROY_INPUT)))
00317         goto Catch;
00318 
00319     fftwf_execute(Plan);
00320     fftwf_destroy_plan(Plan);
00321 
00322     /* Divide */
00323     for(Channel = 0; Channel < NumChannels; Channel++)
00324     {
00325         for(Scan = 0; Scan < NumScans; Scan++)
00326         {
00327             for(i = 0; i < ScanSize; i++)
00328                 Buf[i + ScanSize*(Scan + NumScans*Channel)] /= CoeffDct[i];
00329         }
00330     }
00331 
00332     /* Perform inverse transform */
00333     Dims[0].n = ScanSize;
00334     Dims[0].is = 1;
00335     Dims[0].os = Stride;
00336     HowManyDims[0].n = NumChannels;
00337     HowManyDims[0].is = ScanSize*NumScans;
00338     HowManyDims[0].os = ChannelStride;
00339     HowManyDims[1].n = NumScans;
00340     HowManyDims[1].is = ScanSize;
00341     HowManyDims[1].os = ScanStride;
00342 
00343     /* Use DCT-III (inverse of DCT-II) for half-sample symmetric boundaries,
00344     DCT-I (inverse of DCT-I) for whole-sample symmetric. */
00345     Kind[0] = (Boundary == BOUNDARY_HSYMMETRIC) ? FFTW_REDFT01 : FFTW_REDFT00;
00346 
00347     if(!(Plan = fftwf_plan_guru_r2r(1, Dims, 2, HowManyDims, Buf,
00348         Data, Kind, FFTW_ESTIMATE | FFTW_DESTROY_INPUT)))
00349         goto Catch;
00350 
00351     fftwf_execute(Plan);
00352     fftwf_destroy_plan(Plan);
00353     Success = 1;
00354 Catch:
00355     if(CoeffDct)
00356         fftwf_free(CoeffDct);
00357     if(Buf)
00358         fftwf_free(Buf);
00359     fftwf_cleanup();
00360     return Success;
00361 }
00362 
00363 
00380 int PsfPreFilter(float *Data, int Width, int Height, int NumChannels,
00381     const float *Coeff, int NumCoeffs, boundaryhandling Boundary)
00382 {
00383     if(!Data || !Coeff)
00384         return 0;
00385 
00386     if(!PsfPreFilterScan(Data, Width, Height, 1, Width, Width*Height,
00387             NumChannels, Coeff, NumCoeffs, Boundary))
00388         return 0;
00389 
00390     if(!PsfPreFilterScan(Data, 1, Width, Width, Height, Width*Height,
00391             NumChannels, Coeff, NumCoeffs, Boundary))
00392         return 0;
00393 
00394     return 1;
00395 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines