GNOME Bugzilla – Bug 166132
Better image scaling algorithms, redux
Last modified: 2005-02-03 16:07:22 UTC
A follow-up from bug #162250: Feature Request: Better image scaling algorithms. Sven suggested a new bug report ("Having too many comments in a single bug report makes it unlikely that it will be picked up anytime later.") (Un-disclaimer: I do machine learning and image processing research at BYU.) First, from an algorithmic standpoint (UI excluded), it would be VERY easy to add a few new interpolants. This paper goes over a bunch with symmetrical, separable kernels: http://www.cvgpr.uni-mannheim.de/hornegger/MEDBV/handouts/lehmann.pdf Page 1052 describes the algorithm template they're used in. One other nifty resource I found was this: http://www.ldv.ei.tum.de/media/files/dvi/vorlesung/z03_reconstruction_filters.pdf page 223. From it, I wrote some code for one of my own projects: /* 1/6 * if |x| < 1, (12 - 9*B - 6*C)|x|^3 + (-18 + 12*B + 6*C)|x|^2 + (6 - 2*B) else if |x| < 2, (-B - 6C)|x|^3 + (6*B + 30*C)|x|^2 + (-12*B - 48*C)|x| + (8*B + 24*C) else 0 (B, C) = (1, 0): cubic B-spline (0, C): one-parameter family of cardinal cubics with (0, 0.5) being Catmull-Rom (B, 0): Duff's tensioned B-splines */ static inline float cubicKernel(float x, float b, float c) { float weight; float ax = (float)fabs(x); if (ax > 2) return 0; float x3 = ax * ax * ax; float x2 = ax * ax; if (ax < 1) weight = (12 - 9 * b - 6 * c) * x3 + (-18 + 12 * b + 6 * c) * x2 + (6 - 2 * b); else weight = (-b - 6 * c) * x3 + (6 * b + 30 * c) * x2 + (-12 * b - 48 * c) * ax + (8 * b + 24 * c); return weight * (1.0f / 6.0f); } static inline float bicubicDistWeight(float dy, float dx, float b, float c) { return cubicKernel(dy, b, c) * cubicKernel(dx, b, c); } static inline float bsplineDistWeight(float dy, float dx) { return cubicKernel(dy, 1, 0) * cubicKernel(dx, 1, 0); } static inline float catmullRomDistWeight(float dy, float dx) { return cubicKernel(dy, 0, 0.5f) * cubicKernel(dx, 0, 0.5f); } So if (B,C) = (0,0.5), you've got a Catmull-Rom kernel, which is what GIMP uses right now in scale-funcs.c. If (B,C) = (1,0), it's a B-spline kernel, which results in much a smoother (C-2 continuous) result, which GIMP could *definitely* use. Even better: if the bicubic interpolator were coded to smoothly transition between (0,0.5) and (1,0), GIMP could give the users a sliding scale between "smooth" and "sharp" bicubic interpolation. Photoshop's "Bicubic Smooth" and "Bicubic Sharp" options have nothing on that. General-interest FYI: Albert Cahalan's baby, Lanczos, may be the most "correct" interpolant under a certain set of assumptions. Realize, however, that you can always invent a set of assumptions (along with a set of fitness tests) that makes one interpolant more "correct" than another. In fact, you can *prove* that it's *impossible* to make a perfect generalization about between values from a finite set of samples - a result from machine learning that generally gets overlooked by the image processing community.
*** This bug has been marked as a duplicate of 166130 ***
Note to Neil Toronto: in this case (same bug accidentally reported twice by the same person), it is better to mark the additional copy as INVALID instead of DUPLICATE. This avoids inflating the reports on most frequently reported bugs: http://bugzilla.gnome.org/reports/product-mostfrequent.cgi?product=GIMP See also the GIMP developers FAQ: http://developer.gimp.org/faq.html#id2789416