// ========================================================== // Upsampling / downsampling filters // // Design and implementation by // - Hervé Drolon (drolon@infonie.fr) // // This file is part of FreeImage 3 // // COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES // THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE // OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED // CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT // THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY // SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL // PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER // THIS DISCLAIMER. // // Use at your own risk! // ========================================================== #ifndef _FILTERS_H_ #define _FILTERS_H_ /** CGenericFilter is a generic abstract filter class used to access to the filter library.
Filters used in this library have been mainly taken from the following references :
Main reference :
Paul Heckbert, C code to zoom raster images up or down, with nice filtering. UC Berkeley, August 1989. [online] http://www-2.cs.cmu.edu/afs/cs.cmu.edu/Web/People/ph/heckbert.html Heckbert references :
*/ class CGenericFilter { protected: #define FILTER_PI double (3.1415926535897932384626433832795) #define FILTER_2PI double (2.0 * 3.1415926535897932384626433832795) #define FILTER_4PI double (4.0 * 3.1415926535897932384626433832795) /// Filter support double m_dWidth; public: /// Constructor CGenericFilter (double dWidth) : m_dWidth (dWidth) {} /// Destructor virtual ~CGenericFilter() {} /// Returns the filter support double GetWidth() { return m_dWidth; } /// Change the filter suport void SetWidth (double dWidth) { m_dWidth = dWidth; } /// Returns F(dVal) where F is the filter's impulse response virtual double Filter (double dVal) = 0; }; // ----------------------------------------------------------------------------------- // Filters library // All filters are centered on 0 // ----------------------------------------------------------------------------------- /** Box filter
Box, pulse, Fourier window, 1st order (constant) b-spline.

Reference :
Glassner A.S., Principles of digital image synthesis. Morgan Kaufmann Publishers, Inc, San Francisco, Vol. 2, 1995 */ class CBoxFilter : public CGenericFilter { public: /** Constructor
Default fixed width = 0.5 */ CBoxFilter() : CGenericFilter(0.5) {} virtual ~CBoxFilter() {} double Filter (double dVal) { return (fabs(dVal) <= m_dWidth ? 1.0 : 0.0); } }; /** Bilinear filter */ class CBilinearFilter : public CGenericFilter { public: CBilinearFilter () : CGenericFilter(1) {} virtual ~CBilinearFilter() {} double Filter (double dVal) { dVal = fabs(dVal); return (dVal < m_dWidth ? m_dWidth - dVal : 0.0); } }; /** Mitchell & Netravali's two-param cubic filter
The parameters b and c can be used to adjust the properties of the cubic. They are sometimes referred to as "blurring" and "ringing" respectively. The default is b = 1/3 and c = 1/3, which were the values recommended by Mitchell and Netravali as yielding the most visually pleasing results in subjective tests of human beings. Larger values of b and c can produce interesting op-art effects--for example, try b = 0 and c = -5.

Reference :
Don P. Mitchell and Arun N. Netravali, Reconstruction filters in computer graphics. In John Dill, editor, Computer Graphics (SIGGRAPH '88 Proceedings), Vol. 22, No. 4, August 1988, pp. 221-228. */ class CBicubicFilter : public CGenericFilter { protected: // data for parameterized Mitchell filter double p0, p2, p3; double q0, q1, q2, q3; public: /** Constructor
Default fixed width = 2 @param b Filter parameter (default value is 1/3) @param c Filter parameter (default value is 1/3) */ CBicubicFilter (double b = (1/(double)3), double c = (1/(double)3)) : CGenericFilter(2) { p0 = (6 - 2*b) / 6; p2 = (-18 + 12*b + 6*c) / 6; p3 = (12 - 9*b - 6*c) / 6; q0 = (8*b + 24*c) / 6; q1 = (-12*b - 48*c) / 6; q2 = (6*b + 30*c) / 6; q3 = (-b - 6*c) / 6; } virtual ~CBicubicFilter() {} double Filter(double dVal) { dVal = fabs(dVal); if(dVal < 1) return (p0 + dVal*dVal*(p2 + dVal*p3)); if(dVal < 2) return (q0 + dVal*(q1 + dVal*(q2 + dVal*q3))); return 0; } }; /** Catmull-Rom spline, Overhauser spline
When using CBicubicFilter filters, you have to set parameters b and c such that
b + 2 * c = 1
in order to use the numerically most accurate filter.
This gives for b = 0 the maximum value for c = 0.5, which is the Catmull-Rom spline and a good suggestion for sharpness.

References :
*/ class CCatmullRomFilter : public CGenericFilter { public: /** Constructor
Default fixed width = 2 */ CCatmullRomFilter() : CGenericFilter(2) {} virtual ~CCatmullRomFilter() {} double Filter(double dVal) { if(dVal < -2) return 0; if(dVal < -1) return (0.5*(4 + dVal*(8 + dVal*(5 + dVal)))); if(dVal < 0) return (0.5*(2 + dVal*dVal*(-5 - 3*dVal))); if(dVal < 1) return (0.5*(2 + dVal*dVal*(-5 + 3*dVal))); if(dVal < 2) return (0.5*(4 + dVal*(-8 + dVal*(5 - dVal)))); return 0; } }; /** Lanczos-windowed sinc filter
Lanczos3 filter is an alternative to CBicubicFilter with high values of c about 0.6 ... 0.75 which produces quite strong sharpening. It usually offers better quality (fewer artifacts) and a sharp image.

*/ class CLanczos3Filter : public CGenericFilter { public: /** Constructor
Default fixed width = 3 */ CLanczos3Filter() : CGenericFilter(3) {} virtual ~CLanczos3Filter() {} double Filter(double dVal) { dVal = fabs(dVal); if(dVal < m_dWidth) { return (sinc(dVal) * sinc(dVal / m_dWidth)); } return 0; } private: double sinc(double value) { if(value != 0) { value *= FILTER_PI; return (sin(value) / value); } return 1; } }; /** 4th order (cubic) b-spline
*/ class CBSplineFilter : public CGenericFilter { public: /** Constructor
Default fixed width = 2 */ CBSplineFilter() : CGenericFilter(2) {} virtual ~CBSplineFilter() {} double Filter(double dVal) { dVal = fabs(dVal); if(dVal < 1) return (4 + dVal*dVal*(-6 + 3*dVal)) / 6; if(dVal < 2) { double t = 2 - dVal; return (t*t*t / 6); } return 0; } }; // ----------------------------------------------------------------------------------- // Window function library // ----------------------------------------------------------------------------------- /** Blackman window */ class CBlackmanFilter : public CGenericFilter { public: /** Constructor
Default width = 0.5 */ CBlackmanFilter (double dWidth = double(0.5)) : CGenericFilter(dWidth) {} virtual ~CBlackmanFilter() {} double Filter (double dVal) { if(fabs (dVal) > m_dWidth) { return 0; } double dN = 2 * m_dWidth + 1; dVal /= (dN - 1); return 0.42 + 0.5*cos(FILTER_2PI*dVal) + 0.08*cos(FILTER_4PI*dVal); } }; #endif // _FILTERS_H_