Add reference code from OIIO.
This commit is contained in:
parent
b0530a2be6
commit
3e05244b95
2 changed files with 1948 additions and 0 deletions
846
docs/filter.cpp
Normal file
846
docs/filter.cpp
Normal file
|
@ -0,0 +1,846 @@
|
|||
/*
|
||||
Copyright 2008 Larry Gritz and the other authors and contributors.
|
||||
All Rights Reserved.
|
||||
Based on BSD-licensed software Copyright 2004 NVIDIA Corp.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the software's owners nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
(This is the Modified BSD License)
|
||||
*/
|
||||
|
||||
|
||||
// Filter results comparison
|
||||
// pow2 downres (4K -> 128 tested)
|
||||
// - katana 2.7.12
|
||||
// - ImageMagick 6.3.6
|
||||
// - prman 16.0 txmake
|
||||
//
|
||||
// box: oiio, prman, katana, imagemagick match
|
||||
// lanczos3: oiio, katana, imagemagick match. prman is far sharper (perhaps lanczos2?)
|
||||
// sinc: oiio, prman match. Katana is slighly softer. imagemagick is much softer
|
||||
// blackman harris: all differ. In order of decreasing sharpness... imagemagick, oiio, prman
|
||||
// catrom: oiio, imagemagick, prman match
|
||||
// gaussian: prman, katana match (gaussian3). imgmagick, oiio are sharper (gaussian2)
|
||||
|
||||
|
||||
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#include <OpenImageIO/fmath.h>
|
||||
#include <OpenImageIO/filter.h>
|
||||
#include <OpenImageIO/dassert.h>
|
||||
|
||||
|
||||
OIIO_NAMESPACE_BEGIN
|
||||
|
||||
// Below are the implementations of several 2D filters. They all
|
||||
// inherit their interface from Filter2D. Each must redefine two
|
||||
// virtual functions:
|
||||
// char *name() Return the filter name
|
||||
// float operator(float,float) Evaluate the filter
|
||||
//
|
||||
|
||||
class FilterBox1D : public Filter1D {
|
||||
public:
|
||||
FilterBox1D (float width) : Filter1D(width) { }
|
||||
~FilterBox1D (void) { }
|
||||
float operator() (float x) const {
|
||||
return (fabsf(x) <= m_w*0.5f) ? 1.0f : 0.0f;
|
||||
}
|
||||
string_view name (void) const { return "box"; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
class FilterBox2D : public Filter2D {
|
||||
public:
|
||||
FilterBox2D (float width, float height) : Filter2D(width,height) { }
|
||||
~FilterBox2D (void) { }
|
||||
float operator() (float x, float y) const {
|
||||
return (fabsf(x) <= m_w*0.5f && fabsf(y) <= m_h*0.5f) ? 1.0f : 0.0f;
|
||||
}
|
||||
bool separable (void) const { return true; }
|
||||
float xfilt (float x) const { return fabsf(x) <= m_w*0.5f ? 1.0f : 0.0f; }
|
||||
float yfilt (float y) const { return fabsf(y) <= m_h*0.5f ? 1.0f : 0.0f; }
|
||||
string_view name (void) const { return "box"; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
class FilterTriangle1D : public Filter1D {
|
||||
public:
|
||||
FilterTriangle1D (float width) : Filter1D(width), m_rad_inv(2.0f/width) { }
|
||||
~FilterTriangle1D (void) { }
|
||||
float operator() (float x) const {
|
||||
return tri1d (x * m_rad_inv);
|
||||
}
|
||||
string_view name (void) const { return "triangle"; }
|
||||
|
||||
static float tri1d (float x) {
|
||||
x = fabsf(x);
|
||||
return (x < 1.0f) ? (1.0f - x) : 0.0f;
|
||||
}
|
||||
private:
|
||||
float m_rad_inv;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class FilterTriangle2D : public Filter2D {
|
||||
public:
|
||||
FilterTriangle2D (float width, float height)
|
||||
: Filter2D(width,height), m_wrad_inv(2.0f/width),
|
||||
m_hrad_inv(2.0f/height) { }
|
||||
~FilterTriangle2D (void) { }
|
||||
float operator() (float x, float y) const {
|
||||
return FilterTriangle1D::tri1d (x * m_wrad_inv)
|
||||
* FilterTriangle1D::tri1d (y * m_hrad_inv);
|
||||
}
|
||||
bool separable (void) const { return true; }
|
||||
float xfilt (float x) const {
|
||||
return FilterTriangle1D::tri1d (x * m_wrad_inv);
|
||||
}
|
||||
float yfilt (float y) const {
|
||||
return FilterTriangle1D::tri1d (y * m_hrad_inv);
|
||||
}
|
||||
string_view name (void) const { return "triangle"; }
|
||||
private:
|
||||
float m_wrad_inv, m_hrad_inv;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class FilterGaussian1D : public Filter1D {
|
||||
public:
|
||||
FilterGaussian1D (float width) : Filter1D(width), m_rad_inv(2.0f/width) { }
|
||||
~FilterGaussian1D (void) { }
|
||||
float operator() (float x) const {
|
||||
return gauss1d (x * m_rad_inv);
|
||||
}
|
||||
static float gauss1d (float x) {
|
||||
x = fabsf(x);
|
||||
return (x < 1.0f) ? fast_exp (-2.0f * (x*x)) : 0.0f;
|
||||
}
|
||||
string_view name (void) const { return "gaussian"; }
|
||||
private:
|
||||
float m_rad_inv;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class FilterGaussian2D : public Filter2D {
|
||||
public:
|
||||
FilterGaussian2D (float width, float height)
|
||||
: Filter2D(width,height), m_wrad_inv(2.0f/width),
|
||||
m_hrad_inv(2.0f/height) { }
|
||||
~FilterGaussian2D (void) { }
|
||||
float operator() (float x, float y) const {
|
||||
return FilterGaussian1D::gauss1d (x * m_wrad_inv)
|
||||
* FilterGaussian1D::gauss1d (y * m_hrad_inv);
|
||||
}
|
||||
bool separable (void) const { return true; }
|
||||
float xfilt (float x) const {
|
||||
return FilterGaussian1D::gauss1d (x * m_wrad_inv);
|
||||
}
|
||||
float yfilt (float y) const {
|
||||
return FilterGaussian1D::gauss1d (y * m_hrad_inv);
|
||||
}
|
||||
string_view name (void) const { return "gaussian"; }
|
||||
private:
|
||||
float m_wrad_inv, m_hrad_inv;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class FilterSharpGaussian1D : public Filter1D {
|
||||
public:
|
||||
FilterSharpGaussian1D (float width) : Filter1D(width), m_rad_inv(2.0f/width) { }
|
||||
~FilterSharpGaussian1D (void) { }
|
||||
float operator() (float x) const {
|
||||
return gauss1d (x * m_rad_inv);
|
||||
}
|
||||
static float gauss1d (float x) {
|
||||
x = fabsf(x);
|
||||
return (x < 1.0f) ? fast_exp (-4.0f * (x*x)) : 0.0f;
|
||||
}
|
||||
string_view name (void) const { return "gaussian"; }
|
||||
private:
|
||||
float m_rad_inv;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class FilterSharpGaussian2D : public Filter2D {
|
||||
public:
|
||||
FilterSharpGaussian2D (float width, float height)
|
||||
: Filter2D(width,height), m_wrad_inv(2.0f/width),
|
||||
m_hrad_inv(2.0f/height) { }
|
||||
~FilterSharpGaussian2D (void) { }
|
||||
float operator() (float x, float y) const {
|
||||
return FilterSharpGaussian1D::gauss1d (x * m_wrad_inv)
|
||||
* FilterSharpGaussian1D::gauss1d (y * m_hrad_inv);
|
||||
}
|
||||
bool separable (void) const { return true; }
|
||||
float xfilt (float x) const {
|
||||
return FilterSharpGaussian1D::gauss1d (x * m_wrad_inv);
|
||||
}
|
||||
float yfilt (float y) const {
|
||||
return FilterSharpGaussian1D::gauss1d (y * m_hrad_inv);
|
||||
}
|
||||
string_view name (void) const { return "gaussian"; }
|
||||
private:
|
||||
float m_wrad_inv, m_hrad_inv;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class FilterCatmullRom1D : public Filter1D {
|
||||
public:
|
||||
FilterCatmullRom1D (float width)
|
||||
: Filter1D(4.0f), m_scale(4.0f/width) { }
|
||||
~FilterCatmullRom1D (void) { }
|
||||
float operator() (float x) const { return catrom1d(x * m_scale); }
|
||||
string_view name (void) const { return "catmull-rom"; }
|
||||
|
||||
static float catrom1d (float x) {
|
||||
x = fabsf(x);
|
||||
float x2 = x * x;
|
||||
float x3 = x * x2;
|
||||
return (x >= 2.0f) ? 0.0f : ((x < 1.0f) ?
|
||||
(3.0f * x3 - 5.0f * x2 + 2.0f) :
|
||||
(-x3 + 5.0f * x2 - 8.0f * x + 4.0f) );
|
||||
}
|
||||
private:
|
||||
float m_scale;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class FilterCatmullRom2D : public Filter2D {
|
||||
public:
|
||||
FilterCatmullRom2D (float width, float height)
|
||||
: Filter2D(width,height), m_wscale(4.0f/width),
|
||||
m_hscale(4.0f/height) { }
|
||||
~FilterCatmullRom2D (void) { }
|
||||
float operator() (float x, float y) const {
|
||||
return FilterCatmullRom1D::catrom1d(x * m_wscale)
|
||||
* FilterCatmullRom1D::catrom1d(y * m_hscale);
|
||||
}
|
||||
bool separable (void) const { return true; }
|
||||
float xfilt (float x) const { return FilterCatmullRom1D::catrom1d(x * m_wscale); }
|
||||
float yfilt (float y) const { return FilterCatmullRom1D::catrom1d(y * m_hscale); }
|
||||
string_view name (void) const { return "catmull-rom"; }
|
||||
private:
|
||||
float m_wscale, m_hscale;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class FilterBlackmanHarris1D : public Filter1D {
|
||||
public:
|
||||
FilterBlackmanHarris1D (float width)
|
||||
: Filter1D(width), m_rad_inv(2.0f/width) { }
|
||||
~FilterBlackmanHarris1D (void) { }
|
||||
float operator() (float x) const {
|
||||
return bh1d (x * m_rad_inv);
|
||||
}
|
||||
string_view name (void) const { return "blackman-harris"; }
|
||||
static float bh1d (float x) {
|
||||
if (x < -1.0f || x > 1.0f) // Early out if outside filter range
|
||||
return 0.0f;
|
||||
// Compute BH. Straight from classic BH paper, but the usual
|
||||
// formula assumes that the filter is centered at 0.5, so scale:
|
||||
x = (x + 1.0f) * 0.5f;
|
||||
const float A0 = 0.35875f;
|
||||
const float A1 = -0.48829f;
|
||||
const float A2 = 0.14128f;
|
||||
const float A3 = -0.01168f;
|
||||
const float m_pi = float (M_PI);
|
||||
#if 0
|
||||
// original -- three cos calls!
|
||||
return A0 + A1 * cosf(2.f * m_pi * x)
|
||||
+ A2 * cosf(4.f * m_pi * x) + A3 * cosf(6.f * m_pi * x);
|
||||
#else
|
||||
// Use trig identintities to reduce to just one cos.
|
||||
// https://en.wikipedia.org/wiki/List_of_trigonometric_identities
|
||||
// cos(2x) = 2 cos^2(x) - 1
|
||||
// cos(3x) = 4 cos^3(x) − 3 cos(x)
|
||||
float cos2pix = cosf(2.f * m_pi * x);
|
||||
float cos4pix = 2.0f * cos2pix * cos2pix - 1.0f;
|
||||
float cos6pix = cos2pix * (2.0f * cos4pix - 1.0f);
|
||||
return A0 + A1 * cos2pix + A2 * cos4pix + A3 * cos6pix;
|
||||
#endif
|
||||
}
|
||||
private:
|
||||
float m_rad_inv;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class FilterBlackmanHarris2D : public Filter2D {
|
||||
public:
|
||||
FilterBlackmanHarris2D (float width, float height)
|
||||
: Filter2D(width,height),
|
||||
m_wrad_inv(2.0f/width), m_hrad_inv(2.0f/height) { }
|
||||
~FilterBlackmanHarris2D (void) { }
|
||||
float operator() (float x, float y) const {
|
||||
return FilterBlackmanHarris1D::bh1d (x*m_wrad_inv)
|
||||
* FilterBlackmanHarris1D::bh1d (y*m_hrad_inv);
|
||||
}
|
||||
bool separable (void) const { return true; }
|
||||
float xfilt (float x) const { return FilterBlackmanHarris1D::bh1d(x*m_wrad_inv); }
|
||||
float yfilt (float y) const { return FilterBlackmanHarris1D::bh1d(y*m_hrad_inv); }
|
||||
string_view name (void) const { return "blackman-harris"; }
|
||||
private:
|
||||
float m_wrad_inv, m_hrad_inv;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class FilterSinc1D : public Filter1D {
|
||||
public:
|
||||
FilterSinc1D (float width) : Filter1D(width), m_rad(width/2.0f) { }
|
||||
~FilterSinc1D (void) { }
|
||||
float operator() (float x) const { return sinc1d (x, m_rad); }
|
||||
string_view name (void) const { return "sinc"; }
|
||||
|
||||
static float sinc1d (float x, float rad) {
|
||||
x = fabsf(x);
|
||||
if (x > rad)
|
||||
return 0.0f;
|
||||
const float m_pi = float (M_PI);
|
||||
return (x < 0.0001f) ? 1.0f : sinf (m_pi*x)/(m_pi*x);
|
||||
}
|
||||
private:
|
||||
float m_rad;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class FilterSinc2D : public Filter2D {
|
||||
public:
|
||||
FilterSinc2D (float width, float height)
|
||||
: Filter2D(width,height),
|
||||
m_wrad(width/2.0f), m_hrad(height/2.0f) { }
|
||||
~FilterSinc2D (void) { }
|
||||
float operator() (float x, float y) const {
|
||||
return FilterSinc1D::sinc1d(x,m_wrad) * FilterSinc1D::sinc1d(y,m_hrad);
|
||||
}
|
||||
bool separable (void) const { return true; }
|
||||
float xfilt (float x) const { return FilterSinc1D::sinc1d(x,m_wrad); }
|
||||
float yfilt (float y) const { return FilterSinc1D::sinc1d(y,m_hrad); }
|
||||
string_view name (void) const { return "sinc"; }
|
||||
private:
|
||||
float m_wrad, m_hrad;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class FilterLanczos3_1D : public Filter1D {
|
||||
public:
|
||||
FilterLanczos3_1D (float width)
|
||||
: Filter1D(width), m_scale(6.0f/width) { }
|
||||
~FilterLanczos3_1D (void) { }
|
||||
float operator() (float x) const {
|
||||
return lanczos3 (x * m_scale);
|
||||
}
|
||||
string_view name (void) const { return "lanczos3"; }
|
||||
|
||||
static float lanczos3 (float x) {
|
||||
const float a = 3.0f; // Lanczos 3 lobe
|
||||
const float ainv = 1.0f / a;
|
||||
const float m_pi = float (M_PI);
|
||||
x = fabsf(x);
|
||||
if (x > a)
|
||||
return 0.0f;
|
||||
if (x < 0.0001f)
|
||||
return 1.0f;
|
||||
#if 0
|
||||
// Full precision, for reference:
|
||||
float pix = m_pi * x;
|
||||
return a/(x*x*(m_pi*m_pi)) * sinf(pix)*sinf(pix*ainv);
|
||||
#elif 0
|
||||
// Use approximate fast_sinphi -- about 0.1% absolute error, but
|
||||
// around 2.5x times faster. BUT when graphed, looks very icky near
|
||||
// f(0).
|
||||
return a/(x*x*(m_pi*m_pi)) * fast_sinpi(x)*fast_sinpi(x*ainv);
|
||||
#else
|
||||
// Compromise: full-precision sin(), but use the trig identity
|
||||
// sin(3x) = -4 sin^3(x) + 3 sin(x)
|
||||
// to make it so only one call to sin is sufficient. This is still
|
||||
// about 1.5x the speed of the reference implementation, but with
|
||||
// no precision compromises.
|
||||
float s1 = sinf(x*ainv*m_pi); // sin(x*pi/a)
|
||||
float s3 = (-4.0f * s1*s1 + 3.0f) * s1; // sin(3*x*pi/a) == sin(x*pi)
|
||||
return a/(x*x*(m_pi*m_pi)) * s1 * s3;
|
||||
#endif
|
||||
}
|
||||
private:
|
||||
float m_scale;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class FilterLanczos3_2D : public Filter2D {
|
||||
public:
|
||||
FilterLanczos3_2D (float width, float height)
|
||||
: Filter2D(width,height), m_wscale(6.0f/width),
|
||||
m_hscale(6.0f/height) { }
|
||||
~FilterLanczos3_2D (void) { }
|
||||
float operator() (float x, float y) const {
|
||||
return FilterLanczos3_1D::lanczos3 (x * m_wscale)
|
||||
* FilterLanczos3_1D::lanczos3 (y * m_hscale);
|
||||
}
|
||||
bool separable (void) const { return true; }
|
||||
float xfilt (float x) const { return FilterLanczos3_1D::lanczos3(x * m_wscale); }
|
||||
float yfilt (float y) const { return FilterLanczos3_1D::lanczos3(y * m_hscale); }
|
||||
string_view name (void) const { return "lanczos3"; }
|
||||
protected:
|
||||
float m_wscale, m_hscale;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class FilterRadialLanczos3_2D : public FilterLanczos3_2D {
|
||||
public:
|
||||
FilterRadialLanczos3_2D (float width, float height)
|
||||
: FilterLanczos3_2D(width,height) { }
|
||||
float operator() (float x, float y) const {
|
||||
x *= m_wscale;
|
||||
y *= m_hscale;
|
||||
return FilterLanczos3_1D::lanczos3(sqrtf(x*x + y*y));
|
||||
}
|
||||
bool separable (void) const { return false; }
|
||||
string_view name (void) const { return "radial-lanczos3"; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
class FilterMitchell1D : public Filter1D {
|
||||
public:
|
||||
FilterMitchell1D (float width) : Filter1D(width), m_rad_inv(2.0f/width) { }
|
||||
~FilterMitchell1D (void) { }
|
||||
float operator() (float x) const {
|
||||
return mitchell1d (x * m_rad_inv);
|
||||
}
|
||||
string_view name (void) const { return "mitchell"; }
|
||||
|
||||
static float mitchell1d (float x) {
|
||||
x = fabsf (x);
|
||||
if (x > 1.0f)
|
||||
return 0.0f;
|
||||
// Computation stright out of the classic Mitchell paper.
|
||||
// In the paper, the range is -2 to 2, so we rescale:
|
||||
x *= 2.0f;
|
||||
float x2 = x*x;
|
||||
const float B = 1.0f/3.0f;
|
||||
const float C = 1.0f/3.0f;
|
||||
const float SIXTH = 1.0f/6.0f;
|
||||
if (x >= 1.0f)
|
||||
return ((-B - 6.0f*C)*x*x2 + (6.0f*B + 30.0f*C)*x2 +
|
||||
(-12.0f*B - 48.0f*C)*x + (8.0f*B + 24.0f*C)) * SIXTH;
|
||||
else
|
||||
return ((12.0f - 9.0f*B - 6.0f*C)*x*x2 +
|
||||
(-18.0f + 12.0f*B + 6.0f*C)*x2 + (6.0f - 2.0f*B)) * SIXTH;
|
||||
}
|
||||
private:
|
||||
float m_rad_inv;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class FilterMitchell2D : public Filter2D {
|
||||
public:
|
||||
FilterMitchell2D (float width, float height)
|
||||
: Filter2D(width,height),
|
||||
m_wrad_inv(2.0f/width), m_hrad_inv(2.0f/height) { }
|
||||
~FilterMitchell2D (void) { }
|
||||
float operator() (float x, float y) const {
|
||||
return FilterMitchell1D::mitchell1d (x * m_wrad_inv)
|
||||
* FilterMitchell1D::mitchell1d (y * m_hrad_inv);
|
||||
}
|
||||
bool separable (void) const { return true; }
|
||||
float xfilt (float x) const {
|
||||
return FilterMitchell1D::mitchell1d (x * m_wrad_inv);
|
||||
}
|
||||
float yfilt (float y) const {
|
||||
return FilterMitchell1D::mitchell1d (y * m_hrad_inv);
|
||||
}
|
||||
string_view name (void) const { return "mitchell"; }
|
||||
private:
|
||||
float m_wrad_inv, m_hrad_inv;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// B-spline filter from Stark et al, JGT 10(1)
|
||||
class FilterBSpline1D : public Filter1D {
|
||||
public:
|
||||
FilterBSpline1D (float width)
|
||||
: Filter1D(width), m_wscale(4.0f/width)
|
||||
{ }
|
||||
~FilterBSpline1D (void) { }
|
||||
float operator() (float x) const {
|
||||
return bspline1d (x*m_wscale);
|
||||
}
|
||||
string_view name (void) const { return "b-spline"; }
|
||||
|
||||
static float bspline1d (float x) {
|
||||
x = fabsf (x);
|
||||
if (x <= 1.0f)
|
||||
return b1 (1.0f-x);
|
||||
else if (x < 2.0f)
|
||||
return b0 (2.0f-x);
|
||||
else return 0.0f;
|
||||
}
|
||||
private:
|
||||
float m_wscale; // width scale factor
|
||||
static float b0 (float t) { return t*t*t / 6.0f; }
|
||||
static float b1 (float t) {
|
||||
return 0.5f * t * (t * (1.0f - t) + 1.0f) + 1.0f/6.0f;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class FilterBSpline2D : public Filter2D {
|
||||
public:
|
||||
FilterBSpline2D (float width, float height)
|
||||
: Filter2D(width,height), m_wscale(4.0f/width), m_hscale(4.0f/height)
|
||||
{ }
|
||||
~FilterBSpline2D (void) { }
|
||||
float operator() (float x, float y) const {
|
||||
return FilterBSpline1D::bspline1d (x * m_wscale)
|
||||
* FilterBSpline1D::bspline1d (y * m_hscale);
|
||||
}
|
||||
bool separable (void) const { return true; }
|
||||
float xfilt (float x) const {
|
||||
return FilterBSpline1D::bspline1d(x*m_wscale);
|
||||
}
|
||||
float yfilt (float y) const {
|
||||
return FilterBSpline1D::bspline1d(y*m_hscale);
|
||||
}
|
||||
string_view name (void) const { return "b-spline"; }
|
||||
private:
|
||||
float m_wscale, m_hscale;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class FilterDisk2D : public Filter2D {
|
||||
public:
|
||||
FilterDisk2D (float width, float height) : Filter2D(width,height) { }
|
||||
~FilterDisk2D (void) { }
|
||||
float operator() (float x, float y) const {
|
||||
x /= (m_w*0.5f);
|
||||
y /= (m_h*0.5f);
|
||||
return ((x*x+y*y) < 1.0f) ? 1.0f : 0.0f;
|
||||
}
|
||||
string_view name (void) const { return "disk"; }
|
||||
};
|
||||
|
||||
|
||||
class FilterCubic1D : public Filter1D {
|
||||
public:
|
||||
FilterCubic1D (float width)
|
||||
: Filter1D(width), m_a(0.0f), m_rad_inv(2.0f / width)
|
||||
{ }
|
||||
~FilterCubic1D (void) { }
|
||||
float operator() (float x) const {
|
||||
return cubic(x * m_rad_inv, m_a);
|
||||
}
|
||||
|
||||
static float cubic (float x, float a) {
|
||||
x = fabsf (x);
|
||||
if (x > 1.0f)
|
||||
return 0.0f;
|
||||
// Because range is -2 to 2, we rescale
|
||||
x *= 2.0f;
|
||||
|
||||
if (x >= 1.0f)
|
||||
return a * (x * (x * (x - 5.0f) + 8.0f) - 4.0f);
|
||||
// return a * x*x*x - 5.0f * a * x*x + 8.0f * a * x - 4.0f * a;
|
||||
else
|
||||
return x*x*((a + 2.0f) * x - (a + 3.0f)) + 1.0f;
|
||||
// return (a + 2.0f) * x*x*x - (a + 3.0f) * x*x + 1.0f;
|
||||
}
|
||||
|
||||
virtual string_view name (void) const { return "cubic"; }
|
||||
protected:
|
||||
float m_a;
|
||||
float m_rad_inv;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class FilterCubic2D : public Filter2D {
|
||||
public:
|
||||
FilterCubic2D (float width, float height)
|
||||
: Filter2D(width,height), m_a(0.0f)
|
||||
, m_wrad_inv(2.0f/width), m_hrad_inv(2.0f/height) { }
|
||||
~FilterCubic2D (void) { }
|
||||
float operator() (float x, float y) const {
|
||||
return FilterCubic1D::cubic(x * m_wrad_inv, m_a)
|
||||
* FilterCubic1D::cubic(y * m_hrad_inv, m_a);
|
||||
}
|
||||
bool separable (void) const { return true; }
|
||||
float xfilt (float x) const {
|
||||
return FilterCubic1D::cubic (x * m_wrad_inv, m_a);
|
||||
}
|
||||
float yfilt (float y) const {
|
||||
return FilterCubic1D::cubic (y * m_hrad_inv, m_a);
|
||||
}
|
||||
virtual string_view name (void) const { return "cubic"; }
|
||||
protected:
|
||||
float m_a;
|
||||
float m_wrad_inv, m_hrad_inv;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class FilterKeys1D : public FilterCubic1D {
|
||||
public:
|
||||
FilterKeys1D (float width) : FilterCubic1D(width) { m_a = -0.5f; }
|
||||
~FilterKeys1D (void) { }
|
||||
virtual string_view name (void) const { return "keys"; }
|
||||
};
|
||||
|
||||
|
||||
class FilterKeys2D : public FilterCubic2D {
|
||||
public:
|
||||
FilterKeys2D (float width, float height) : FilterCubic2D(width,height) { m_a = -0.5f; }
|
||||
~FilterKeys2D (void) { }
|
||||
virtual string_view name (void) const { return "keys"; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
class FilterSimon1D : public FilterCubic1D {
|
||||
public:
|
||||
FilterSimon1D (float width) : FilterCubic1D(width) { m_a = -0.75f; }
|
||||
~FilterSimon1D (void) { }
|
||||
virtual string_view name (void) const { return "simon"; }
|
||||
};
|
||||
|
||||
|
||||
class FilterSimon2D : public FilterCubic2D {
|
||||
public:
|
||||
FilterSimon2D (float width, float height) : FilterCubic2D(width,height) { m_a = -0.75f; }
|
||||
~FilterSimon2D (void) { }
|
||||
virtual string_view name (void) const { return "simon"; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
class FilterRifman1D : public FilterCubic1D {
|
||||
public:
|
||||
FilterRifman1D (float width) : FilterCubic1D(width) { m_a = -1.0f; }
|
||||
~FilterRifman1D (void) { }
|
||||
virtual string_view name (void) const { return "rifman"; }
|
||||
};
|
||||
|
||||
|
||||
class FilterRifman2D : public FilterCubic2D {
|
||||
public:
|
||||
FilterRifman2D (float width, float height) : FilterCubic2D(width,height) { m_a = -1.0f; }
|
||||
~FilterRifman2D (void) { }
|
||||
virtual string_view name (void) const { return "rifman"; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
namespace {
|
||||
FilterDesc filter1d_list[] = {
|
||||
// name dim width fixedwidth scalable separable
|
||||
{ "box", 1, 1, false, true, true },
|
||||
{ "triangle", 1, 2, false, true, true },
|
||||
{ "gaussian", 1, 3, false, true, true },
|
||||
{ "sharp-gaussian", 1, 2, false, true, true },
|
||||
{ "catmull-rom", 1, 4, false, true, true },
|
||||
{ "blackman-harris", 1, 3, false, true, true },
|
||||
{ "sinc", 1, 4, false, true, true },
|
||||
{ "lanczos3", 1, 6, false, true, true },
|
||||
{ "mitchell", 1, 4, false, true, true },
|
||||
{ "bspline", 1, 4, false, true, true },
|
||||
{ "cubic", 1, 4, false, true, true },
|
||||
{ "keys", 1, 4, false, true, true },
|
||||
{ "simon", 1, 4, false, true, true },
|
||||
{ "rifman", 1, 4, false, true, true }
|
||||
};
|
||||
}
|
||||
|
||||
int
|
||||
Filter1D::num_filters ()
|
||||
{
|
||||
return sizeof(filter1d_list)/sizeof(filter1d_list[0]);
|
||||
}
|
||||
|
||||
void
|
||||
Filter1D::get_filterdesc (int filternum, FilterDesc *filterdesc)
|
||||
{
|
||||
ASSERT (filternum >= 0 && filternum < num_filters());
|
||||
*filterdesc = filter1d_list[filternum];
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Filter1D::create is the static method that, given a filter name,
|
||||
// width, and height, returns an allocated and instantiated filter of
|
||||
// the correct implementation. If the name is not recognized, return
|
||||
// NULL.
|
||||
Filter1D *
|
||||
Filter1D::create (string_view filtername, float width)
|
||||
{
|
||||
if (filtername == "box")
|
||||
return new FilterBox1D (width);
|
||||
if (filtername == "triangle")
|
||||
return new FilterTriangle1D (width);
|
||||
if (filtername == "gaussian")
|
||||
return new FilterGaussian1D (width);
|
||||
if (filtername == "sharp-gaussian")
|
||||
return new FilterSharpGaussian1D (width);
|
||||
if (filtername == "catmull-rom" || filtername == "catrom")
|
||||
return new FilterCatmullRom1D (width);
|
||||
if (filtername == "blackman-harris")
|
||||
return new FilterBlackmanHarris1D (width);
|
||||
if (filtername == "sinc")
|
||||
return new FilterSinc1D (width);
|
||||
if (filtername == "lanczos3" || filtername == "lanczos")
|
||||
return new FilterLanczos3_1D (width);
|
||||
if (filtername == "mitchell")
|
||||
return new FilterMitchell1D (width);
|
||||
if (filtername == "b-spline" || filtername == "bspline")
|
||||
return new FilterBSpline1D (width);
|
||||
if (filtername == "cubic")
|
||||
return new FilterCubic1D (width);
|
||||
if (filtername == "keys")
|
||||
return new FilterKeys1D (width);
|
||||
if (filtername == "simon")
|
||||
return new FilterSimon1D (width);
|
||||
if (filtername == "rifman")
|
||||
return new FilterRifman1D (width);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Filter1D::destroy (Filter1D *filt)
|
||||
{
|
||||
delete filt;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static FilterDesc filter2d_list[] = {
|
||||
// name dim width fixedwidth scalable separable
|
||||
{ "box", 2, 1, false, true, true },
|
||||
{ "triangle", 2, 2, false, true, true },
|
||||
{ "gaussian", 2, 3, false, true, true },
|
||||
{ "sharp-gaussian", 2, 2, false, true, true },
|
||||
{ "catmull-rom", 2, 4, false, true, true },
|
||||
{ "blackman-harris", 2, 3, false, true, true },
|
||||
{ "sinc", 2, 4, false, true, true },
|
||||
{ "lanczos3", 2, 6, false, true, true },
|
||||
{ "radial-lanczos3", 2, 6, false, true, false },
|
||||
{ "mitchell", 2, 4, false, true, true },
|
||||
{ "bspline", 2, 4, false, true, true },
|
||||
{ "disk", 2, 1, false, true, false },
|
||||
{ "cubic", 2, 4, false, true, true },
|
||||
{ "keys", 2, 4, false, true, true },
|
||||
{ "simon", 2, 4, false, true, true },
|
||||
{ "rifman", 2, 4, false, true, true }
|
||||
};
|
||||
|
||||
int
|
||||
Filter2D::num_filters ()
|
||||
{
|
||||
return sizeof(filter2d_list)/sizeof(filter2d_list[0]);
|
||||
}
|
||||
|
||||
void
|
||||
Filter2D::get_filterdesc (int filternum, FilterDesc *filterdesc)
|
||||
{
|
||||
ASSERT (filternum >= 0 && filternum < num_filters());
|
||||
*filterdesc = filter2d_list[filternum];
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Filter2D::create is the static method that, given a filter name,
|
||||
// width, and height, returns an allocated and instantiated filter of
|
||||
// the correct implementation. If the name is not recognized, return
|
||||
// NULL.
|
||||
|
||||
Filter2D *
|
||||
Filter2D::create (string_view filtername, float width, float height)
|
||||
{
|
||||
if (filtername == "box")
|
||||
return new FilterBox2D (width, height);
|
||||
if (filtername == "triangle")
|
||||
return new FilterTriangle2D (width, height);
|
||||
if (filtername == "gaussian")
|
||||
return new FilterGaussian2D (width, height);
|
||||
if (filtername == "sharp-gaussian")
|
||||
return new FilterSharpGaussian2D (width, height);
|
||||
if (filtername == "catmull-rom" || filtername == "catrom")
|
||||
return new FilterCatmullRom2D (width, height);
|
||||
if (filtername == "blackman-harris")
|
||||
return new FilterBlackmanHarris2D (width, height);
|
||||
if (filtername == "sinc")
|
||||
return new FilterSinc2D (width, height);
|
||||
if (filtername == "lanczos3" || filtername == "lanczos")
|
||||
return new FilterLanczos3_2D (width, height);
|
||||
if (filtername == "radial-lanczos3" || filtername == "radial-lanczos")
|
||||
return new FilterRadialLanczos3_2D (width, height);
|
||||
if (filtername == "mitchell")
|
||||
return new FilterMitchell2D (width, height);
|
||||
if (filtername == "b-spline" || filtername == "bspline")
|
||||
return new FilterBSpline2D (width, height);
|
||||
if (filtername == "disk")
|
||||
return new FilterDisk2D (width, height);
|
||||
if (filtername == "cubic")
|
||||
return new FilterCubic2D (width, height);
|
||||
if (filtername == "keys")
|
||||
return new FilterKeys2D (width, height);
|
||||
if (filtername == "simon")
|
||||
return new FilterSimon2D (width, height);
|
||||
if (filtername == "rifman")
|
||||
return new FilterRifman2D (width, height);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Filter2D::destroy (Filter2D *filt)
|
||||
{
|
||||
delete filt;
|
||||
}
|
||||
|
||||
|
||||
OIIO_NAMESPACE_END
|
1102
docs/imagebufalgo_xform.cpp
Normal file
1102
docs/imagebufalgo_xform.cpp
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue