《Fundamentals of Computer Graphics》第五版 第十章 信号处理

454 阅读9分钟

图形学经常涉及连续变量的函数。表示这种函数的最常用的方法是用函数的样本(samples):只保存一个离散点集上的函数值,需要时再对整个函数重构(reconstruct)。常见的例子有:栅格图、触笔在数字面板上的运动、动作捕捉(motion capture)系统、医用 CT 扫描仪等。对于栅格图,重构可用于放大缩小。

函数的样本表示(sampled representations)应用于很多领域,如数字音频(digital audio)、计算物理等,图形学只是相关算法和数学的使用者之一。从 20 世纪 20 年代开始,采样和重构在通信领域就已经为人所知,到 20 世纪 40 年代,就已经表述为如今所使用的形式。

数字音频:一维采样

1982 年推出的 CD 光盘(compact disc)是采样的第一个广为人知的应用。录音时,麦克风把声音转化为电压,然后存储在某种媒介上;播放时,扬声器将电压转化为声音。

数字录音就是采样:模数转换器(analog-to-digital converter,也称为 A/D converter,简称 ADC)每秒钟测量几千次电压,并将测量结果存储到某种媒介上。播放时,数模转换器(digital-to-analog converter,也称为 D/A converter,简称 DAC)以合适的速率读取数据,并生成相应的电压。

高质量复现录制结果所需的采样频率依赖于声音中的高频成分。为了避免欠采样失真(undersampling artifacts),数字录音机在输入给 ADC 之前,先过滤掉高频信号。为了消除重构失真(reconstruction artifacts),数字音频播放器对 DAC 的输出进行滤波,以保证波形光滑。

digital-audio.png

欠采样失真和重构失真在图形学中也会出现,解决方案也一样:采样前滤波、重构时滤波。下图是采样失真的一个例子:

sampling-artifacts.png

可以看出,如果采样频率较低,高频信号会“伪装”成低频信号,这一现象称为混淆(aliasing)。图像中的混淆通常以莫尔条纹(moire patterns)的形式出现,它源于样本网格和图像中规则特征之间的相互作用。阶梯状直线也是混淆现象的一个例子,这种小尺度特征甚至可以产生大尺度失真。

卷积(Convolution)

卷积是采样、滤波和重构算法的基础。卷积是函数的二元运算,记为 fgf\star g

滑动平均(Moving Averages)

最简单的光滑处理方法是在半径(radius)为 rr 的范围内对函数求平均。对于连续变量的函数:

h(x)=12rxrx+rg(t)dth(x) = \frac{1}{2r}\int_{x-r}^{x+r}g(t)dt

对于离散函数:

c[i]=12r+1j=iri+ra[j]c[i] = \frac{1}{2r + 1}\sum_{j=i-r}^{i+r}a[j]

滑动平均就是卷积的雏形。

离散型卷积(Discrete Convolution)

卷积 aba\star b 就是用序列 bb 对序列 aa 做加权平均:

(ab)[i]=j=+a[j]b[ij](a\star b)[i] = \sum_{j=-\infty}^{+\infty}a[j]b[i-j]

