Image Interpolation with Geometric Contour Stencils
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
sinterp.c
Go to the documentation of this file.
1 
23 #include <string.h>
24 #include "invmat.h"
25 #include "sinterp.h"
26 
27 
29 #define NEIGHRADIUS 1
30 
31 #define QUAD_RES 8
32 
33 #define TRIG_TABLE_SIZE 256
34 
35 #define EXP_TABLE_SIZE 1024
36 
37 /* Quantities derived from NEIGHRADIUS */
39 #define WINDOWRADIUS (1 + NEIGHRADIUS)
40 
41 #define NEIGHDIAMETER (1 + 2*NEIGHRADIUS)
42 
43 #define NEIGHCENTER (NEIGHRADIUS + NEIGHRADIUS*NEIGHDIAMETER)
44 
45 #define NUMNEIGH (NEIGHDIAMETER*NEIGHDIAMETER)
46 
47 
49 typedef struct
50 {
52  float Orientation[NUMNEIGH];
54  float Matrix[NUMNEIGH*NUMNEIGH];
56  float Anisotropy;
57 } sinterpentry;
58 
59 
61 typedef struct sinterpstruct
62 {
64  const sset *StencilSet;
71 } sinterptype;
72 
73 
75 static double Rho(double x, double y, double theta,
76  float SigmaTangent, float SigmaNormal, float Anisotropy)
77 {
78  double t, n;
79 
80  SigmaNormal = Anisotropy*SigmaNormal + (1 - Anisotropy)*SigmaTangent;
81  t = (cos(theta)*x + sin(theta)*y) / SigmaTangent;
82  n = (-sin(theta)*x + cos(theta)*y) / SigmaNormal;
83  return exp(-0.5*(t*t + n*n));
84 }
85 
86 
88 static float RhoFast(float x, float y, float theta,
89  float SigmaTangent, float SigmaNormal, float Anisotropy)
90 {
91  static float ExpTable[EXP_TABLE_SIZE];
92  static float CosTable[TRIG_TABLE_SIZE];
93  static float SinTable[TRIG_TABLE_SIZE];
94  static int TablesInitialized = 0;
95  static const float ExpArgScale = 37.0236f;
96  static const float TrigScale = (float)((TRIG_TABLE_SIZE - 1)/M_PI);
97  float t, n;
98  int i;
99 
100 
101  if(!TablesInitialized)
102  {
103  /* Precompute exp and trig tables */
104  for(i = 0; i < EXP_TABLE_SIZE; i++)
105  ExpTable[i] = (float)exp(-(i - 0.5)/ExpArgScale);
106 
107  for(i = 0; i < TRIG_TABLE_SIZE; i++)
108  {
109  CosTable[i] = (float)cos(i/TrigScale);
110  SinTable[i] = (float)sin(i/TrigScale);
111  }
112 
113  TablesInitialized = 1;
114  }
115 
116  SigmaNormal = Anisotropy*SigmaNormal + (1 - Anisotropy)*SigmaTangent;
117 
118  i = (int)(theta*TrigScale + 0.5f);
119  t = (CosTable[i]*x + SinTable[i]*y) / SigmaTangent;
120  n = (-SinTable[i]*x + CosTable[i]*y) / SigmaNormal;
121  t = (t*t + n*n)*ExpArgScale/2;
122 
123  if(t >= EXP_TABLE_SIZE)
124  return 0;
125  else
126  return ExpTable[(int)t];
127 
128  /*return exp(-0.5*(t*t + n*n));*/
129 }
130 
131 
133 static float Window(float x)
134 {
135  x = (float)fabs(x)/(((float)WINDOWRADIUS)/2);
136 
137  if(x < 1)
138  return (x/2 - 1)*x*x + 0.66666666666666667f;
139  else if(x < 2)
140  {
141  x = 2 - x;
142  return x*x*x/6;
143  }
144  else
145  return 0;
146 }
147 
148 
170 int InterpolateStencil(sinterp *SInterp, int S,
171  const double *PsfSamples)
172 {
173  const sset *StencilSet;
174  sinterpentry *Entry;
175  double A[NUMNEIGH*NUMNEIGH], InverseA[NUMNEIGH*NUMNEIGH];
176  double X, Y, Alpha, Beta, Sum, Mag, MinMag;
177  float RhoSigmaTangent, RhoSigmaNormal;
178  int x, y, m, mx, my, n, nx, ny, Weight, R, Offset;
179 
180 
181  if(!SInterp || !(StencilSet = SInterp->StencilSet)
182  || S < 0 || S >= GetNumStencils(StencilSet))
183  return 0;
184 
185  RhoSigmaTangent = SInterp->RhoSigmaTangent;
186  RhoSigmaNormal = SInterp->RhoSigmaNormal;
187  Entry = &SInterp->StencilInterp[S];
188  R = (int)ceil(QUAD_RES*GetPsfRadius(StencilSet));
189  MinMag = 1e10;
190 
191  /* Compute orientations for the synthesis functions */
192  for(ny = -NEIGHRADIUS, n = 0; ny <= NEIGHRADIUS; ny++)
193  for(nx = -NEIGHRADIUS; nx <= NEIGHRADIUS; nx++, n++)
194  {
195  for(y = 0, Beta = 0; y <= QUAD_RES; y++)
196  {
197  Weight = (y == 0 || y == QUAD_RES) ? 1 : 2;
198  X = nx + 0.5;
199  Y = ny - 0.5 + ((double)y)/QUAD_RES;
200  Beta += Weight*(EvalPhi(StencilSet, S, X, Y)
201  - EvalPhi(StencilSet, S, X - 1, Y));
202  }
203 
204  for(x = 0, Alpha = 0; x <= QUAD_RES; x++)
205  {
206  Weight = (x == 0 || x == QUAD_RES) ? 1 : 2;
207  X = nx - 0.5 + ((double)x)/QUAD_RES;
208  Y = ny + 0.5;
209  Alpha -= Weight*(EvalPhi(StencilSet, S, X, Y)
210  - EvalPhi(StencilSet, S, X, Y - 1));
211  }
212 
213  Alpha /= (2*QUAD_RES);
214  Beta /= (2*QUAD_RES);
215  Mag = Alpha*Alpha + Beta*Beta;
216 
217  if(Mag < MinMag)
218  MinMag = Mag;
219 
220  Entry->Orientation[n] = (float)atan2(Beta, Alpha);
221 
222  while(Entry->Orientation[n] < 0)
223  Entry->Orientation[n] += (float)M_PI;
224  while(Entry->Orientation[n] >= (float)M_PI)
225  Entry->Orientation[n] -= (float)M_PI;
226  }
227 
228  MinMag = sqrt(MinMag);
229  Entry->Anisotropy = (float)pow(MinMag,4);
230  /* printf("S=%2d: %g\n", S, Entry->Anisotropy);*/
231 
232  /* Compute interpolation matrix A_{m,n} = (Psf * Rho^n)(m - n) */
233  for(my = -NEIGHRADIUS, m = 0; my <= NEIGHRADIUS; my++)
234  for(mx = -NEIGHRADIUS; mx <= NEIGHRADIUS; mx++, m++)
235  {
236  for(ny = -NEIGHRADIUS, n = 0; ny <= NEIGHRADIUS; ny++)
237  for(nx = -NEIGHRADIUS; nx <= NEIGHRADIUS; nx++, n++)
238  {
239  Sum = 0;
240 
241  for(y = -R, Offset = 0; y <= R; y++)
242  for(x = -R; x <= R; x++, Offset++)
243  Sum += PsfSamples[Offset]
244  * Rho(mx - nx - ((double)x)/QUAD_RES,
245  my - ny - ((double)y)/QUAD_RES,
246  SInterp->StencilInterp[S].Orientation[n],
247  RhoSigmaTangent, RhoSigmaNormal,
248  SInterp->StencilInterp[S].Anisotropy);
249 
250  A[m + NUMNEIGH*n] = Sum/(QUAD_RES*QUAD_RES);
251  }
252  }
253 
254  if(!InvertMatrix(InverseA, A, NUMNEIGH))
255  return 0;
256 
257  for(n = 0; n < NUMNEIGH*NUMNEIGH; n++)
258  Entry->Matrix[n] = (float)InverseA[n];
259 
260  return 1;
261 }
262 
263 
265 static double *SamplePsf(double (*Psf)(double, double, const void*),
266  const void *PsfParam, int R, double Step)
267 {
268  const int W = 2*R + 1;
269  double *Samples = NULL;
270  int i, j, Offset;
271 
272 
273  if(!(Samples = (double *)Malloc(sizeof(double)*W*W)))
274  return NULL;
275 
276  if(!Psf)
277  Samples[0] = 1/(Step*Step);
278  else
279  for(j = -R, Offset = 0; j <= R; j++)
280  for(i = -R; i <= R; i++, Offset++)
281  Samples[Offset] = Psf(Step*i, Step*j, PsfParam);
282 
283  return Samples;
284 }
285 
286 
298 sinterp *NewSInterp(const sset *StencilSet,
299  float RhoSigmaTangent, float RhoSigmaNormal)
300 {
301  sinterp *SInterp = NULL;
302  double *PsfSamples = NULL;
303  int S;
304 
305 
306  if(!StencilSet
307  || !(SInterp = (sinterp *)Malloc(sizeof(struct sinterpstruct))))
308  return NULL;
309 
310  SInterp->StencilSet = StencilSet;
311  SInterp->StencilInterp = NULL;
312  SInterp->RhoSigmaTangent = RhoSigmaTangent;
313  SInterp->RhoSigmaNormal = RhoSigmaNormal;
314 
315  if(!(SInterp->StencilInterp = (sinterpentry *)Malloc(sizeof(sinterpentry)*
316  GetNumStencils(StencilSet)))
317  || !(PsfSamples = SamplePsf(GetPsf(StencilSet), GetPsfParam(StencilSet),
318  (int)ceil(QUAD_RES*GetPsfRadius(StencilSet)), 1.0/QUAD_RES)))
319  goto Catch;
320 
321  for(S = 0; S < GetNumStencils(StencilSet); S++)
322  if(!InterpolateStencil(SInterp, S, PsfSamples))
323  goto Catch;
324 
325  Free(PsfSamples);
326  return SInterp;
327 Catch:
328  Free(PsfSamples);
329  FreeSInterp(SInterp);
330  return NULL;
331 }
332 
333 
340 void FreeSInterp(sinterp *SInterp)
341 {
342  if(SInterp)
343  {
344  Free(SInterp->StencilInterp);
345  Free(SInterp);
346  }
347 }
348 
349 
356 static int ConstExtension(int N, int i)
357 {
358  if(i < 0)
359  return 0;
360  else if(i >= N)
361  return N - 1;
362  else
363  return i;
364 }
365 
366 
400 int ArbitraryScale(float *Output, int OutputWidth, int OutputHeight,
401  const int *Stencil, const sinterp *SInterp,
402  const float *Input, int InputWidth, int InputHeight,
403  float ScaleFactor, int CenteredGrid)
404 {
405  int (*Extension)(int, int) = ConstExtension;
406  const int InputNumEl = 3*InputWidth*InputHeight;
407  float *Coeff = NULL;
408  const float *Matrix, *CoeffPtr;
409  float u[3], uk[3], v[3], c[3*(NUMNEIGH + 1)], X, Y, Weight, DenomSum;
410  float WindowWeightX[2*WINDOWRADIUS], WindowWeightY[2*WINDOWRADIUS];
411  float XStart, YStart, Xp, Yp, WindowWeight;
412  float RhoSigmaTangent, RhoSigmaNormal;
413  int i, ix, iy, k, x, y, m, n, mx, my, nx, ny, S, Success = 0;
414 
415 
416  if(!(Coeff = (float *)Malloc(sizeof(float)*(NUMNEIGH + 1)*InputNumEl)))
417  goto Catch;
418 
419  if(CenteredGrid)
420  {
421  XStart = (1/ScaleFactor - 1
422  + (InputWidth - OutputWidth/ScaleFactor))/2;
423  YStart = (1/ScaleFactor - 1
424  + (InputHeight - OutputHeight/ScaleFactor))/2;
425  }
426  else
427  XStart = YStart = 0;
428 
429  RhoSigmaTangent = SInterp->RhoSigmaTangent;
430  RhoSigmaNormal = SInterp->RhoSigmaNormal;
431 
432  /* Compute the coefficients c_m^k for every pixel */
433  for(y = 0, k = 0; y < InputHeight; y++)
434  for(x = 0; x < InputWidth; x++, k++)
435  {
436  S = Stencil[x + InputWidth*y];
437  Matrix = SInterp->StencilInterp[S].Matrix;
438  c[0] = Input[3*k + 0];
439  c[1] = Input[3*k + 1];
440  c[2] = Input[3*k + 2];
441 
442  for(m = 3; m < 3*(NUMNEIGH + 1); m++)
443  c[m] = 0;
444 
445  for(ny = -NEIGHRADIUS, n = 0; ny <= NEIGHRADIUS; ny++)
446  for(nx = -NEIGHRADIUS; nx <= NEIGHRADIUS; nx++, n++)
447  {
448  if(nx != 0 || ny != 0)
449  {
450  i = 3*(Extension(InputWidth, x + nx)
451  + InputWidth*Extension(InputHeight, y - ny));
452  v[0] = Input[i + 0] - c[0];
453  v[1] = Input[i + 1] - c[1];
454  v[2] = Input[i + 2] - c[2];
455 
456  /* Compute c_m^k */
457  for(m = 0; m < NUMNEIGH; m++)
458  {
459  c[3*(m + 1) + 0] += Matrix[m + NUMNEIGH*n]*v[0];
460  c[3*(m + 1) + 1] += Matrix[m + NUMNEIGH*n]*v[1];
461  c[3*(m + 1) + 2] += Matrix[m + NUMNEIGH*n]*v[2];
462  }
463  }
464  }
465 
466  /* Save the coefficients */
467  for(m = 0; m < 3*(NUMNEIGH + 1); m++)
468  Coeff[3*(NUMNEIGH + 1)*k + m] = c[m];
469  }
470 
471  /* Compute the interpolation */
472  for(y = 0, k = 0; y < OutputHeight; y++)
473  {
474  Y = YStart + y/ScaleFactor;
475  iy = (int)ceil(Y - WINDOWRADIUS);
476 
477  for(n = 0; n < 2*WINDOWRADIUS; n++)
478  WindowWeightY[n] = Window(Y - iy - n);
479 
480  for(x = 0; x < OutputWidth; x++, k += 3)
481  {
482  X = XStart + x/ScaleFactor;
483  ix = (int)ceil(X - WINDOWRADIUS);
484 
485  for(n = 0; n < 2*WINDOWRADIUS; n++)
486  WindowWeightX[n] = Window(X - ix - n);
487 
488  DenomSum = 0;
489  u[0] = u[1] = u[2] = 0;
490 
491  for(my = 0; my < 2*WINDOWRADIUS; my++)
492  {
493  if((iy + my) < 0 || (iy + my) >= InputHeight)
494  continue;
495 
496  Yp = Y - (iy + my);
497  i = ix + InputWidth*(iy + my);
498 
499  for(mx = 0; mx < 2*WINDOWRADIUS; mx++, i++)
500  {
501  if((ix + mx) < 0 || (ix + mx) >= InputWidth)
502  continue;
503 
504  Xp = X - (ix + mx);
505  CoeffPtr = Coeff + i*3*(NUMNEIGH + 1);
506  S = Stencil[i];
507 
508  uk[0] = CoeffPtr[0];
509  uk[1] = CoeffPtr[1];
510  uk[2] = CoeffPtr[2];
511 
512  for(ny = -NEIGHRADIUS, n = 0; ny <= NEIGHRADIUS; ny++)
513  for(nx = -NEIGHRADIUS; nx <= NEIGHRADIUS; nx++, n++)
514  {
515  Weight = RhoFast(Xp - nx, -(Yp + ny),
516  SInterp->StencilInterp[S].Orientation[n],
517  RhoSigmaTangent, RhoSigmaNormal,
518  SInterp->StencilInterp[S].Anisotropy);
519  uk[0] += CoeffPtr[3*(n + 1) + 0] * Weight;
520  uk[1] += CoeffPtr[3*(n + 1) + 1] * Weight;
521  uk[2] += CoeffPtr[3*(n + 1) + 2] * Weight;
522  }
523 
524  WindowWeight = WindowWeightX[mx] * WindowWeightY[my];
525  DenomSum += WindowWeight;
526  u[0] += WindowWeight * uk[0];
527  u[1] += WindowWeight * uk[1];
528  u[2] += WindowWeight * uk[2];
529  }
530  }
531 
532  Output[k + 0] = u[0] / DenomSum;
533  Output[k + 1] = u[1] / DenomSum;
534  Output[k + 2] = u[2] / DenomSum;
535  }
536  }
537 
538  Success = 1;
539 Catch:
540  Free(Coeff);
541  return Success;
542 }
543 
544 
566 float *ComputeRhoSamples(const sinterp *SInterp,
567  int ScaleFactor, int CenteredGrid)
568 {
569  float *Matrix;
570  float *RhoSamples = NULL;
571  double Weight, RhoS[NUMNEIGH];
572  double x, y, SampleOffset;
573  float RhoSigmaTangent, RhoSigmaNormal;
574  int SupportWidth, SupportSize;
575  int S, sx, sy, i, m, mx, my, n, nx, ny;
576 
577 
578  if(CenteredGrid && ScaleFactor % 2 == 0)
579  { /* If using the centered grid and the scale factor is even */
580  SupportWidth = 2*WINDOWRADIUS*ScaleFactor;
581  SampleOffset = 0.5/ScaleFactor - WINDOWRADIUS;
582  }
583  else
584  { /* If using the top-left grid or scale factor is odd */
585  SupportWidth = 2*WINDOWRADIUS*ScaleFactor - 1;
586  SampleOffset = 1.0/ScaleFactor - WINDOWRADIUS;
587  }
588 
589  SupportSize = SupportWidth*SupportWidth;
590 
591  if(!SInterp || !(RhoSamples = (float *)Malloc(sizeof(float)*
592  NUMNEIGH*GetNumStencils(SInterp->StencilSet)*SupportSize)))
593  return NULL;
594 
595  RhoSigmaTangent = SInterp->RhoSigmaTangent;
596  RhoSigmaNormal = SInterp->RhoSigmaNormal;
597 
598  /* Compute the samples of the Rho functions */
599  for(S = 0; S < GetNumStencils(SInterp->StencilSet); S++)
600  {
601  Matrix = SInterp->StencilInterp[S].Matrix;
602 
603  for(sy = SupportWidth - 1, i = 0; sy >= 0; sy--)
604  for(sx = 0; sx < SupportWidth; sx++, i++)
605  {
606  x = SampleOffset + ((double)sx)/ScaleFactor;
607  y = SampleOffset + ((double)sy)/ScaleFactor;
608 
609  for(n = 0; n < NUMNEIGH; n++)
610  RhoS[n] = 0;
611 
612  RhoS[NEIGHCENTER] = 1;
613 
614  for(my = -NEIGHRADIUS, m = 0; my <= NEIGHRADIUS; my++)
615  for(mx = -NEIGHRADIUS; mx <= NEIGHRADIUS; mx++, m++)
616  {
617  Weight = Rho(x - mx, y - my,
618  SInterp->StencilInterp[S].Orientation[m],
619  RhoSigmaTangent, RhoSigmaNormal,
620  SInterp->StencilInterp[S].Anisotropy);
621 
622  for(ny = -NEIGHRADIUS, n = 0; ny <= NEIGHRADIUS; ny++)
623  for(nx = -NEIGHRADIUS; nx <= NEIGHRADIUS; nx++, n++)
624  if(n != NEIGHCENTER)
625  RhoS[n] += Matrix[m + NUMNEIGH*n]*Weight;
626  }
627 
628  for(n = 0; n < NUMNEIGH; n++)
629  if(n != NEIGHCENTER)
630  RhoS[NEIGHCENTER] -= RhoS[n];
631 
632  Weight = Window((float)x)*Window((float)y);
633 
634  for(n = 0; n < NUMNEIGH; n++)
635  RhoSamples[i + SupportSize*(n + NUMNEIGH*S)]
636  = (float)(RhoS[n] * Weight);
637  }
638  }
639 
640  return RhoSamples;
641 }
642 
643 
660 void IntegerScalePass(float *Output,
661  const int *Stencil, const float *RhoSamples,
662  const float *Input, int InputWidth, int InputHeight,
663  int ScaleFactor, int CenteredGrid)
664 {
665  const int OutputWidth = ScaleFactor*InputWidth;
666  const int OutputHeight = ScaleFactor*InputHeight;
667  int (*Extension)(int, int) = ConstExtension;
668  const int InputStride = 3*InputWidth;
669  const int OutputStride = 3*OutputWidth;
670  const float *RhoSamplePtr, *InputPtr;
671  float v[3], Weight;
672  int sx, sy, SampleOffset, SupportWidth, SupportSize, ni;
673  int ix, iy, InteriorLower, InteriorUpperX, InteriorUpperY;
674  int i, i0, i00, x, y, nx, ny, OutputOffset;
675 
676 
677  if(CenteredGrid && ScaleFactor % 2 == 0)
678  { /* If using the centered grid and the scale factor is even */
679  SupportWidth = 2*WINDOWRADIUS*ScaleFactor;
680  SampleOffset = WINDOWRADIUS*ScaleFactor - ScaleFactor/2;
681  }
682  else
683  { /* If using the top-left grid or scale factor is odd */
684  SupportWidth = 2*WINDOWRADIUS*ScaleFactor - 1;
685  SampleOffset = WINDOWRADIUS*ScaleFactor - 1;
686 
687  if(CenteredGrid)
688  SampleOffset -= (ScaleFactor - 1)/2;
689  }
690 
691  SupportSize = SupportWidth*SupportWidth;
692  OutputOffset = 3*SampleOffset*(1 + OutputWidth);
693 
694  /* Determine the interior of the image */
695  InteriorLower = (SampleOffset + ScaleFactor - 1)/ScaleFactor;
696  InteriorUpperX = (OutputWidth + SampleOffset
697  - SupportWidth + 1)/ScaleFactor;
698  InteriorUpperY = (OutputHeight + SampleOffset
699  - SupportWidth + 1)/ScaleFactor;
700 
701  if(InteriorLower < NEIGHRADIUS)
702  InteriorLower = NEIGHRADIUS;
703  if(InteriorUpperX > InputWidth - NEIGHRADIUS - 1)
704  InteriorUpperX = InputWidth - NEIGHRADIUS - 1;
705  if(InteriorUpperY > OutputHeight - NEIGHRADIUS - 1)
706  InteriorUpperY = OutputHeight - NEIGHRADIUS - 1;
707 
708  for(iy = -WINDOWRADIUS; iy < InputHeight + WINDOWRADIUS; iy++)
709  for(ix = -WINDOWRADIUS; ix < InputWidth + WINDOWRADIUS; ix++)
710  {
711  if(!(InteriorLower <= ix && ix < InteriorUpperX
712  && InteriorLower <= iy && iy < InteriorUpperY))
713  { /* General code for near the boundaries of the image */
714  RhoSamplePtr = RhoSamples + SupportSize*NUMNEIGH*
715  Stencil[(Extension(InputWidth, ix)
716  + InputWidth*Extension(InputHeight, iy))];
717 
718  for(ny = -NEIGHRADIUS; ny <= NEIGHRADIUS; ny++)
719  for(nx = -NEIGHRADIUS; nx <= NEIGHRADIUS; nx++)
720  {
721  ni = 3*(Extension(InputWidth, ix + nx)
722  + InputWidth*Extension(InputHeight, iy - ny));
723  v[0] = Input[ni + 0];
724  v[1] = Input[ni + 1];
725  v[2] = Input[ni + 2];
726  y = ScaleFactor*iy - SampleOffset;
727 
728  for(sy = 0; sy < SupportWidth;
729  sy++, y++, RhoSamplePtr += SupportWidth)
730  if(0 <= y && y < OutputHeight)
731  {
732  x = ScaleFactor*ix - SampleOffset;
733  i = 3*(x + OutputWidth*y);
734 
735  for(sx = 0; sx < SupportWidth;
736  sx++, x++, i += 3)
737  if(0 <= x && x < OutputWidth)
738  {
739  Weight = RhoSamplePtr[sx];
740  Output[i + 0] += Weight*v[0];
741  Output[i + 1] += Weight*v[1];
742  Output[i + 2] += Weight*v[2];
743  }
744  }
745  }
746  }
747  else
748  { /* Faster code for the interior of the image */
749  RhoSamplePtr = RhoSamples +
750  SupportSize*NUMNEIGH*Stencil[ix + InputWidth*iy];
751  i00 = 3*(ScaleFactor*ix + OutputWidth*ScaleFactor*iy) - OutputOffset;
752  InputPtr = Input + 3*(ix - NEIGHRADIUS + InputWidth*(iy + NEIGHRADIUS));
753 
754  for(ny = 0; ny < NEIGHDIAMETER; ny++, InputPtr -= InputStride)
755  {
756  for(nx = 0; nx < 3*NEIGHDIAMETER; nx += 3)
757  {
758  v[0] = InputPtr[nx + 0];
759  v[1] = InputPtr[nx + 1];
760  v[2] = InputPtr[nx + 2];
761 
762  for(sy = 0, i0 = i00; sy < SupportWidth; sy++,
763  i0 += OutputStride, RhoSamplePtr += SupportWidth)
764  for(sx = 0, i = i0; sx < SupportWidth; sx++, i += 3)
765  {
766  Weight = RhoSamplePtr[sx];
767  Output[i + 0] += Weight*v[0];
768  Output[i + 1] += Weight*v[1];
769  Output[i + 2] += Weight*v[2];
770  }
771  }
772  }
773  }
774  }
775 }
776 
777 
802 int Prefilter(float *Filtered,
803  const int *Stencil, const float *RhoSamples,
804  const float *Input, int InputWidth, int InputHeight,
805  int ScaleFactor, int CenteredGrid, float PsfSigma, int NumPasses)
806 {
807  const int InputNumEl = 3*InputWidth*InputHeight;
808  const int InterpWidth = ScaleFactor*InputWidth;
809  const int InterpHeight = ScaleFactor*InputHeight;
810  const int InterpNumEl = 3*InterpWidth*InterpHeight;
811  float *Interp = NULL, *Residual = NULL;
812  float MaxResidual;
813  int i, Pass, Success = 0;
814 
815 
816  if(!Filtered || !Stencil || !RhoSamples || !Input
817  || !(Interp = (float *)Malloc(sizeof(float)*InterpNumEl))
818  || !(Residual = (float *)Malloc(sizeof(float)*InputNumEl)))
819  goto Catch;
820 
821  memcpy(Filtered, Input, sizeof(float)*InputNumEl);
822 
823  for(i = 0; i < InterpNumEl; i++)
824  Interp[i] = 0;
825 
826  printf("\n Iteration Residual norm\n -------------------------\n");
827 
828  for(Pass = 0; Pass < NumPasses; Pass++)
829  {
830  if(Pass == 0)
831  IntegerScalePass(Interp, Stencil, RhoSamples,
832  Input, InputWidth, InputHeight, ScaleFactor, CenteredGrid);
833  else
834  IntegerScalePass(Interp, Stencil, RhoSamples,
835  Residual, InputWidth, InputHeight, ScaleFactor, CenteredGrid);
836 
837  if((MaxResidual = DeconvResidual(Residual,
838  Input, InputWidth, InputHeight,
839  Interp, InterpWidth, InterpHeight,
840  (float)ScaleFactor, CenteredGrid, PsfSigma)) < 0)
841  goto Catch;
842 
843  printf(" %8d %15.8f\n", Pass + 1, MaxResidual);
844 
845  for(i = 0; i < InputNumEl; i++)
846  Filtered[i] += Residual[i];
847  }
848 
849  Success = 1;
850 Catch:
851  Free(Residual);
852  Free(Interp);
853  return Success;
854 }
855 
856 
858 static float Sqr(float x)
859 {
860  return x*x;
861 }
862 
863 
880 float DeconvResidual(float *Residual,
881  const float *Coarse, int CoarseWidth, int CoarseHeight,
882  const float *Interp, int InterpWidth, int InterpHeight,
883  float ScaleFactor, int CenteredGrid, float PsfSigma)
884 {
885  /*int (*Extension)(int, int) = ExtensionMethod[Param.Boundary];*/
886  int (*Extension)(int, int) = ConstExtension;
887  const int CoarseStride = 3*CoarseWidth;
888  const float PsfRadius = 4*PsfSigma*ScaleFactor;
889  const int PsfWidth = (int)ceil(2*PsfRadius);
890  float *Temp = NULL, *PsfBuf = NULL;
891  float ExpDenom, Weight, Sum[3], DenomSum, MaxResidual = 0;
892  float XStart, YStart, X, Y;
893  int IndexX0, IndexY0, SrcOffset, DestOffset;
894  int x, y, i, n, c;
895 
896 
897  if(!(Temp = (float *)Malloc(sizeof(float)*3*CoarseWidth*InterpHeight))
898  || !(PsfBuf = (float *)Malloc(sizeof(float)*PsfWidth)))
899  {
900  free(Temp);
901  free(PsfBuf);
902  return -1;
903  }
904 
905  if(CenteredGrid)
906  {
907  XStart = (1/ScaleFactor - 1
908  + (CoarseWidth - InterpWidth/ScaleFactor))/2;
909  YStart = (1/ScaleFactor - 1
910  + (CoarseHeight - InterpHeight/ScaleFactor))/2;
911  }
912  else
913  XStart = YStart = 0;
914 
915  ExpDenom = 2 * Sqr(PsfSigma*ScaleFactor);
916 
917  for(x = 0; x < CoarseWidth; x++)
918  {
919  X = (-XStart + x)*ScaleFactor;
920  IndexX0 = (int)ceil(X - PsfRadius);
921 
922  /* Evaluate the PSF */
923  for(n = 0; n < PsfWidth; n++)
924  PsfBuf[n] = (float)exp(-Sqr(X - (IndexX0 + n)) / ExpDenom);
925 
926  for(y = 0, SrcOffset = 0, DestOffset = 3*x; y < InterpHeight;
927  y++, SrcOffset += InterpWidth, DestOffset += CoarseStride)
928  {
929  Sum[0] = Sum[1] = Sum[2] = DenomSum = 0;
930 
931  for(n = 0; n < PsfWidth; n++)
932  {
933  Weight = PsfBuf[n];
934  DenomSum += Weight;
935  i = 3*(Extension(InterpWidth, IndexX0 + n) + SrcOffset);
936 
937  for(c = 0; c < 3; c++)
938  Sum[c] += Weight * Interp[i + c];
939  }
940 
941  for(c = 0; c < 3; c++)
942  Temp[DestOffset + c] = Sum[c] / DenomSum;
943  }
944  }
945 
946  for(y = 0; y < CoarseHeight; y++,
947  Residual += CoarseStride, Coarse += CoarseStride)
948  {
949  Y = (-YStart + y)*ScaleFactor;
950  IndexY0 = (int)ceil(Y - PsfRadius);
951 
952  /* Evaluate the PSF */
953  for(n = 0; n < PsfWidth; n++)
954  PsfBuf[n] = (float)exp(-Sqr(Y - (IndexY0 + n)) / ExpDenom);
955 
956  for(x = 0; x < CoarseStride; x += 3)
957  {
958  Sum[0] = Sum[1] = Sum[2] = DenomSum = 0;
959 
960  for(n = 0; n < PsfWidth; n++)
961  {
962  SrcOffset = x + CoarseStride*Extension(InterpHeight, IndexY0 + n);
963  Weight = PsfBuf[n];
964  DenomSum += Weight;
965 
966  for(c = 0; c < 3; c++)
967  Sum[c] += Weight * Temp[SrcOffset + c];
968  }
969 
970  for(c = 0; c < 3; c++)
971  {
972  Residual[x + c] = Coarse[x + c] - Sum[c] / DenomSum;
973 
974  if(fabs(Residual[x + c]) > MaxResidual)
975  MaxResidual = (float)fabs(Residual[x + c]);
976  }
977  }
978  }
979 
980  Free(PsfBuf);
981  Free(Temp);
982  return MaxResidual;
983 }
984