Filter 类
class Filter {
public:
// Filter Interface
virtual ~Filter();
Filter(float xw, float yw)
: xWidth(xw), yWidth(yw), invXWidth(1.f / xw), invYWidth(1.f / yw) {
}
virtual float Evaluate(float x, float y) const = 0;
// Filter Public Data
const float xWidth, yWidth;
const float invXWidth, invYWidth;
};
类的作用:
(怎么重构1个Pixel的颜色呢,主要是利用 filter, 在 filter 的范围内的sample都可以贡献自己的 计算出来的颜色给 Pixel,并且 filter还会计算这个Sample的颜色的权重,简单地理解就是,加权平均 filter 范围内的 所有的 sample 的颜色值)
To reconstruct pixel values, we will consider the problem of interpolating the samples
near a particular pixel. To compute a final value for a pixel I (x, y), interpolation results
in computing a weighted average
where L(xi , yi) is the radiance value of the ith sample located at (xi , yi), and f is a filter
function. Figure 7.36 shows a pixel at location (x, y) that has a pixel filter with extent
xWidth in the x direction and yWidth in the y direction. All of the samples inside the
box given by the filter extent may contribute to the pixel’s value, depending on the filter
function’s value for f (x − xi , y − yi).
Figure 7.36: 2D Image Filtering. To compute a filtered pixel value for the pixel marked with a filled
circle located at (x, y), all of the image samples inside the box around (x, y) with extent xWidth
and yWidth need to be considered. Each of the image samples (xi , yi), denoted by open circles, is
weighted by a 2D filter function, f (x − xi , y − yi). The weighted average of all samples is the final
pixel value.
In practice, there is no single best filter function. Choosing the
best one for a particular scene takes a mixture of quantitative(量) evaluation and qualitative(量)
judgment(判断).
Another issue that influences the choice of image filter is that the reconstruction filter can
interact with the sampling pattern in surprising ways. Recall the LDSampler: it generated
an extremely well-distributed low-discrepancy pattern over the area of a single pixel, but
samples in adjacent pixels were placed without regard for the samples in their neighbors.
When used with a box filter, this sampling pattern works extremely well, but when a filter
that both spansmultiple pixels and isn’t a constant value is used, it becomes less effective.
(filter的选择与采样模式有关系)
1. 构造函数
Filter(float xw, float yw)
: xWidth(xw), yWidth(yw), invXWidth(1.f / xw), invYWidth(1.f / yw) {
}
作用:
(在构造函数中,传入 filter的 范围,超过这个 范围的 sample 的权重都是0,这个filter 的在x,y 上的整体范围是
2 * xWidth, 2 * yWidth)
All filters define a width beyond which they have a value of zero; this width may be different
in the x and y directions. The constructor takes these values and stores them along
with their reciprocals, for use by the filter implementations. The filter’s overall extent in
each direction (its support) is twice the value of its corresponding width
2. virtual float Evaluate(float x, float y) const = 0;
作用:
(给 sample 的位置坐标,那么这个方法就计算对这个Sample 相对于 filter 中点 的 权重,主要是计算 sample 的在这个 filter中的权重)
The sole(单独) function that Filter implementations need to provide is Evaluate(). It takes
x and y arguments, which give the position of the sample point relative to the center
of the filter. The return value specifies the weight of the sample. Code elsewhere in the
system will never call the filter function with points outside of the filter’s extent, so filter
implementations don’t need to check for this case.
Box Filter 类
class BoxFilter : public Filter {
public:
BoxFilter(float xw, float yw) : Filter(xw, yw) { }
float Evaluate(float x, float y) const;
};
float BoxFilter::Evaluate(float x, float y) const {
return 1.;
}
类的作用:
(BoxFilter 范围内的所有的sample的权重都是1,但是,尽量避免使用BoxFilter)
The box filter equally weights all samples within a square region of the image. Although
computationally efficient, it’s just about the worst filter possible.
Not only does the box filter do a poor job of reconstructing the function when the frequency
is low, giving a discontinuous result even though the original function was smooth, but it
also does an extremely poor job of reconstruction as the function’s frequency approaches
and passes the Nyquist limit.
TriangleFilter 类
class TriangleFilter : public Filter {
public:
TriangleFilter(float xw, float yw) : Filter(xw, yw) { }
float Evaluate(float x, float y) const;
};
float TriangleFilter::Evaluate(float x, float y) const {
return max(0.f, xWidth - fabsf(x)) *
max(0.f, yWidth - fabsf(y));
}
类的作用:
The triangle filter gives slightly better results than the box: samples at the filter center
have a weight of one, and the weight falls off linearly to the square extent of the filter
Evaluating the triangle filter is simple: the implementation just computes a linear function
based on the width of the filter in both the x and y directions.
GaussianFilter 类
class GaussianFilter : public Filter {
public:
// GaussianFilter Public Methods
GaussianFilter(float xw, float yw, float a)
: Filter(xw, yw), alpha(a), expX(expf(-alpha * xWidth * xWidth)),
expY(expf(-alpha * yWidth * yWidth)) { }
float Evaluate(float x, float y) const;
private:
// GaussianFilter Private Data
const float alpha;
const float expX, expY;
// GaussianFilter Utility Functions
float Gaussian(float d, float expv) const {
return max(0.f, float(expf(-alpha * d * d) - expv));
}
};
类的作用:
Unlike the box and triangle filters, the Gaussian filter gives a reasonably good result in
practice. This filter applies a Gaussian bump that is centered at the pixel and radially
symmetric around it. The Gaussian’s value at the end of its extent is subtracted from the
filter value, in order to make the filter go to zero at its limit.The Gaussian
does tend to cause slight blurring of the final image compared to some of the other filters,
but this blurring can actually help mask any remaining aliasing in the image.
The 1D Gaussian filter function of width w is
where α controls the rate of falloff of the filter. Smaller values cause a slower falloff,
giving a blurrier image. The second term here ensures that the Gaussian goes to zero
at the end of its extent, rather than having an abrupt cliff. For efficiency, the constructor
precomputes the constant term for e^(−αw2)
in each direction.
MitchellFilter 类
class MitchellFilter : public Filter {
public:
// MitchellFilter Public Methods
MitchellFilter(float b, float c, float xw, float yw)
: Filter(xw, yw), B(b), C(c) {
}
float Evaluate(float x, float y) const;
float Mitchell1D(float x) const {
x = fabsf(2.f * x);
if (x > 1.f)
return ((-B - 6*C) * x*x*x + (6*B + 30*C) * x*x +
(-12*B - 48*C) * x + (8*B + 24*C)) * (1.f/6.f);
else
return ((12 - 9*B - 6*C) * x*x*x +
(-18 + 12*B + 6*C) * x*x +
(6 - 2*B)) * (1.f/6.f);
}
private:
const float B, C;
};
类的作用:
Mitchell and Netravali (1988) have developed a family of parameterized filter
functions in order to be able to explore this space in a systematic manner. After analyzing
test subjects’ subjective responses to images filtered with a variety of parameter
values, they developed a filter that tends to do a good job of trading off between ringing
(phantom edges next to actual edges in the image) and blurring (excessively blurred
results)—two common artifacts from poor reconstruction filters.
it does a very
good job with the sinusoidal function, up until the point where the sampling rate isn’t
sufficient to capture the function’s detail.
LanczosSincFilter类
// Sinc Filter Declarations
class LanczosSincFilter : public Filter {
public:
// LanczosSincFilter Public Methods
LanczosSincFilter(float xw, float yw, float t)
: Filter(xw, yw), tau(t) { }
float Evaluate(float x, float y) const;
float Sinc1D(float x) const {
x = fabsf(x);
if (x < 1e-5) return 1.f;
if (x > 1.) return 0.f;
x *= M_PI;
float sinc = sinf(x) / x;
float lanczos = sinf(x * tau) / (x * tau);
return sinc * lanczos;
}
private:
const float tau;
};
float LanczosSincFilter::Evaluate(float x, float y) const {
return Sinc1D(x * invXWidth) * Sinc1D(y * invYWidth);
}
类的作用:
Finally, the LanczosSincFilter class implements a filter based on the sinc function. In
practice, the sinc filter is often multiplied by another function that goes to zero after
some distance. This gives a filter function with finite extent, which is necessary for an
implementation with reasonable performance. An additional parameter τ controls how
many cycles the sinc function passes through before it is clamped to a value of zero,
Figure 7.44 shows a graph of three cycles of the sinc function, along with a graph of the
windowing function we use, which was developed by Lanczos. The Lanczos window is
just the central lobe of the sinc function, scaled to cover the τ cycles:
The windowed sinc filter also does extremely well at reconstructing the sinusoidal function
until prealiasing begins.