Linear Methods for Image Interpolation
|
00001 00016 #include <math.h> 00017 #include <string.h> 00018 #include "lkernels.h" 00019 00020 #ifndef M_PI 00021 00022 #define M_PI 3.14159265358979323846264338327950288 00023 #endif 00024 00026 #define NUMEL(x) (sizeof(x)/sizeof(*(x))) 00027 00028 00034 float NearestNeighborKernel(float x) 00035 { 00036 if(-0.5f <= x && x < 0.5f) 00037 return 1; 00038 else 00039 return 0; 00040 } 00041 00042 00044 static float BilinearKernel(float x) 00045 { 00046 x = fabs(x); 00047 00048 if(x < 1) 00049 return 1 - x; 00050 else 00051 return 0; 00052 } 00053 00054 00056 static float BicubicKernel(float x) 00057 { 00058 const float alpha = -0.5f; 00059 00060 x = fabs(x); 00061 00062 if(x < 2) 00063 { 00064 if(x <= 1) 00065 return ((alpha + 2)*x - (alpha + 3))*x*x + 1; 00066 else 00067 return ((alpha*x - 5*alpha)*x + 8*alpha)*x - 4*alpha; 00068 } 00069 else 00070 return 0; 00071 } 00072 00073 00075 static float Lanczos2Kernel(float x) 00076 { 00077 if(-2 < x && x < 2) 00078 { 00079 if(x != 0) 00080 return sin(M_PI*x)*sin((M_PI/2)*x) / ((M_PI*M_PI/2)*x*x); 00081 else 00082 return 1; 00083 } 00084 else 00085 return 0; 00086 } 00087 00088 00090 static float Lanczos3Kernel(float x) 00091 { 00092 if(-3 < x && x < 3) 00093 { 00094 if(x != 0) 00095 return sin(M_PI*x)*sin((M_PI/3)*x) / ((M_PI*M_PI/3)*x*x); 00096 else 00097 return 1; 00098 } 00099 else 00100 return 0; 00101 } 00102 00103 00105 static float Lanczos4Kernel(float x) 00106 { 00107 if(-4 < x && x < 4) 00108 { 00109 if(x != 0) 00110 return sin(M_PI*x)*sin((M_PI/4)*x) / ((M_PI*M_PI/4)*x*x); 00111 else 00112 return 1; 00113 } 00114 else 00115 return 0; 00116 } 00117 00118 00120 static const float BSpline2Prefilter[1] = 00121 {-1.715728752538099e-1}; /* exact value: -3 + sqrt(8) */ 00122 00124 static float BSpline2Kernel(float x) 00125 { 00126 x = fabs(x); 00127 00128 if(x <= 0.5f) 00129 return 0.75f - x*x; 00130 else if(x < 1.5f) 00131 { 00132 x = 1.5f - x; 00133 return x*x/2; 00134 } 00135 else 00136 return 0; 00137 } 00138 00139 00141 static float Schaum2Kernel(float x) 00142 { 00143 x = fabs(x); 00144 00145 /* This kernel is discontinuous. At discontinuous points, it takes the 00146 average value of the left and right limits. */ 00147 if(x < 0.5f) 00148 return 1 - x*x; 00149 else if(x == 0.5f) 00150 return 0.5625; 00151 else if(x < 1.5f) 00152 return (x - 3)*x/2 + 1; 00153 else if(x == 1.5f) 00154 return -0.0625; 00155 else 00156 return 0; 00157 } 00158 00159 00161 static float Schaum3Kernel(float x) 00162 { 00163 x = fabs(x); 00164 00165 if(x <= 1) 00166 return ((x - 2)*x - 1)*x/2 + 1; 00167 else if(x < 2) 00168 return ((-x + 6)*x - 11)*x/6 + 1; 00169 else 00170 return 0; 00171 } 00172 00173 00174 00176 static const float BSpline3Prefilter[1] = 00177 {-2.679491924311227e-1}; /* exact value: -2 + sqrt(3) */ 00178 00180 static float BSpline3Kernel(float x) 00181 { 00182 x = fabs(x); 00183 00184 if(x < 1) 00185 return (x/2 - 1)*x*x + 0.66666666666666667f; 00186 else if(x < 2) 00187 { 00188 x = 2 - x; 00189 return x*x*x/6; 00190 } 00191 else 00192 return 0; 00193 } 00194 00195 00197 static const float BSpline5Prefilter[2] = 00198 {-4.309628820326465e-2, /* exact: sqrt(13*sqrt(105)+135)/sqrt(2)-sqrt(105)/2-13/2.0 */ 00199 -4.305753470999738e-1}; /* exact: sqrt(105)/2+sqrt(135-13*sqrt(105))/sqrt(2)-13/2.0 */ 00200 00202 static float BSpline5Kernel(float x) 00203 { 00204 x = fabs(x); 00205 00206 if(x <= 1) 00207 { 00208 float xSqr = x*x; 00209 return (((-10*x + 30)*xSqr - 60)*xSqr + 66) / 120; 00210 } 00211 else if(x < 2) 00212 { 00213 x = 2 - x; 00214 return (1 + (5 + (10 + (10 + (5 - 5*x)*x)*x)*x)*x) / 120; 00215 } 00216 else if(x < 3) 00217 { 00218 float xSqr; 00219 x = 3 - x; 00220 xSqr = x*x; 00221 return xSqr*xSqr*x / 120; 00222 } 00223 else 00224 return 0; 00225 } 00226 00227 00229 static const float BSpline7Prefilter[3] = 00230 {-9.148694809608277e-3, -1.225546151923267e-1, -5.352804307964382e-1}; 00231 00233 static float BSpline7Kernel(float x) 00234 { 00235 x = fabs(x); 00236 00237 if(x <= 1) 00238 { 00239 float xSqr = x*x; 00240 return ((((35*x - 140)*xSqr + 560)*xSqr - 1680)*xSqr + 2416) / 5040; 00241 } 00242 else if(x <= 2) 00243 { 00244 x = 2 - x; 00245 return (120 + (392 + (504 + (280 + (-84 + (-42 + 00246 21*x)*x)*x*x)*x)*x)*x) / 5040; 00247 } 00248 else if(x < 3) 00249 { 00250 x = 3 - x; 00251 return (((((((-7*x + 7)*x + 21)*x + 35)*x + 35)*x 00252 + 21)*x + 7)*x + 1) / 5040; 00253 } 00254 else if(x < 4) 00255 { 00256 float xSqr; 00257 x = 4 - x; 00258 xSqr = x*x; 00259 return xSqr*xSqr*xSqr*x / 5040; 00260 } 00261 else 00262 return 0; 00263 } 00264 00265 00267 static const float BSpline9Prefilter[4] = 00268 {-2.121306903180818e-3, -4.322260854048175e-2, 00269 -2.017505201931532e-1, -6.079973891686259e-1}; 00270 00272 static float BSpline9Kernel(float x) 00273 { 00274 x = fabs(x); 00275 00276 if(x <= 1) 00277 { 00278 float xSqr = x*x; 00279 return (((((-63*x + 315)*xSqr - 2100)*xSqr + 11970)*xSqr 00280 - 44100)*xSqr + 78095) / 181440; 00281 } 00282 else if(x <= 2) 00283 { 00284 x = 2 - x; 00285 return (14608 + (36414 + (34272 + (11256 + (-4032 + (-4284 + (-672 00286 + (504 + (252 - 84*x)*x)*x)*x)*x)*x)*x)*x)*x) / 362880; 00287 } 00288 else if(x <= 3) 00289 { 00290 x = 3 - x; 00291 return (502 + (2214 + (4248 + (4536 + (2772 + (756 + (-168 + (-216 00292 + (-72 + 36*x)*x)*x)*x)*x)*x)*x)*x)*x) / 362880; 00293 } 00294 else if(x < 4) 00295 { 00296 x = 4 - x; 00297 return (1 + (9 + (36 + (84 + (126 + (126 + (84 + (36 + (9 00298 - 9*x)*x)*x)*x)*x)*x)*x)*x)*x) / 362880; 00299 } 00300 else if(x < 5) 00301 { 00302 float xCube; 00303 x = 5 - x; 00304 xCube = x*x*x; 00305 return xCube*xCube*xCube / 362880; 00306 } 00307 else 00308 return 0; 00309 } 00310 00311 00313 static const float BSpline11Prefilter[5] = 00314 {-5.105575344465021e-4, -1.666962736623466e-2, -8.975959979371331e-2, 00315 -2.721803492947859e-1, -6.612660689007345e-1}; 00316 00318 static float BSpline11Kernel(float x) 00319 { 00320 x = fabs(x); 00321 00322 if(x <= 1) 00323 { 00324 float xSqr = x*x; 00325 return (15724248 + (-7475160 + (1718640 + (-255024 + (27720 00326 + (-2772 + 462*x)*xSqr)*xSqr)*xSqr)*xSqr)*xSqr) / 39916800; 00327 } 00328 else if(x <= 2) 00329 { 00330 x = 2 - x; 00331 return (2203488 + (4480872 + (3273600 + (574200 + (-538560 00332 + (-299376 + (39600 + (7920 + (-2640 + (-1320 00333 + 330*x)*x)*x)*x)*x*x)*x)*x)*x)*x)*x) / 39916800; 00334 } 00335 else if(x <= 3) 00336 { 00337 x = 3 - x; 00338 return (152637 + (515097 + (748275 + (586575 + (236610 + (12474 00339 + (-34650 + (-14850 + (-495 + (1485 00340 + (495-165*x)*x)*x)*x)*x)*x)*x)*x)*x)*x)*x) / 39916800; 00341 } 00342 else if(x < 4) 00343 { 00344 x = 4 - x; 00345 return (2036 + (11132 + (27500 + (40260 + (38280 + (24024 + (9240 00346 + (1320 + (-660 + (-440 + (-110 00347 + 55*x)*x)*x)*x)*x)*x)*x)*x)*x)*x)*x) / 39916800; 00348 } 00349 else if(x < 5) 00350 { 00351 x = 5 - x; 00352 return (1 + (11 + (55 + (165 + (330 + (462 + (462 + (330 + (165 00353 + (55 + (11 - 11*x)*x)*x)*x)*x)*x)*x)*x)*x)*x)*x) / 39916800; 00354 } 00355 else if(x < 6) 00356 { 00357 float xSqr, xPow4; 00358 x = 6 - x; 00359 xSqr = x*x; 00360 xPow4 = xSqr*xSqr; 00361 return xPow4*xPow4*xSqr*x / 39916800; 00362 } 00363 else 00364 return 0; 00365 } 00366 00367 00369 static const float OMoms3Prefilter[1] = 00370 {-3.441311542550502e-1}; /* exact: (sqrt(105) - 13)/8 */ 00371 00373 static float OMoms3Kernel(float x) 00374 { 00375 x = fabs(x); 00376 00377 if(x < 1) 00378 return ((x/2 - 1)*x + 1/14.0f)*x + 13/21.0f; 00379 else if(x < 2) 00380 return ((-x/6 + 1)*x - 85/42.0f)*x + 29/21.0f; 00381 else 00382 return 0; 00383 } 00384 00385 00387 static const float OMoms5Prefilter[2] = 00388 {-7.092571896868541e-2, -4.758127100084396e-1}; 00389 00391 static float OMoms5Kernel(float x) 00392 { 00393 x = fabs(x); 00394 00395 if(x <= 1) 00396 return (((((-10*x + 30)*x - (200/33.0f))*x 00397 - (540/11.0f))*x - (5/33.0f))*x + (687/11.0)) / 120; 00398 else if(x < 2) 00399 return (((((330*x - 2970)*x + 10100)*x 00400 - 14940)*x + 6755)*x + 2517)/7920; 00401 else if(x < 3) 00402 { 00403 float xSqr; 00404 x = 3 - x; 00405 xSqr = x*x; 00406 return ((xSqr + (20/33.0f))*xSqr + (1/66.0f))*x / 120; 00407 } 00408 else 00409 return 0; 00410 } 00411 00413 static const float OMoms7Prefilter[3] = 00414 {-1.976842538386140e-2, -1.557007746773578e-1, -5.685376180022930e-1}; 00415 00417 static float OMoms7Kernel(float x) 00418 { 00419 x = fabs(x); 00420 00421 if(x <= 1) 00422 return (((((((15015*x - 60060)*x + 21021)*x + 180180)*x + 2695)*x 00423 - 629244)*x + 21)*x + 989636) / 2162160; 00424 else if(x <= 2) 00425 { 00426 x = 2 - x; 00427 return (x*(x*(x*(x*(x*(x*(5005*x - 10010) - 13013) - 10010) + 54285) 00428 + 119350) + 106267) + 36606) / 1201200; 00429 } 00430 else if(x <= 3) 00431 { 00432 x = 3 - x; 00433 return (x*(x*(x*(x*(x*(x*(-15015*x + 15015) + 24024) + 90090) 00434 + 102410) + 76230) + 31164) + 5536) / 10810800; 00435 } 00436 else if(x < 4) 00437 { 00438 float xSqr; 00439 x = 4 - x; 00440 xSqr = x*x; 00441 return (x*(xSqr*(xSqr*(2145*xSqr + 3003) + 385) + 3)) / 10810800; 00442 } 00443 else 00444 return 0; 00445 } 00446 00447 00449 static interpmethod InterpMethodTable[] = 00450 {{"nearest", NearestNeighborKernel, 0.51f, 0, 0, 0, 1}, 00451 {"bilinear", BilinearKernel, 1, 0, 0, 0, 1}, 00452 {"bicubic", BicubicKernel, 2, 0, 0, 0, 1}, 00453 {"lanczos2", Lanczos2Kernel, 2, 1, 0, 0, 1}, 00454 {"lanczos3", Lanczos3Kernel, 3, 1, 0, 0, 1}, 00455 {"lanczos4", Lanczos4Kernel, 4, 1, 0, 0, 1}, 00456 {"schaum2", Schaum2Kernel, 1.51f, 0, 0, 0, 1}, 00457 {"schaum3", Schaum3Kernel, 2, 0, 0, 0, 1}, 00458 {"bspline2", BSpline2Kernel, 1.5f, 0, 00459 NUMEL(BSpline2Prefilter), BSpline2Prefilter, 8}, 00460 {"bspline3", BSpline3Kernel, 2, 0, 00461 NUMEL(BSpline3Prefilter), BSpline3Prefilter, 6}, 00462 {"bspline5", BSpline5Kernel, 3, 0, 00463 NUMEL(BSpline5Prefilter), BSpline5Prefilter, 120}, 00464 {"bspline7", BSpline7Kernel, 4, 0, 00465 NUMEL(BSpline7Prefilter), BSpline7Prefilter, 5040}, 00466 {"bspline9", BSpline9Kernel, 5, 0, 00467 NUMEL(BSpline9Prefilter), BSpline9Prefilter, 362880}, 00468 {"bspline11", BSpline11Kernel, 6, 0, 00469 NUMEL(BSpline11Prefilter), BSpline11Prefilter, 39916800}, 00470 {"omoms3", OMoms3Kernel, 2, 0, 00471 NUMEL(OMoms3Prefilter), OMoms3Prefilter, 21/4.0f}, 00472 {"omoms5", OMoms5Kernel, 3, 0, 00473 NUMEL(OMoms5Prefilter), OMoms5Prefilter, 7920/107.0f}, 00474 {"omoms7", OMoms7Kernel, 4, 0, 00475 NUMEL(OMoms7Prefilter), OMoms7Prefilter, 675675/346.0f}}; 00476 00477 00492 interpmethod *GetInterpMethod(const char *Name) 00493 { 00494 int i; 00495 00496 for(i = 0; i < (int)NUMEL(InterpMethodTable); i++) 00497 if(!strcmp(InterpMethodTable[i].Name, Name)) 00498 return &InterpMethodTable[i]; 00499 00500 return 0; 00501 }