Linear Methods for Image Interpolation
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
lprefilt.c
Go to the documentation of this file.
1 
21 #include <stdlib.h>
22 #include <math.h>
23 #include <fftw3.h>
24 #include "adaptlob.h"
25 #include "lprefilt.h"
26 
27 
48 static void PrefilterScan(float *Data, int Stride, int N, float alpha,
49  boundaryhandling Boundary)
50 {
51  const float Eps = 1e-4;
52  float Sum, Weight, Last;
53  int i, iEnd, n0;
54 
55  n0 = (int)ceil(log(Eps)/log(fabs(alpha)));
56 
57  if(n0 > N)
58  n0 = N;
59 
60  switch(Boundary)
61  {
62  case BOUNDARY_CONSTANT:
63  Sum = Data[0]/(1 - alpha);
64  break;
66  Sum = Data[0];
67  Weight = 1;
68  iEnd = n0*Stride;
69 
70  for(i = Stride; i < iEnd; i += Stride)
71  {
72  Weight *= alpha;
73  Sum += Data[i]*Weight;
74  }
75  break;
76  default: /* BOUNDARY_HSYMMETRIC */
77  Sum = Data[0]*(1 + alpha);
78  Weight = alpha;
79  iEnd = n0*Stride;
80 
81  for(i = Stride; i < iEnd; i += Stride)
82  {
83  Weight *= alpha;
84  Sum += Data[i]*Weight;
85  }
86  break;
87  }
88 
89  Last = Data[0] = Sum;
90  iEnd = (N - 1)*Stride;
91 
92  for(i = Stride; i < iEnd; i += Stride)
93  {
94  Data[i] += alpha*Last;
95  Last = Data[i];
96  }
97 
98  switch(Boundary)
99  {
100  case BOUNDARY_CONSTANT:
101  Last = Data[iEnd] = (alpha*(-Data[iEnd] + (alpha - 1)*alpha*Last))
102  /((alpha - 1)*(alpha*alpha - 1));
103  break;
104  case BOUNDARY_HSYMMETRIC:
105  Data[iEnd] += alpha*Last;
106  Last = Data[iEnd] *= alpha/(alpha - 1);
107  break;
108  case BOUNDARY_WSYMMETRIC:
109  Data[iEnd] += alpha*Last;
110  Last = Data[iEnd] = (alpha/(alpha*alpha - 1))
111  * ( Data[iEnd] + alpha*Data[iEnd - Stride] );
112  break;
113  }
114 
115  for(i = iEnd - Stride; i >= 0; i -= Stride)
116  {
117  Data[i] = alpha*(Last - Data[i]);
118  Last = Data[i];
119  }
120 }
121 
122 
132 void PrefilterImage(float *Data, int Width, int Height, int NumChannels,
133  const float *alpha, int NumFilterPairs, float ConstantFactor,
134  boundaryhandling Boundary)
135 {
136  const int NumPixels = Width*Height;
137  int k, x, y, Channel;
138 
139 
140  /* Square the ConstantFactor for two spatial dimensions */
141  ConstantFactor = ConstantFactor*ConstantFactor;
142 
143  for(Channel = 0; Channel < NumChannels; Channel++)
144  {
145  for(x = 0; x < Width; x++)
146  for(k = 0; k < NumFilterPairs; k++)
147  PrefilterScan(Data + x, Width, Height, alpha[k], Boundary);
148 
149  for(y = 0; y < Height; y++)
150  for(k = 0; k < NumFilterPairs; k++)
151  PrefilterScan(Data + Width*y, 1, Width, alpha[k], Boundary);
152 
153  for(k = 0; k < NumPixels; k++)
154  Data[k] *= ConstantFactor;
155 
156  Data += NumPixels;
157  }
158 }
159 
160 
161 typedef struct {
162  float (*Kernel)(float);
164  float (*Psf)(float, const void*);
165  const void *PsfParams;
166  float x;
168 
169 
170 static float ConvIntegrand(float t, const void *Params)
171 {
172  float (*Kernel)(float) = ((convolutionparams*)Params)->Kernel;
173  float (*Psf)(float, const void*) = ((convolutionparams*)Params)->Psf;
174  const void *PsfParams = ((convolutionparams*)Params)->PsfParams;
175  float x = ((convolutionparams*)Params)->x;
176 
177  return Kernel(t) * Psf(x - t, PsfParams);
178 }
179 
180 
181 static float ConvIntegrandNormalized(float t, const void *Params)
182 {
183  float (*Kernel)(float) = ((convolutionparams*)Params)->Kernel;
184  const int R = 2*ceil(((convolutionparams*)Params)->KernelRadius);
185  float (*Psf)(float, const void*) = ((convolutionparams*)Params)->Psf;
186  const void *PsfParams = ((convolutionparams*)Params)->PsfParams;
187  float Sum, x = ((convolutionparams*)Params)->x;
188  int r;
189 
190  for(r = -R, Sum = 0; r <= R; r++)
191  Sum += Kernel(t - r);
192 
193  return (Kernel(t)/Sum) * Psf(x - t, PsfParams);
194 }
195 
196 
214 void PsfConvCoeff(float *Coeff, int NumCoeffs,
215  float (*Psf)(float, const void*), const void *PsfParams,
216  float (*Kernel)(float), float KernelRadius, int KernelNormalize)
217 {
218  float (*ConvFun)(float, const void*) = ConvIntegrand;
219  convolutionparams ConvParams;
220  int m;
221 
222  ConvParams.Kernel = Kernel;
223  ConvParams.KernelRadius = KernelRadius;
224  ConvParams.Psf = Psf;
225  ConvParams.PsfParams = PsfParams;
226 
227  if(KernelNormalize)
228  ConvFun = ConvIntegrandNormalized;
229 
230  for(m = 0; m < NumCoeffs; m++)
231  {
232  ConvParams.x = m;
233  Coeff[m] = AdaptLob(ConvFun, -KernelRadius, KernelRadius,
234  1e-7f, (const void *)&ConvParams);
235  }
236 }
237 
238 
266 static int PsfPreFilterScan(float *Data, int Stride, int ScanSize,
267  int ScanStride, int NumScans, int ChannelStride, int NumChannels,
268  const float *Coeff, int NumCoeffs, boundaryhandling Boundary)
269 {
270  const int PadCoeff = ScanSize + ((Boundary == BOUNDARY_HSYMMETRIC) ? 1:0);
271  float *Buf = NULL, *CoeffDct = NULL;
272  fftwf_plan Plan = 0;
273  fftwf_iodim Dims[1], HowManyDims[2];
274  fftw_r2r_kind Kind[1];
275  int i, Scan, Channel, Success = 0;
276 
277 
278  if((Boundary != BOUNDARY_HSYMMETRIC && Boundary != BOUNDARY_WSYMMETRIC)
279  || !(Buf = (float *)fftwf_malloc(sizeof(float)*ScanSize*NumScans*NumChannels))
280  || !(CoeffDct = (float *)fftwf_malloc(sizeof(float)*PadCoeff)))
281  goto Catch;
282 
283  for(i = 0; i < NumCoeffs && i < PadCoeff; i++)
284  Buf[i] = Coeff[i];
285  for(; i < PadCoeff; i++)
286  Buf[i] = 0;
287 
288  /* Perform DCT-I */
289  if(!(Plan = fftwf_plan_r2r_1d(PadCoeff, Buf, CoeffDct,
290  FFTW_REDFT00, FFTW_ESTIMATE | FFTW_DESTROY_INPUT)))
291  goto Catch;
292 
293  fftwf_execute(Plan);
294  fftwf_destroy_plan(Plan);
295 
296  /* Incorporate the normalization scale factor into the coefficients */
297  for(i = 0; i < ScanSize; i++)
298  CoeffDct[i] *= 2*(PadCoeff - 1);
299 
300  /* Forward transform of the image data */
301  Dims[0].n = ScanSize;
302  Dims[0].is = Stride;
303  Dims[0].os = 1;
304  HowManyDims[0].n = NumChannels;
305  HowManyDims[0].is = ChannelStride;
306  HowManyDims[0].os = ScanSize*NumScans;
307  HowManyDims[1].n = NumScans;
308  HowManyDims[1].is = ScanStride;
309  HowManyDims[1].os = ScanSize;
310 
311  /* Use DCT-II for half-sample symmetric boundaries,
312  DCT-I for whole-sample symmetric. */
313  Kind[0] = (Boundary == BOUNDARY_HSYMMETRIC) ? FFTW_REDFT10 : FFTW_REDFT00;
314 
315  if(!(Plan = fftwf_plan_guru_r2r(1, Dims, 2, HowManyDims, Data,
316  Buf, Kind, FFTW_ESTIMATE | FFTW_DESTROY_INPUT)))
317  goto Catch;
318 
319  fftwf_execute(Plan);
320  fftwf_destroy_plan(Plan);
321 
322  /* Divide */
323  for(Channel = 0; Channel < NumChannels; Channel++)
324  {
325  for(Scan = 0; Scan < NumScans; Scan++)
326  {
327  for(i = 0; i < ScanSize; i++)
328  Buf[i + ScanSize*(Scan + NumScans*Channel)] /= CoeffDct[i];
329  }
330  }
331 
332  /* Perform inverse transform */
333  Dims[0].n = ScanSize;
334  Dims[0].is = 1;
335  Dims[0].os = Stride;
336  HowManyDims[0].n = NumChannels;
337  HowManyDims[0].is = ScanSize*NumScans;
338  HowManyDims[0].os = ChannelStride;
339  HowManyDims[1].n = NumScans;
340  HowManyDims[1].is = ScanSize;
341  HowManyDims[1].os = ScanStride;
342 
343  /* Use DCT-III (inverse of DCT-II) for half-sample symmetric boundaries,
344  DCT-I (inverse of DCT-I) for whole-sample symmetric. */
345  Kind[0] = (Boundary == BOUNDARY_HSYMMETRIC) ? FFTW_REDFT01 : FFTW_REDFT00;
346 
347  if(!(Plan = fftwf_plan_guru_r2r(1, Dims, 2, HowManyDims, Buf,
348  Data, Kind, FFTW_ESTIMATE | FFTW_DESTROY_INPUT)))
349  goto Catch;
350 
351  fftwf_execute(Plan);
352  fftwf_destroy_plan(Plan);
353  Success = 1;
354 Catch:
355  if(CoeffDct)
356  fftwf_free(CoeffDct);
357  if(Buf)
358  fftwf_free(Buf);
359  fftwf_cleanup();
360  return Success;
361 }
362 
363 
380 int PsfPreFilter(float *Data, int Width, int Height, int NumChannels,
381  const float *Coeff, int NumCoeffs, boundaryhandling Boundary)
382 {
383  if(!Data || !Coeff)
384  return 0;
385 
386  if(!PsfPreFilterScan(Data, Width, Height, 1, Width, Width*Height,
387  NumChannels, Coeff, NumCoeffs, Boundary))
388  return 0;
389 
390  if(!PsfPreFilterScan(Data, 1, Width, Width, Height, Width*Height,
391  NumChannels, Coeff, NumCoeffs, Boundary))
392  return 0;
393 
394  return 1;
395 }