main-upsampling
Examples of Upsampling
Here are examples of upsampling with various reconstruction filters. I used my example solution to the Imaging Programming Assignment.
Notice how the best filters for the checkboard example, aren’t necessarily the best for a more natural image - in particular, the “sharper” filters (like Cat-Rom and Lanczos) are too sharp for the checkboard (they ring), but they produce much sharper results for the BAD LINK.
Synthetic Example
This is a very tiny example (24 pixels square) of a checkerboard (a bad case - natural images don’t have this much high frequencies). The colors in the main parts are not black and white (they are gray) so the ringing doesn’t “overflow” the 0-255 range. I have upsampled by a factor of 8.
original image (24x24) | |
Box Filter | |
Tent Filter | |
Cubic BSpline Filter | |
Catmull-Rom (interpolating cubic) | |
Mitchell-Netraveli | |
Lanczos (radius 2) | |
Lanczos (radius 3) | |
Lanczos (radius 4) |
This time scaled up by 3 - the original is pretty small.
Natural Example
original image (90x60) | |
Box Filter | |
Tent Filter | |
Cubic BSpline Filter | |
Catmull-Rom (interpolating cubic) | |
Mitchell-Netraveli | |
Lanczos (radius 2) | |
Lanczos (radius 3) | |
Lanczos (radius 4) |
Here are the equations for the various filters. All come from the book EXCEPT for Lanczos, which I took from Wikipedia (and adapted).
Warning: you are getting a glimpse into how my solution works (yes, its designed for simplicity, not for efficiency).
class Filter { public: Filter(float rad, string& nm) : radius(rad), name(nm) {}; string name; float radius; // should be an over statement (so you get some zeros) virtual float eval(float) = 0; }; class BoxFilter : public Filter { public: BoxFilter() : Filter(1,string("Box")) {}; virtual float eval(float t) { return ( (t>=-.5) && (t<.5) ) ? ((float)1) : ((float)0); }; }; class TentFilter : public Filter { public: TentFilter() : Filter(1,string("Tent")) {}; virtual float eval(float t) { float x = abs(t); return ( x>1 ) ? 0.0f : (1.0f - x); }; }; // from p90 of Shirley static float cubed(float x) { return x*x*x; } static float squared(float x) { return x*x; } class BSplineFilter : public Filter { public: BSplineFilter() : Filter(2,string("CubicBSpline")) { }; virtual float eval(float x) { float a = abs(x); float m = 1.0f-a; if (a<=1) return (-3.0f * m*m*m + 3.0f*m*m + 3*m + 1) / 6.0f; if (a<2) return cubed(2.0f - a) / 6.0f; return 0; }; }; // p91 of Shirley class CatRomFilter : public Filter { public: CatRomFilter() : Filter(2,string("Catmull-Rom")) { }; virtual float eval(float x) { float a = abs(x); float m = 1.0f-a; if (a<=1) return (-3.0f * m*m*m + 4.0f*m*m + m) / 2.0f; if (a<2) return (cubed(2.0f - a) - squared(2.0f-a)) /2;; return 0; }; }; class MitchellNetravali : public Filter { public: MitchellNetravali() : Filter(2,string("Mitchell-Netravali")) {}; virtual float eval(float x) { float a = abs(x); float m = 1.0f-a; if (a<=1) return (-21.0f * m*m*m + 27.0f*m*m + 9*m + 1) / 18.0f; if (a<2) return (7.0f*cubed(2.0f - a) - 6.0f*squared(2.0f-a)) / 18.0f; return 0; }; }; // taken from the WikiPedia page class Lanczos : public Filter { public: Lanczos(float radius) : Filter(radius,string("Lanczos")+stringify(radius)) {}; float eval(float x) { if (x == 0.0) return 1.0; if (x <= -radius || x >= radius) return 0.0; float pi_x = x * fpi; return radius * sin(pi_x) * sin(pi_x / radius) / (pi_x * pi_x); } };