Linear Methods for Image Interpolation
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
lkernels.c
Go to the documentation of this file.
1 
16 #include <math.h>
17 #include <string.h>
18 #include "lkernels.h"
19 
20 #ifndef M_PI
21 
22 #define M_PI 3.14159265358979323846264338327950288
23 #endif
24 
26 #define NUMEL(x) (sizeof(x)/sizeof(*(x)))
27 
28 
34 float NearestNeighborKernel(float x)
35 {
36  if(-0.5f <= x && x < 0.5f)
37  return 1;
38  else
39  return 0;
40 }
41 
42 
44 static float BilinearKernel(float x)
45 {
46  x = fabs(x);
47 
48  if(x < 1)
49  return 1 - x;
50  else
51  return 0;
52 }
53 
54 
56 static float BicubicKernel(float x)
57 {
58  const float alpha = -0.5f;
59 
60  x = fabs(x);
61 
62  if(x < 2)
63  {
64  if(x <= 1)
65  return ((alpha + 2)*x - (alpha + 3))*x*x + 1;
66  else
67  return ((alpha*x - 5*alpha)*x + 8*alpha)*x - 4*alpha;
68  }
69  else
70  return 0;
71 }
72 
73 
75 static float Lanczos2Kernel(float x)
76 {
77  if(-2 < x && x < 2)
78  {
79  if(x != 0)
80  return sin(M_PI*x)*sin((M_PI/2)*x) / ((M_PI*M_PI/2)*x*x);
81  else
82  return 1;
83  }
84  else
85  return 0;
86 }
87 
88 
90 static float Lanczos3Kernel(float x)
91 {
92  if(-3 < x && x < 3)
93  {
94  if(x != 0)
95  return sin(M_PI*x)*sin((M_PI/3)*x) / ((M_PI*M_PI/3)*x*x);
96  else
97  return 1;
98  }
99  else
100  return 0;
101 }
102 
103 
105 static float Lanczos4Kernel(float x)
106 {
107  if(-4 < x && x < 4)
108  {
109  if(x != 0)
110  return sin(M_PI*x)*sin((M_PI/4)*x) / ((M_PI*M_PI/4)*x*x);
111  else
112  return 1;
113  }
114  else
115  return 0;
116 }
117 
118 
120 static const float BSpline2Prefilter[1] =
121  {-1.715728752538099e-1}; /* exact value: -3 + sqrt(8) */
122 
124 static float BSpline2Kernel(float x)
125 {
126  x = fabs(x);
127 
128  if(x <= 0.5f)
129  return 0.75f - x*x;
130  else if(x < 1.5f)
131  {
132  x = 1.5f - x;
133  return x*x/2;
134  }
135  else
136  return 0;
137 }
138 
139 
141 static float Schaum2Kernel(float x)
142 {
143  x = fabs(x);
144 
145  /* This kernel is discontinuous. At discontinuous points, it takes the
146  average value of the left and right limits. */
147  if(x < 0.5f)
148  return 1 - x*x;
149  else if(x == 0.5f)
150  return 0.5625;
151  else if(x < 1.5f)
152  return (x - 3)*x/2 + 1;
153  else if(x == 1.5f)
154  return -0.0625;
155  else
156  return 0;
157 }
158 
159 
161 static float Schaum3Kernel(float x)
162 {
163  x = fabs(x);
164 
165  if(x <= 1)
166  return ((x - 2)*x - 1)*x/2 + 1;
167  else if(x < 2)
168  return ((-x + 6)*x - 11)*x/6 + 1;
169  else
170  return 0;
171 }
172 
173 
174 
176 static const float BSpline3Prefilter[1] =
177  {-2.679491924311227e-1}; /* exact value: -2 + sqrt(3) */
178 
180 static float BSpline3Kernel(float x)
181 {
182  x = fabs(x);
183 
184  if(x < 1)
185  return (x/2 - 1)*x*x + 0.66666666666666667f;
186  else if(x < 2)
187  {
188  x = 2 - x;
189  return x*x*x/6;
190  }
191  else
192  return 0;
193 }
194 
195 
197 static const float BSpline5Prefilter[2] =
198  {-4.309628820326465e-2, /* exact: sqrt(13*sqrt(105)+135)/sqrt(2)-sqrt(105)/2-13/2.0 */
199  -4.305753470999738e-1}; /* exact: sqrt(105)/2+sqrt(135-13*sqrt(105))/sqrt(2)-13/2.0 */
200 
202 static float BSpline5Kernel(float x)
203 {
204  x = fabs(x);
205 
206  if(x <= 1)
207  {
208  float xSqr = x*x;
209  return (((-10*x + 30)*xSqr - 60)*xSqr + 66) / 120;
210  }
211  else if(x < 2)
212  {
213  x = 2 - x;
214  return (1 + (5 + (10 + (10 + (5 - 5*x)*x)*x)*x)*x) / 120;
215  }
216  else if(x < 3)
217  {
218  float xSqr;
219  x = 3 - x;
220  xSqr = x*x;
221  return xSqr*xSqr*x / 120;
222  }
223  else
224  return 0;
225 }
226 
227 
229 static const float BSpline7Prefilter[3] =
230  {-9.148694809608277e-3, -1.225546151923267e-1, -5.352804307964382e-1};
231 
233 static float BSpline7Kernel(float x)
234 {
235  x = fabs(x);
236 
237  if(x <= 1)
238  {
239  float xSqr = x*x;
240  return ((((35*x - 140)*xSqr + 560)*xSqr - 1680)*xSqr + 2416) / 5040;
241  }
242  else if(x <= 2)
243  {
244  x = 2 - x;
245  return (120 + (392 + (504 + (280 + (-84 + (-42 +
246  21*x)*x)*x*x)*x)*x)*x) / 5040;
247  }
248  else if(x < 3)
249  {
250  x = 3 - x;
251  return (((((((-7*x + 7)*x + 21)*x + 35)*x + 35)*x
252  + 21)*x + 7)*x + 1) / 5040;
253  }
254  else if(x < 4)
255  {
256  float xSqr;
257  x = 4 - x;
258  xSqr = x*x;
259  return xSqr*xSqr*xSqr*x / 5040;
260  }
261  else
262  return 0;
263 }
264 
265 
267 static const float BSpline9Prefilter[4] =
268  {-2.121306903180818e-3, -4.322260854048175e-2,
269  -2.017505201931532e-1, -6.079973891686259e-1};
270 
272 static float BSpline9Kernel(float x)
273 {
274  x = fabs(x);
275 
276  if(x <= 1)
277  {
278  float xSqr = x*x;
279  return (((((-63*x + 315)*xSqr - 2100)*xSqr + 11970)*xSqr
280  - 44100)*xSqr + 78095) / 181440;
281  }
282  else if(x <= 2)
283  {
284  x = 2 - x;
285  return (14608 + (36414 + (34272 + (11256 + (-4032 + (-4284 + (-672
286  + (504 + (252 - 84*x)*x)*x)*x)*x)*x)*x)*x)*x) / 362880;
287  }
288  else if(x <= 3)
289  {
290  x = 3 - x;
291  return (502 + (2214 + (4248 + (4536 + (2772 + (756 + (-168 + (-216
292  + (-72 + 36*x)*x)*x)*x)*x)*x)*x)*x)*x) / 362880;
293  }
294  else if(x < 4)
295  {
296  x = 4 - x;
297  return (1 + (9 + (36 + (84 + (126 + (126 + (84 + (36 + (9
298  - 9*x)*x)*x)*x)*x)*x)*x)*x)*x) / 362880;
299  }
300  else if(x < 5)
301  {
302  float xCube;
303  x = 5 - x;
304  xCube = x*x*x;
305  return xCube*xCube*xCube / 362880;
306  }
307  else
308  return 0;
309 }
310 
311 
313 static const float BSpline11Prefilter[5] =
314  {-5.105575344465021e-4, -1.666962736623466e-2, -8.975959979371331e-2,
315  -2.721803492947859e-1, -6.612660689007345e-1};
316 
318 static float BSpline11Kernel(float x)
319 {
320  x = fabs(x);
321 
322  if(x <= 1)
323  {
324  float xSqr = x*x;
325  return (15724248 + (-7475160 + (1718640 + (-255024 + (27720
326  + (-2772 + 462*x)*xSqr)*xSqr)*xSqr)*xSqr)*xSqr) / 39916800;
327  }
328  else if(x <= 2)
329  {
330  x = 2 - x;
331  return (2203488 + (4480872 + (3273600 + (574200 + (-538560
332  + (-299376 + (39600 + (7920 + (-2640 + (-1320
333  + 330*x)*x)*x)*x)*x*x)*x)*x)*x)*x)*x) / 39916800;
334  }
335  else if(x <= 3)
336  {
337  x = 3 - x;
338  return (152637 + (515097 + (748275 + (586575 + (236610 + (12474
339  + (-34650 + (-14850 + (-495 + (1485
340  + (495-165*x)*x)*x)*x)*x)*x)*x)*x)*x)*x)*x) / 39916800;
341  }
342  else if(x < 4)
343  {
344  x = 4 - x;
345  return (2036 + (11132 + (27500 + (40260 + (38280 + (24024 + (9240
346  + (1320 + (-660 + (-440 + (-110
347  + 55*x)*x)*x)*x)*x)*x)*x)*x)*x)*x)*x) / 39916800;
348  }
349  else if(x < 5)
350  {
351  x = 5 - x;
352  return (1 + (11 + (55 + (165 + (330 + (462 + (462 + (330 + (165
353  + (55 + (11 - 11*x)*x)*x)*x)*x)*x)*x)*x)*x)*x)*x) / 39916800;
354  }
355  else if(x < 6)
356  {
357  float xSqr, xPow4;
358  x = 6 - x;
359  xSqr = x*x;
360  xPow4 = xSqr*xSqr;
361  return xPow4*xPow4*xSqr*x / 39916800;
362  }
363  else
364  return 0;
365 }
366 
367 
369 static const float OMoms3Prefilter[1] =
370  {-3.441311542550502e-1}; /* exact: (sqrt(105) - 13)/8 */
371 
373 static float OMoms3Kernel(float x)
374 {
375  x = fabs(x);
376 
377  if(x < 1)
378  return ((x/2 - 1)*x + 1/14.0f)*x + 13/21.0f;
379  else if(x < 2)
380  return ((-x/6 + 1)*x - 85/42.0f)*x + 29/21.0f;
381  else
382  return 0;
383 }
384 
385 
387 static const float OMoms5Prefilter[2] =
388  {-7.092571896868541e-2, -4.758127100084396e-1};
389 
391 static float OMoms5Kernel(float x)
392 {
393  x = fabs(x);
394 
395  if(x <= 1)
396  return (((((-10*x + 30)*x - (200/33.0f))*x
397  - (540/11.0f))*x - (5/33.0f))*x + (687/11.0)) / 120;
398  else if(x < 2)
399  return (((((330*x - 2970)*x + 10100)*x
400  - 14940)*x + 6755)*x + 2517)/7920;
401  else if(x < 3)
402  {
403  float xSqr;
404  x = 3 - x;
405  xSqr = x*x;
406  return ((xSqr + (20/33.0f))*xSqr + (1/66.0f))*x / 120;
407  }
408  else
409  return 0;
410 }
411 
413 static const float OMoms7Prefilter[3] =
414  {-1.976842538386140e-2, -1.557007746773578e-1, -5.685376180022930e-1};
415 
417 static float OMoms7Kernel(float x)
418 {
419  x = fabs(x);
420 
421  if(x <= 1)
422  return (((((((15015*x - 60060)*x + 21021)*x + 180180)*x + 2695)*x
423  - 629244)*x + 21)*x + 989636) / 2162160;
424  else if(x <= 2)
425  {
426  x = 2 - x;
427  return (x*(x*(x*(x*(x*(x*(5005*x - 10010) - 13013) - 10010) + 54285)
428  + 119350) + 106267) + 36606) / 1201200;
429  }
430  else if(x <= 3)
431  {
432  x = 3 - x;
433  return (x*(x*(x*(x*(x*(x*(-15015*x + 15015) + 24024) + 90090)
434  + 102410) + 76230) + 31164) + 5536) / 10810800;
435  }
436  else if(x < 4)
437  {
438  float xSqr;
439  x = 4 - x;
440  xSqr = x*x;
441  return (x*(xSqr*(xSqr*(2145*xSqr + 3003) + 385) + 3)) / 10810800;
442  }
443  else
444  return 0;
445 }
446 
447 
449 static interpmethod InterpMethodTable[] =
450  {{"nearest", NearestNeighborKernel, 0.51f, 0, 0, 0, 1},
451  {"bilinear", BilinearKernel, 1, 0, 0, 0, 1},
452  {"bicubic", BicubicKernel, 2, 0, 0, 0, 1},
453  {"lanczos2", Lanczos2Kernel, 2, 1, 0, 0, 1},
454  {"lanczos3", Lanczos3Kernel, 3, 1, 0, 0, 1},
455  {"lanczos4", Lanczos4Kernel, 4, 1, 0, 0, 1},
456  {"schaum2", Schaum2Kernel, 1.51f, 0, 0, 0, 1},
457  {"schaum3", Schaum3Kernel, 2, 0, 0, 0, 1},
458  {"bspline2", BSpline2Kernel, 1.5f, 0,
459  NUMEL(BSpline2Prefilter), BSpline2Prefilter, 8},
460  {"bspline3", BSpline3Kernel, 2, 0,
461  NUMEL(BSpline3Prefilter), BSpline3Prefilter, 6},
462  {"bspline5", BSpline5Kernel, 3, 0,
463  NUMEL(BSpline5Prefilter), BSpline5Prefilter, 120},
464  {"bspline7", BSpline7Kernel, 4, 0,
465  NUMEL(BSpline7Prefilter), BSpline7Prefilter, 5040},
466  {"bspline9", BSpline9Kernel, 5, 0,
467  NUMEL(BSpline9Prefilter), BSpline9Prefilter, 362880},
468  {"bspline11", BSpline11Kernel, 6, 0,
469  NUMEL(BSpline11Prefilter), BSpline11Prefilter, 39916800},
470  {"omoms3", OMoms3Kernel, 2, 0,
471  NUMEL(OMoms3Prefilter), OMoms3Prefilter, 21/4.0f},
472  {"omoms5", OMoms5Kernel, 3, 0,
473  NUMEL(OMoms5Prefilter), OMoms5Prefilter, 7920/107.0f},
474  {"omoms7", OMoms7Kernel, 4, 0,
475  NUMEL(OMoms7Prefilter), OMoms7Prefilter, 675675/346.0f}};
476 
477 
492 interpmethod *GetInterpMethod(const char *Name)
493 {
494  int i;
495 
496  for(i = 0; i < (int)NUMEL(InterpMethodTable); i++)
497  if(!strcmp(InterpMethodTable[i].Name, Name))
498  return &InterpMethodTable[i];
499 
500  return 0;
501 }