通常在图形学中,两个函数中有一个(假设为 bb支集有限(finite support)。也就是说,存在半径 rr 使得:k>r|k|>r 时,b[k]=0b[k]=0。此时:

(ab)[i]=j=iri+ra[j]b[ij](a\star b)[i] = \sum_{j=i-r}^{i+r}a[j]b[i-j]

伪代码如下:

function convolve(sequence a, filter b, int i)s=0r=b.radiusfor j=ir to i+r dos=s+a[j]b[ij]return s\begin{aligned} &\text{\textbf{function} convolve(sequence $a$, filter $b$, int $i$)} \\ &\quad\begin{aligned} &s = 0 \\ &r = b.\text{radius} \\ &\text{\textbf{for} $j=i-r$ to $i+r$ \textbf{do}} \\ &\quad s = s + a[j]b[i-j] \\ &\textbf{return $s$} \end{aligned} \end{aligned}

卷积的一个重要应用是滤波,前面的滑动平均就是卷积的一个例子,它的滤波器 bb 形式如下:

b[k]={12r+1,rkr0,otherwiseb[k] = \left\{ \begin{aligned} &\frac{1}{2r+1}, &&-r\leqslant k\leqslant r \\ &0, &&\text{otherwise} \end{aligned} \right.

这种滤波器称为箱式滤波器(box filter)。阶梯函数(step function)做箱式滤波后会变成一个线性斜坡形函数。通常约定卷积滤波器的积分(求和)为 11,以保证整体信号强度不受影响。

discrete-convolution-step-function.png

实际上,参与卷积的两个函数是对称的,也就是说,滤波器(filter)和信号(signal)可以互换。除了交换律(commutative law)之外,卷积还满足结合律(associative law)和分配率(distributive law):

ab=ba(ab)c=a(bc)a(b+c)=ab+ac\begin{aligned} a\star b &= b\star a \\ (a\star b)\star c &= a\star (b\star c) \\ a\star(b + c) &= a\star b + a\star c \end{aligned}

离散型恒等滤波器(discrete identity filter)是一种非常简单的滤波器,也称为离散脉冲(discrete impulse):

d[k]=δk0={1,k=00,k0d[k] = \delta_{k0} = \left\{ \begin{aligned} &1, &&k = 0 \\ &0, &&k\neq 0 \end{aligned} \right.

其中,δij\delta_{ij} 是克罗内克符号(Kronecker delta)。

discrete-identity-filter.png

恒等滤波器对信号本身没有任何影响:a=ada=a\star d。信号 aa 在滤波器 bb 过滤前后的差别可以借助 dd 来表示:

aab=a(db)a - a\star b = a\star(d - b)

根据原始定义,卷积还可以看作序列 bb 移位后以 aa 为权重加权求和:

ab=j=+a[j]bja\star b = \sum_{j=-\infty}^{+\infty}a[j]b_{\rightarrow j}

其中,序列 bjb_{\rightarrow j} 是序列 bb 沿正方向移动 jj 后的结果:

bj[i]=b[ij]b_{\rightarrow j}[i] = b[i - j]

sum-shifted-filters.png

连续型卷积(Continuous Convolution)

连续型卷积定义如下:

(fg)(x)=+f(t)g(xt)dt(f\star g)(x) = \int_{-\infty}^{+\infty}f(t)g(x-t)dt

与离散型卷积类似,连续型卷积也可看作滤波器加权的滑动平均,也具有交换律、结合律和分配率。

continueous-convolution.png

连续型卷积也可看作滤波器 gg 移位后的加权求和:

fg=+f(t)gtdtf\star g = \int_{-\infty}^{+\infty}f(t)g_{\rightarrow t}dt

上式就是二元函数 f(t)gt(x)f(t)g_{\rightarrow t}(x) 对变量 tt 积分。

对于下面的箱函数(box function):

f(x)={1,12x<120,otherwisef(x) = \left\{ \begin{aligned} &1, &&-\frac{1}{2}\leqslant x<\frac{1}{2} \\ &0, &&\text{otherwise} \end{aligned} \right.

可以计算:

(ff)(x)={1x,1<x<10,otherwise(f\star f)(x) = \left\{ \begin{aligned} &1 - |x|, &&-1 < x < 1 \\ &0, &&\text{otherwise} \end{aligned} \right.

上式称为帐篷函数(tent function),也是一种常用的滤波器。

连续型卷积中也存在一个特殊的恒等函数(identity function),称为狄拉克脉冲(Dirac impulse)或狄拉克函数(Dirac delta function),定义如下:

{+δ(x)dx=1δ(x)=0,x0\left\{ \begin{aligned} &\int_{-\infty}^{+\infty}\delta(x)dx = 1 \\ &\delta(x) = 0, x\neq 0 \end{aligned} \right.

delta-function.png

狄拉克函数具有挑选性:

+f(x)δ(xx0)dx=f(x0)\int_{-\infty}^{+\infty}f(x)\delta(x-x_{0})dx = f(x_{0})

容易计算 f=fδf = f\star\delta

混合型卷积(Discrete-Continueous Convolution)

连接离散和连续的方式有两种。其一是采样,对连续变量的函数 gg 采样可以得到离散序列 aa

a[i]=g(i)a[i] = g(i)

其二是重构,使用混合型卷积,即,使用连续型滤波器 ff 对离散序列 aa 滤波,可以重构出连续变量的函数:

(af)(x)=i=+a[i]f(xi)(a\star f)(x) = \sum_{i=-\infty}^{+\infty}a[i]f(x - i)

实际上,混合型卷积就是一种特殊的连续型卷积,只要为离散序列配上狄拉克梳(Dirac comb,详见后文),或者用狄拉克梳对原始连续信号 gg 采样,就可以把混合型卷积表示为连续型卷积 af=(s1g)fa\star f=(s_{1}g)\star f,其中 s1s_{1} 是周期为 11 的狄拉克梳。

上式表明 (af)(x)(a\star f)(x) 就是序列 aaxx 附近的加权和。

discrete-continueous-convolution.png

如果滤波器 ff 的半径为 rr,则卷积可以简化为:

(af)(x)=i=xrx+ra[i]f(xi)(a\star f)(x) = \sum_{i=\lceil x-r\rceil}^{\lfloor x+r\rfloor}a[i]f(x - i)

伪代码如下:

function reconstruct(sequence a, filter f, real x)s=0r=f.radiusfor i=xr to x+r dos=s+a[i]f(xi)return s\begin{aligned} &\text{\textbf{function} reconstruct(sequence $a$, filter $f$, real $x$)} \\ &\quad\begin{aligned} &s = 0 \\ &r = f.\text{radius} \\ &\text{\textbf{for} $i=\lceil x-r\rceil$ to $\lfloor x+r\rfloor$ \textbf{do}} \\ &\quad s = s + a[i]f(x-i) \\ &\textbf{return $s$} \end{aligned} \end{aligned}

混合型卷积也可以看作滤波器移位之和:

af=i=+a[i]fia\star f = \sum_{i=-\infty}^{+\infty}a[i]f_{\rightarrow i}

高维卷积

采样算法和相关理论可以直接推广到高维,下面以二维为例进行说明。

二维离散型卷积:

(ab)[i,j]=i=+j=+a[i,j]b[ii,jj](a\star b)[i, j] = \sum_{i'=-\infty}^{+\infty}\sum_{j'=-\infty}^{+\infty}a[i', j']b[i-i', j-j']

如果滤波器 bb 支集有限,且半径为 rr,则可以简化为:

(ab)[i,j]=i=iri+rj=jrj+ra[i,j]b[ii,jj](a\star b)[i, j] = \sum_{i'=i-r}^{i+r}\sum_{j'=j-r}^{j+r}a[i', j']b[i-i', j-j']

伪代码如下:

function convolve2d(sequence2d a, filter2d b, int i, int j)s=0r=b.radiusfor i=ir to i+r dofor j=jr to j+r dos=s+a[i][j]b[ii][jj]return s\begin{aligned} &\text{\textbf{function} convolve2d(sequence2d $a$, filter2d $b$, int $i$, int $j$)} \\ &\quad\begin{aligned} &s = 0 \\ &r = b.\text{radius} \\ &\text{\textbf{for} $i'=i-r$ to $i+r$ \textbf{do}} \\ &\quad\begin{aligned} &\text{\textbf{for} $j'=j-r$ to $j+r$ \textbf{do}} \\ &\quad s = s + a[i'][j']b[i-i'][j-j'] \end{aligned} \\ &\textbf{return}\ s \end{aligned} \end{aligned}

二维连续型卷积:

(fg)(x,y)=x=+y=+f(x,y)g(xx,yy)dxdy(f\star g)(x, y) = \int_{x'=-\infty}^{+\infty}\int_{y'=-\infty}^{+\infty}f(x', y')g(x-x', y-y')dx'dy'

二维混合型卷积:

(af)(x,y)=i=+j=+a[i,j]f(xi,yj)(a\star f)(x, y) = \sum_{i=-\infty}^{+\infty}\sum_{j=-\infty}^{+\infty}a[i, j]f(x-i, y-j)

与一维情形类似,二维卷积可以理解为在一个区域内对输入加权平均,滤波器决定了权重。

卷积滤波器(Convolution Filters)

本节主要介绍图形学中常用的滤波器,这些滤波器都有一个自然半径(natural radius),它是信号采样和重构的默认尺寸。

任何滤波器 ff 都可以定义相应的伸缩版本:

fs(x)=f(x/s)sf_{s}(x) = \frac{f(x/s)}{s}

fsf_{s} 是将 ff 水平拉伸 ss 倍,再垂直压缩为原有的 1/s1/s 之后的结果。如果 ff 的自然半径是 rr,那么 fsf_{s} 的半径就是 srsr

常用的卷积滤波器

箱式滤波器(Box Filter)

箱式滤波器是一个分段常函数。离散型箱式滤波器:

abox,r[i]={1/(2r+1),ir0,otherwisea_{\text{box}, r}[i] = \left\{ \begin{aligned} &1/(2r+1), &&|i|\leqslant r \\ &0, &&\text{otherwise} \end{aligned} \right.

连续型箱式滤波器:

fbox,r(x)={1/(2r),rx<r0,otherwisef_{\text{box}, r}(x) = \left\{ \begin{aligned} &1/(2r), &&-r\leqslant x<r \\ &0, &&\text{otherwise} \end{aligned} \right.

由于箱式滤波器有间断点,因此边界(boundary)的处理至关重要。之所以约定连续型箱式滤波器只取一个端点,即 fbox,r(r)=1/(2r)f_{\text{box}, r}(-r)=1/(2r)fbox,r(r)=0f_{\text{box}, r}(r)=0,是为了避免重构函数时覆盖的点数发生突变。一般约定箱式滤波器的自然半径为 r=1/2r=1/2,此时的箱式滤波器记为 fboxf_{\text{box}}

continueous-box-filter.png

帐篷式滤波器(Tent Filter)

帐篷式滤波器,也称为线性滤波器(linear filter),是一个分段线性函数:

ftent(x)={1x,x<10,otherwisef_{\text{tent}}(x) = \left\{ \begin{aligned} &1-|x|, &&|x|<1 \\ &0, &&\text{otherwise} \end{aligned} \right.

自然半径约定为 11

tent-filter.png

C0C^{0} 类(即连续函数)滤波器无需区分离散型和连续型,离散型滤波器就是连续型滤波器的采样。

高斯滤波器(Gaussian Filter)

高斯函数(Gaussian function),又名正态分布(normal distribution),是一种在理论和应用上都很重要的滤波器:

fg,σ(x)=1σ2πex2/2σ2f_{g, \sigma}(x) = \frac{1}{\sigma\sqrt{2\pi}}e^{-x^{2}/2\sigma^{2}}

参数 σ\sigma 称为标准差(standard deviation)。高斯滤波器没有任何特殊的自然半径。实际应用中,常把超出半径 rr 的尾部截断,所得结果称为截断高斯函数(trimmed Gaussian function),σ\sigmarr 是滤波器的参数。而伸缩变换只会改变参数 σ\sigmarr,不会产生新的滤波器。滤波器的宽度和自然半径依赖于具体应用场景。

通常,σ=1\sigma=1r=3r=3 是一个好的切入点。

Gaussian-filter.png

三次 B 样条滤波器(B-Spline Cubic Filter)

很多滤波器都定义为分段多项式。自然半径为 22 的四段三次滤波器常用于信号重构,B 样条滤波器就是其中之一:

fB(x)=16{3(1x)3+3(1x)2+3(1x)+1,x1(2x)3,1<x20,otherwisef_{B}(x) = \frac{1}{6} \left\{ \begin{aligned} &-3(1-|x|)^{3} + 3(1-|x|)^{2} + 3(1-|x|) + 1, &&|x|\leqslant 1 \\ &(2-|x|)^{3}, &&1<|x|\leqslant 2 \\ &0, &&\text{otherwise} \end{aligned} \right.

B 样条滤波器是 C2C^{2} 函数,即二阶导数连续。除了上式,B 样条滤波器还有一种更简洁的定义:fB=fboxfboxfboxfboxf_{B}=f_{\text{box}}\star f_{\text{box}}\star f_{\text{box}}\star f_{\text{box}}

B-Spline-filter.png

三次 Catmull-Rom 滤波器(Catmull-Rom Cubic Filter)

Catmull-Rom 滤波器也是一种分段三次样条滤波器:

fC(x)=12{3(1x)3+4(1x)2+(1x),x1(2x)3(2x)2,1<x20,otherwisef_{C}(x) = \frac{1}{2} \left\{ \begin{aligned} &-3(1-|x|)^{3} + 4(1-|x|)^{2} + (1-|x|), &&|x|\leqslant 1 \\ &(2-|x|)^{3} - (2-|x|)^{2}, &&1<|x|\leqslant 2 \\ &0, &&\text{otherwise} \end{aligned} \right.

Catmull-Rom-filter.png

三次 Mitchell-Netravali 滤波器(Mitchell-Netravali Cubic Filter)

Mitchell-Netravali 滤波器是前两种滤波器的加权组合:

fM(x)=13fB(x)+23fC(x)=118{21(1x)3+27(1x)2+9(1x)+1,x17(2x)36(2x)2,1<x20,otherwise\begin{aligned} f_{M}(x) &= \frac{1}{3}f_{B}(x) + \frac{2}{3}f_{C}(x) \\ &= \frac{1}{18} \left\{ \begin{aligned} &-21(1-|x|)^{3} + 27(1-|x|)^{2} + 9(1-|x|) + 1, &&|x|\leqslant 1 \\ &7(2-|x|)^{3} - 6(2-|x|)^{2}, &&1<|x|\leqslant 2 \\ &0, &&\text{otherwise} \end{aligned} \right. \end{aligned}

Mitchell-Netravali-filter.png

滤波器的性质

脉冲响应(impulse response)就是滤波器对脉冲信号的响应。由于脉冲信号是卷积运算中的恒等函数,因此脉冲响应其实就是滤波器的别名。

当连续型滤波器被用于信号重构时,如果重构前后样本点处的值保持不变——重构后的函数把样本点串了起来,则称这种滤波器为插值滤波器(interpolating filter)。容易知道,插值滤波器就是满足如下条件的滤波器:

{f(0)=1f(i)=0, i0\left\{ \begin{aligned} &f(0) = 1 \\ &f(i) = 0,\ \forall i\neq 0 \end{aligned} \right.

interpolating-filter.png

对于有负值的滤波器,当原始信号急剧变化时,过滤后的信号会出现振荡(ringing)或过冲(overshoot)。

overshoot.png

能把常数序列重构为常函数的连续型滤波器称为无波纹的(ripple free)。无波纹滤波器的数学表述如下:

i=+f(x+i)=1, xR\sum_{i=-\infty}^{+\infty}f(x + i) = 1,\ \forall x\in\mathbb{R}

ripple.png

除了高斯滤波器,上一小节中列举的所有常用滤波器在自然半径下都是无波纹的。但是在非自然半径下,都有可能出现波纹。在混合型卷积中消除波纹的一种简单方法是除以权重和:

(af)(x)=i=+a[i]f(xi)i=+f(xi)=(afˉ)(x)fˉ(x)=f(x)i=+f(xi)\begin{gathered} (\overline{a\star f})(x) = \frac{\displaystyle\sum_{i=-\infty}^{+\infty}a[i]f(x-i)}{\displaystyle\sum_{i=-\infty}^{+\infty}f(x-i)} = (a\star \bar{f})(x) \\ \bar{f}(x) = \frac{f(x)}{\displaystyle\sum_{i=-\infty}^{+\infty}f(x-i)} \end{gathered}

不同的连续型滤波器可能有不同的连续程度(degree of continuity),连续程度一般用最高阶连续导数来表述:具有 nn 阶连续导数的函数称为 CnC^{n} 类函数。

可分离滤波器

二维滤波器有时直接使用二元函数来定义,但大多数情况下,都是用已知的一维滤波器来构造二维滤波器。最常用的是可分离滤波器(separable filter):

f2(x,y)=f1(x)f1(y)b2[i,j]=b1[i]b1[j]\begin{gathered} f_{2}(x, y) = f_{1}(x)f_{1}(y) \\ b_{2}[i, j] = b_{1}[i]b_{1}[j] \end{gathered}

相比于其它二维滤波器,可分离滤波器更加高效。对于离散型卷积,容易知道:

(ab2)[i,j]=i=+b1[ii]Sj[i]Sj[i]=j=+a[i,j]b1[jj]\begin{gathered} (a\star b_{2})[i, j] = \sum_{i'=-\infty}^{+\infty}b_{1}[i-i']S_{j}[i'] \\ S_{j}[i'] = \sum_{j'=-\infty}^{+\infty}a[i', j']b_{1}[j-j'] \end{gathered}

利用上式,可以先计算 Sj[i]S_{j}[i] 并存储起来,然后再使用这些值计算卷积,这对大型滤波器有重要意义。通常,半径为 rr 的滤波器对图像滤波时,每个像素平均需要计算 (2r+1)2(2r+1)^{2} 次乘法。如果使用上面的方法,则每个像素计算 2(2r+1)2(2r+1) 次乘法即可,当然,代价是更多的存储空间。可分离滤波器让渐进复杂度由 O(r2)O(r^{2}) 变成了 O(r)O(r),这让大型滤波器的使用成为可能。上述算法的伪代码如下:

function filterImage(image I, filter b)r=b.radiusnx=I.widthny=I.heightallocate storage array S[0,,nx1]allocate image Iout[r,,nxr1;r,,nyr1]initialize S and Iout to all zerofor j=r to nyr1 dofor i=0 to nx1 doS[i]=0for j=jr to j+r doS[i]=S[i]+I[i,j]b[jj]for i=r to nxr1 dofor i=ir to i+r doIout[i,j]=Iout[i,j]+S[i]b[ii]return Iout\begin{aligned} &\text{\textbf{function} filterImage(image $I$, filter $b$)} \\ &\quad\begin{aligned} &r=b.\text{radius} \\ &n_{x}=I.\text{width} \\ &n_{y}=I.\text{height} \\ &\text{allocate storage array}\ S[0,\cdots,n_{x}-1] \\ &\text{allocate image}\ I_{\text{out}}[r,\cdots,n_{x}-r-1;r,\cdots,n_{y}-r-1] \\ &\text{initialize $S$ and $I_{\text{out}}$ to all zero} \\ &\textbf{for}\ j=r\ \text{to}\ n_{y}-r-1\ \textbf{do} \\ &\quad\begin{aligned} &\textbf{for}\ i'=0\ \text{to}\ n_{x}-1\ \textbf{do} \\ &\quad\begin{aligned} &S[i']=0 \\ &\textbf{for}\ j'=j-r\ \text{to}\ j+r\ \textbf{do} \\ &\quad S[i']=S[i']+I[i',j']b[j-j'] \end{aligned} \\ &\textbf{for}\ i=r\ \text{to}\ n_{x}-r-1\ \textbf{do} \\ &\quad\begin{aligned} &\textbf{for}\ i'=i-r\ \text{to}\ i+r\ \textbf{do} \\ &\quad I_{\text{out}}[i,j]=I_{\text{out}}[i,j]+S[i']b[i-i'] \end{aligned} \end{aligned} \\ &\textbf{return}\ I_{\text{out}} \end{aligned} \end{aligned}

为说明主要问题,上述伪代码没有处理图像边界。

图像信号处理

信号处理在图形学中最重要、最常见的应用场景就是图像处理。

使用离散滤波器做图像滤波

卷积滤波是图像处理软件中最广泛使用的功能。图像的模糊化(blurring)可以借助常用的低通滤波器(low-pass filter)来实现。高斯滤波器模糊处理得非常光滑,也最常用。

image-blurring.png

图像锐化(sharpening)——模糊化的逆操作——可以使用钝化蒙层(unsharp mask)来实现,即,在原始图像上减掉模糊化图像,然后再重新标度(rescaling)以保证整体亮度不变:

Isharp=(1+α)Iα(Ifg,σ)=I((1+α)dαfg,σ)=Ifsharp(σ,α)\begin{aligned} I_{\text{sharp}} &= (1 + \alpha)I - \alpha(I\star f_{g, \sigma}) \\ &= I\star((1 + \alpha)d - \alpha f_{g, \sigma}) \\ &= I\star f_{\text{sharp}}(\sigma, \alpha) \end{aligned}

其中,fg,σf_{g, \sigma} 是宽度为 σ\sigma 的高斯滤波器。

image-sharpening.png

阴影(drop shadow)可以借助模糊移位拷贝来实现。移位后模糊化可以表示为:

Ishadow=(Idm,n)fg,σ=I(dm,nfg,σ)=Ifshadow(m,n,σ)\begin{aligned} I_{\text{shadow}} &= (I\star d_{m, n})\star f_{g, \sigma} \\ &= I\star (d_{m, n}\star f_{g, \sigma}) \\ &= I\star f_{\text{shadow}}(m, n, \sigma) \end{aligned}

其中,偏心脉冲(off-center impulse):

dm,n(i,j)={1,i=m and j=n0,otherwise=δimδjn\begin{aligned} d_{m, n}(i, j) &= \left\{ \begin{aligned} &1, &&i=m\ \text{and}\ j=n \\ &0, &&\text{otherwise} \end{aligned} \right. \\ &=\delta_{im}\delta_{jn} \end{aligned}

容易知道,移位操作(shifting operation)就是用偏心脉冲做卷积。

drop-shadow.png

图像采样抗锯齿

图像合成(image synthesis)中经常需要根据连续模型生成图像的样本表示,也就是在二维规则点阵上对连续信号采样。如果不做任何处理,则会产生各种混淆失真(aliasing artifacts),比如,锯齿(jaggies)——图像中锐利边界上的阶梯状失真,莫尔图案(moire patterns)——有重复图案的区域中出现的宽条带。

aliasing-artifacts-in-images.png

问题的根源在于图像本身包含了太多的小尺度特征,因此必须在采样前光滑滤波。高斯滤波器可以有效地消除莫尔图案,但却让整体上更模糊。这说明,滤波器的选择需要在锐度(sharpness)和混淆之间权衡。

filtering-before-sampling.png

重构(reconstruction)与重采样(resampling)

重采样(resampling),即改变采样率(sample rate)或图像尺寸,是一种最常见的应用滤波的图像操作。

缩小图像尺寸的一种简单方法是像素删减(pixel dropping),即在每个点附近都删掉几个像素以适应新的图像尺寸。这种方法速度很快,但生成的图像质量较低,可用作预览(preview)。

resampling.png

调整图像大小本质上就是重采样:根据输入样本重构出一个连续变量的函数,然后在新的图像尺寸下对其采样。由于卷积具有结合律,因此可以将重构滤波器和采样滤波器合成之后再对输入信号做卷积,合成后的滤波器称为重采样滤波器(resampling filter)。例如,像素删减算法——选取输入图像中距离最近的样本点的值作为输出值,其实就完全等价于用宽度为 11 的箱式滤波器对输入图像重构,然后再点采样(point-sampling)。

resampling-filter.png

图像重采样时,通常需要指定原图像单位下的一个源矩形(source rectangle)(xl,xh)×(yl,yh)(x_{l},x_{h})\times(y_{l},y_{h}),它表示原图像中想要保留的部分,借此可将新图像中样本间距表示为 Δx=(xhxl)/nxnew\Delta x=(x_{h}-x_{l})/n_{x}^{\text{new}}Δy=(yhyl)/nynew\Delta y=(y_{h}-y_{l})/n_{y}^{\text{new}}。为了简化讨论,下面仅给出一维情形的伪代码,其中 ff 是重采样滤波器:

function resample(sequence a, float xl, float xh, int n, filter f)create sequence b of length nr=f.radiusx0=xl+Δx/2for i=0 to n1 dos=0x=x0+iΔxfor j=xr to x+r dos=s+a[j]f(xj)b[i]=sreturn b\begin{aligned} &\text{\textbf{function} resample(sequence $a$, float $x_{l}$, float $x_{h}$, int $n$, filter $f$)} \\ &\quad\begin{aligned} &\text{create sequence $b$ of length $n$} \\ &r = f.\text{radius} \\ &x_{0} = x_{l} + \Delta x/2 \\ &\text{\textbf{for} $i=0$ to $n-1$ \textbf{do}} \\ &\quad\begin{aligned} &s = 0 \\ &x = x_{0} + i\Delta x \\ &\text{\textbf{for} $j=\lceil x-r\rceil$ to $\lfloor x+r\rfloor$ \textbf{do}} \\ &\quad s = s + a[j]f(x-j) \\ &b[i] = s \end{aligned} \\ &\textbf{return}\ b \end{aligned} \end{aligned}

上述伪代码包含了图像重采样的所有基本内容,剩下的唯一问题是图像边缘的处理,下面有三种常见的处理方式:

  • 越过边界时停止循环。这等价于将图像沿所有边界以零信号向外延伸。
  • 把数组的越界访问裁剪到边界。这等价于把图像边缘的最后一行和最后一列向外延伸。
  • 接近信号序列的边界时,修改滤波器以保证不会越界。

用第一种方法处理图像时会产生暗淡边缘(dim edge)。第二种方法容易实现,但第三种方法效果最好。在图像边缘修正滤波器的最简单的方法是重新归一化(renormalize):在图像内部对滤波器归一化。这可以保持图像亮度。为了考虑性能,可能还需要把图像中心和图像边缘分开处理。

滤波器的选择对于重采样至关重要。这里主要涉及两个问题:滤波器的形状和尺寸。为了实现信号重构,滤波器应尽可能光滑以避免混淆失真,而且应该是无波纹的。为了对信号采样,滤波器的尺寸应足够大以避免欠采样(undersampling),而且足够光滑以避免莫尔失真。

filter-size.png

通常会选择一种滤波器形状,然后根据输入、输出的相对分辨率来伸缩滤波器。较小的分辨率决定了滤波器的尺寸。当图像缩小时,即降采样(downsampling),信号采样所需的光滑度高于信号重构,因此用输出信号样本间距作为滤波器尺寸。当图像放大时,即增采样(upsampling),信号重构所需的光滑度起主导作用,滤波器的尺寸由输入信号样本间距决定。

滤波器的选择需要在速度和质量之间权衡。常用的有:箱式滤波器——速度至上、帐篷式滤波器——中等质量、分段三次滤波器——高质量。分段三次滤波器的光滑度可以通过对 fBf_{B}fCf_{C} 插值来调节,Mitchell-Netravali 滤波器是一个好的选择。

和图像滤波类似,可分离滤波器同样可以显著地加速重采样。基本想法是先做行重采样,生成一个宽变高不变的图像,再做列重采样。

separable-resampling.png

采样理论

采样理论可以为采样和重构提供深刻的理解。

傅里叶变换(The Fourier Transform)

傅里叶变换和卷积是采样理论中最重要的数学概念。傅里叶变换就是把函数表示为不同频率的平面波叠加。周期函数可以表示为傅里叶级数(Fourier series)。而非周期函数可以表示为:

f(x)=+f^(u)ei2πuxduf(x) = \int_{-\infty}^{+\infty}\hat{f}(u)e^{i2\pi ux}du

周期函数也可以用傅里叶变换来表示,只不过要在傅里叶级数展开系数上配一个狄拉克函数。

上式也称为傅里叶逆变换(inverse Fourier transform,简称 IFT)。其中,傅里叶变换((forward) Fourier transform,简称 FT)f^\hat{f}

f^(u)=+f(x)ei2πuxdx\hat{f}(u) = \int_{-\infty}^{+\infty}f(x)e^{-i2\pi ux}dx

f^\hat{f} 是一个复函数,函数值的幅角包含了相应频率的相位信息,它的大小称为傅里叶谱(Fourier spectrum)。由于傅里叶变换和逆变换的对称性,可以将它们看作是同一种操作。有时采用符号 F{f}\mathcal{F}\{f\} 表示 ff 的傅里叶变换,F1{f^}\mathcal{F}^{-1}\{\hat{f}\} 表示 f^\hat{f} 的傅里叶逆变换。

傅里叶变换具有以下性质:

  1. 傅里叶变换是线性变换

    F{αf+βg}=αf^+βg^,  constants α,β\mathcal{F}\{\alpha f + \beta g\} = \alpha\hat{f} + \beta\hat{g},\ \forall\ \text{constants}\ \alpha, \beta
  2. 借助狄拉克函数的傅里叶变换可以证明帕塞瓦尔定理(Parseval's theorem)

    +f(x)2dx=+f^(u)2du\int_{-\infty}^{+\infty}|f(x)|^{2}dx = \int_{-\infty}^{+\infty}|\hat{f}(u)|^{2}du

    其物理含义是实空间和频率空间所观测到的能量相等。

    Parseval-theorem.png

  3. 相似性定理

    F{f(x/b)}=bf^(bu), bR\mathcal{F}\{f(x/b)\} = b\hat{f}(bu),\ \forall b\in\mathbb{R}

    similarity-theorem.png

  4. f^(0)\hat{f}(0) 代表信号的零频分量,可以理解为 ff 的平均值。

  5. 借助欧拉公式容易知道,如果 ff 是实函数,那么 Ref^\mathrm{Re}\hat{f} 是偶函数,Imf^\mathrm{Im}\hat{f} 是奇函数,f^=(Ref^)2+(Imf^)2|\hat{f}|=\sqrt{(\mathrm{Re}\hat{f})^{2}+(\mathrm{Im}\hat{f})^{2}} 是偶函数。如果 ff 是偶的实函数,那么 f^\hat{f} 是实函数。

  6. 卷积定理:卷积的傅里叶变换等于傅里叶变换的乘积,乘积的傅里叶变换等于傅里叶变换的卷积。

    F{fg}=f^g^F{fg}=f^g^\begin{gathered} \mathcal{F}\{f\star g\} = \hat{f}\hat{g} \\ \mathcal{F}\{fg\} = \hat{f}\star\hat{g} \end{gathered}

    正因为这些,傅里叶变换在采样和重构的研究中很有用。傅里叶变换提供了频率视角来看待采样、滤波和重构。

常见的傅里叶变换

箱式滤波器的傅里叶变换:

F{fbox}=sinπuπu=sinc πu\mathcal{F}\{f_{\text{box}}\} = \frac{\sin \pi u}{\pi u} = \mathrm{sinc}\ \pi u

借助和箱式滤波器之间的关系,帐篷式滤波器、三次 B 样条滤波器的傅里叶变换为:

F{ftent}=sin2πuπ2u2=sinc2πuF{fB}=sin4πuπ4u4=sinc4πu\begin{gathered} \mathcal{F}\{f_{\text{tent}}\} = \frac{\sin^{2}\pi u}{\pi^{2}u^{2}} = \mathrm{sinc}^{2}\pi u \\ \mathcal{F}\{f_{\text{B}}\} = \frac{\sin^{4}\pi u}{\pi^{4}u^{4}} = \mathrm{sinc}^{4}\pi u \end{gathered}

借助一点复变函数的知识可以知道高斯函数的傅里叶变换:

F{fg,σ}=e2π2σ2u2\mathcal{F}\{f_{g, \sigma}\} = e^{-2\pi^{2}\sigma^{2}u^{2}}

Gallery-Fourier-transform.png

采样理论中的狄拉克脉冲

狄拉克函数可用于对连续变量函数采样。位置 aa、值为 bb 的样本点可以表示为 bδ(xa)b\delta(x-a)。而采样则可以表示为原始信号与脉冲序列(impulse train)的乘积。脉冲序列,也称为狄拉克梳(Dirac comb):

sT(x)=n=+δ(xTn)s_{T}(x) = \sum_{n=-\infty}^{+\infty}\delta(x - Tn)

狄拉克梳的傅里叶级数和傅里叶变换分别为:

sT(x)=1Tk=+ei2π(k/T)xF{sT}=1Tk=+δ(uk/T)=1Ts1/T(u)\begin{gathered} s_{T}(x) = \frac{1}{T}\sum_{k=-\infty}^{+\infty}e^{i2\pi(k/T)x} \\ \mathcal{F}\{s_{T}\} = \frac{1}{T}\sum_{k=-\infty}^{+\infty}\delta(u - k/T) = \frac{1}{T}s_{1/T}(u) \end{gathered}

上式所表达含义是,如果采样周期是简谐波周期的整数倍,则求和发散为无穷大;否则,求和收敛为零。

dirac-comb.png

采样与混淆

傅里叶变换让卷积滤波器对信号的作用更加清晰。对于连续信号,一般包含各种频率成分,而且大多集中在零频附近,频率越高强度越弱。对连续信号 ff 的采样可以表示为 fsTfs_{T},它的傅里叶变换:

F{fsT}=f^sT^=1Tf^s1/T\mathcal{F}\{fs_{T}\} = \hat{f}\star\widehat{s_{T}} = \frac{1}{T}\hat{f}\star s_{1/T}

又因为,任一函数 gg 和移位狄拉克函数 δx0\delta_{\rightarrow x_{0}} 的卷积等价于对函数的移位:

gx0=gδx0g_{\rightarrow x_{0}} = g\star \delta_{\rightarrow x_{0}}

因此:

(1Tf^s1/T)(u)=1Tk=+f^(uk/T)\left(\frac{1}{T}\hat{f}\star s_{1/T}\right)(u) = \frac{1}{T}\sum_{k=-\infty}^{+\infty}\hat{f}(u - k/T)

也就是说,样本信号(sampled signal)包含了原始信号谱的无穷多个等距复本。这是因为,对于低频信号的样本点,总可以找到更高频的简谐波穿过它们,因此样本信号谱中包含了这些高频混淆信息。上式中原始信号谱称为基谱(base spectrum),那些高频复本称为混淆谱(alias spectra)。

alias-spectra.png

当采样频率较低时,这些信号谱中的复本互相交叠,不同频率的信息被不可逆地混合起来,于是便出现了第一种混淆——源于欠采样(undersampling)的混淆。

根据卷积定理,重构信号谱其实就是样本信号谱与滤波器谱的乘积。重构信号谱包含两部分:基谱和衰减的混淆谱。如果重构滤波器的谱较宽,比如最近邻重构(nearest-neighbor reconstruction)——使用宽度为 11 的箱式滤波器,混淆谱强度较为显著,于是便出现了第二种混淆——不充分的重构滤波器所带来的混淆,这些混淆成分在图像中通常表现为方形图案。

避免采样混淆

为了提高采样和重构的质量,必须适当地选择滤波器。采样前使用低通滤波器对信号滤波,以及提高采样频率,都是为了尽可能地避免混淆谱和基谱的交叠。实际上,采样的基本准则就是信号谱宽必须小于混淆谱和基谱的间距,也就是说,信号的截止频率必须小于采样频率的一半,这也被称为奈奎斯特准则(Nyquist criterion),所允许的信号最高频率称为奈奎斯特频率(Nyquist frequency)或奈奎斯特极限(Nyquist limit)。奈奎斯特-香农采样定理(Nyquist-Shannon sampling theorem)可以表述为:频率不超过奈奎斯特极限的信号原则上可以从样本中精确重构出来。

higher-sample-rates.png

避免重构混淆

重构滤波器的目的是在保持基谱的前提下消除混淆谱。合理的重构滤波器,首先是低通滤波器,其次还应该满足,在采样频率整数倍的位置取值为零,这等价于滤波器无波纹。重构滤波器在消除混淆谱的同时,也会让基谱变得光滑,因此需要在光滑和混淆之间权衡。

aliasing-in-reconstruction.png

避免重采样混淆

重采样滤波器为了同时做到重构和采样,必须要消除掉混淆谱,并让谱宽足够窄以保证在新的采样频率下采样。

aliasing-in-resampling.png

理想滤波器与实用滤波器

不管是采样还是重构,频域箱式函数都是一种理想的选择。但是相应的滤波器 sinc πx\mathrm{sinc}\ \pi x 宽度过宽,衰减速度过慢,以及滤波器中的负值都会在采样时产生问题。高斯滤波器更加实用,由于指数衰减,它可以有效地从输入信号中移除高频成分,而且高斯函数没有隆起可以保证混淆不泄露。

对于重构而言,有波纹的 sinc πx\mathrm{sinc}\ \pi x 函数还会带来振荡失真。