本文主要的参考文献为:
1. 游戏编程中的数学——调和函数和中值座标
2. Hormann K, Floater M S. Mean value coordinates for arbitrary planar polygons[J]. Acm Transactions on Graphics, 2006, 25(4):1424-1441.
3. Floater M S. Mean value coordinates[J]. Computer Aided Geometric Design, 2003, 20(1):19-27.
一般来说,我们不通过一个模型含有的网格(通常为三角形网格或四边形网格)以及顶点去理解它,而是在其网格上建立一个函数,这个函数拥有特定的性质,有助于解决我们面临的难题。那么这次介绍一个在网格上建立函数的方法——中值座标。中值座标是90年代后期产生的,其背后的数学原理却得追述到18、19世纪了,然而直到今天它依然没有受到游戏开发界足够的重视……本文重点是谈谈中值座标的构造与应用。
中值座标的“前菜”
由
这些归一化后的重心座标在网格上是连续的,并且具有
这就是为什么它们通常用于对一个三角形区域进行线性插值,并且在计算机图形学中具有广泛的应用(例如
在许多实际应用中,将重心座标推广到具有任意
再将其归一化得
这样平面上的任一点
中值座标的构造
令
如图所示为一些简单多边形的小栗子:
由上图可以看出,简单多边形可以为凹多边形,也支持嵌套操作,并不局限於单个凸多边形。
对于
这是通常的欧氏距离,并用
它们分别表示
易知
通常,这些座标还需要进行归一化,即需要除以
现在让我们来考虑一下
其中权重函数
欲验证上式,我们首先得解释一下当
由上图可以看出,
现在的关键步骤是对于齐次重心座标的归一化,必须保证
事实上,由
当
然而,在一个非凸多边形中,
为了解决上述问题,通常采用的解决方案是令权重函数
针对上述问题,
其中
现在,我们就来介绍一种最常用的重心座标,它就是我们今天这篇文章的主角——中值座标,其权重函数是酱紫定义的:
可能看到这里就有人感到不解了,这货长得不就跟
事实上,这个证明是比较复杂的,需要两个引理才能证明,篇幅较长,因此这里不再赘述。有兴趣的同学可以看看第2篇参考文献,文中的定理4.3便给出了答案。
继续走下去,将
再将
上式是
至此,离整个中值座标的构造便仅差一步了!!!✿✿ヽ(°▽°)ノ✿
中值座标的性质
对于任一简单多边形的集合
中值座标具有如下优美的性质(证明都可以参见第2篇参考文献):
- 仿射精度:对于任一仿射函数
φ:R2→Rd 都有∑i=1nλiφ(vi)=φ ; Lagrange 性:λi(vj)=δi,j ;- 光滑性:当
v≠vj 时,λi∈C∞ ;而当v=vj 时,λi∈C0 ; - 正则性:
∑i=1nλi≡1 ; - 相似不变性:如果
φ:R2→R2 是具有相似性的(此处具有相似性的变换定义为该变换是一个平移变换,旋转变换,反射变换,等距缩放变换或者它们的组合),且Ψ^=φ(Ψ) ,则λi(v)=λ^i(φ(v)) ; - 线性无关性:如果
∑i=1nciλi(v)=0,v∈R2 ,则ci=0 ; - 如果我们令
Ψ^ 是由Ψ 在ej 边上增加一点v^=(1−μ)vj+μvj+1 ,则λj=λ^j+λ,λj+1=λ^j+1+μλ^ ,且λi=λ^i,i≠j,j+1 ; - 线性性:
λi 在Ψ 的任一条边ej 上是线性的; 非负性:
λi 在凸多边形的内核上是正的,其中,平面上简单多边形的核是该多边形内部的一个点集,该点集中任意一点与多边形边界上一点的连线都处于这个多边形内部。譬如说,就是一个在一个房子里面放一个摄像 头,能将所有的地方监视到的放摄像头的地点的集合即为多边形的核。(参考自博客半平面交,求解多边形内核)至此,整个中值座标的构造算是大功告成了!!!✿✿ヽ(°▽°)ノ✿
中值座标的应用
中值座标最主要的应用便是在给定简单多边形
由于
事实上,接下来所讨论的两个应用本质上还是体现了一种插值思想。
图像变形
中值座标的一个应用是图像变形,因为中值座标为这个问题提供了一个特别简单的解决方案,可简要地说明如下。
给定一个矩形区域
许多时候,图像变形函数可以用
它将每一个
gi(x) 满足gi(v^i)=vi ,这是对于点v^i 的插值,i=1,2,⋯,n 。对于插值基函数gi 而言,一般使用线性或者二次多项式,多项式系数可以用插值点处的导数值去确定。λi:R2→R 是权函数,须满足条件λi(v^i)=1,∑i=1nλi(v^i)=1 且λi(v^)⩾0,i=1,2,⋯,n 。
Shepard 提出了以下简单的权函数:
λi(v^)=ωi(v^)∑i=1nωj(v^),
其中ωi(v^)=1ri ,ri 是v^ 与v^i 的距离。
IDW 是一种全局插值算法,即全部样本点都会参与到与某一插值结点(实际运用当中又叫控制点)的运算当中去,所以它的计算复杂度起码为O(nN) ,其中n 是控制点的数量,N 是整个目标图像的像素点数量。
我们不妨来看一下分别令I^=I∘f 与I^=I∘g 会产生什么不同的神奇现象。(g=f−1 ,下面直接令gi(v^)=v^+vi−v^i )
若采用I^=I∘f ,容易发现生成的目标图像中会出现许多空洞点(为了突出空洞点,图中用深红色点表示空洞点),如下图所示:
正向映射实验效果图对于上述问题,我们需要对空洞进行填补,我分别采用了均值滤波模板、中位数滤波模板与即时填充空洞进行处理:
均值滤波模板填补效果图
填补后局部放大图
容易看出,在对图像进行空洞区域的填补以后,出现了一些疑似空洞的点,故仍需要进行改进。先来简要分析一下原因~
由于存在取平均值的操作,故当一个像素点周围存在不同颜色的像素点时,填补以后容易出现颜色差异较大的点,譬如黑色方块和白色方块相邻边界上的空洞点,填补以后就会变成灰色点。
找到原因以后便可以有针对性地进行改进,自己采用的解决方案是替换均值滤波模板改用中位数滤波模板,需要注意的是,对一个空洞点填补时并不考虑周围的空洞点,即不应该将空洞点的像素用来求中位数;其次,若一个空洞点周围的非空洞点像素点数量为偶数时,其中位数是需要取平均的,此时容易出现类似使用均值滤波模板的填补错误,于是需要进行如下判断,假设该空洞点周围的非空洞点像素点数组为
if surrounding_pixels[i] = = surrounding_pixels[i - 1],i=surrounding_pixels.size()/2
将surrounding_pixels[i]赋给空洞点;
else
为了避免出现取均值的操作,依然将surrounding_pixels[i]赋给空洞点;
中位数滤波模板填补效果图
在作了上述改进以后,发现仍存在一些问题,如:
改进填补后的局部放大图
可以看出,一些方块边缘会出现“毛边”现象,即方块颜色会“渗入”相邻的方块。究其原因,发现在填补时空洞点周围的空洞点太多,影响了其中位数的取值,因为对空洞点进行中位数滤波时是要舍去周围的空洞像素的,如下图所示:
为了解决上述现象,需要对空洞点进行即时填补,因为在之前的程序当中,找到空洞点对其进行中位数滤波以后,出于当前填补结果若是错误会对后面的填补效果产生影响的考虑,并非直接进行填补,而是先把像素存储起来,等到最后再进行填补。
而现在则需要对此做出改变,只要保证当前空洞点的填补结果是正确的就可以了。自己的做法如下所示:假设该空洞点周围的非空洞点像素点数组为
if surrounding_pixels[i] = = surrounding_pixels[i - 1],i=surrounding_pixels.size()/2
将surrounding_pixels[i]赋给空洞点;
else
先不进行操作,将这个点记录下来,等对全部点进行中值滤波以后再对这个点进行中值滤波,此时因为之前的空洞点已被填补,故它能获得更多有效的像素点;
即时填补空洞效果图
可以看出,在改进以后实验结果有了一定的改善。那么,我们再来看一下采用
逆向映射实验效果图
可以看出,实验的效果十分理想。无论是在算法运行时间及算法实现难度上都远胜之前的正向映射+空洞填补算法。当然对于图像变形还有其它优秀的算法,比如径向基函数算法(
纹理参数化
中值座标的另一个应用是纹理参数化,简要地说明如下。
(图片画得并不是很标准哈,见谅(:3 」∠) )
首先需要进行局部参数化:将局部结构映射到平面上,映射过程满足下列条件:
其中,
对于点
如此一来,我们便可以定义函数
其中,
然而,真正将上述方法用于纹理参数化的话会出现计算量太大的问题,因为它需要对模型内每一个点进行计算。因此,在实际运用当中,如果模型是比较规则的或者有足够多的顶点集,则可以弃用上述的中值座标,改用构造一个关于顶点变换的稀疏线性系统,亦可以求出形状变化比较小的参数化结果。
原网格
参数化结果
总结
我们已经表明,中值座标将三角形重心座标的概念推广到任意的简单多边形,甚至是这些简单多边形的集合。中值座标具有许多很漂亮的性质(如
我们注意到,中值座标在任意简单多边形的情况下并不是处处都是正的。另一方面,可能是恰恰由于这些性质,中值座标的插值性能才能如此棒,而且在实际应用中发挥着重要作用。(๑•̀ㅂ•́)و✧文中实验的源码会上传到我的