[toc]
一、问题描述
这是个两年前的工作了,想着如果不整理一下,哪天电脑坏了,估计也就跟着没了吧,这样的事情也不少发生。
当时在设计一个新算法,其中的一小步就是需要对不规则平面区域进行插值。不规则平面区域由封闭曲线构成,下图给出了一个例子:
当然,上面这张图片中的云朵形状还是过于复杂了,但是暂时没找到合适的示意图,就凑合吧。实际需求没有这么复杂,形状整体上更偏向于一个凸集。
这里要解决的问题是,对于由封闭曲线构成的不规则区域,如何设计一个类似双线性插值的算法,使得区域内部的点能够根据区域轮廓曲线的属性值,从上至下或者从左至右进行平滑过渡呢?
二、问题分析与算法实现
2.1 四边形区域的插值
如果不规则区域是一个四边形,只需要进行双线性插值即可满足需求。现在回去看当时写的代码,里面有一段magic code,完全不知道是在干嘛的:
1 | def solve(vertices, coordinates, axis=0): |
所以说及时做笔记是相当重要的。后来细想一下,应该是这么推导得来的。设四边形的的四个端点分别为
将端点坐标记为
线段DC的参数方程为:
同理,线段AB的参数方程为:
设
设区域内一点为
展开得方程组:
两个方程,两个未知数,有手就能解:
将
等式两边同乘
合并同类项:
可以看出这是个一元二次方程,根据求根公式容易求得
最终的效果为:
具体的实现代码可参考:https://github.com/mo-vic/xy-interpolation/blob/main/quadrangle.py
2.2 不规则区域的插值
如果不规则区域是由封闭曲线构成的,可以仿照上面的思路,将区域的轮廓进行划分,构造一个曲边四边形。具体的划分方式是,将轮廓中的左上角,左下角,右下角,右上角四个点作为分界点,将封闭曲线划分为四段,对于每一段轮廓曲线,使用贝塞尔曲线进行拟合:
以从左至右的过渡方式为例,当点靠近蓝色曲线时,值应该接近于0,当点靠近红色曲线时,值应该接近于1。红蓝曲线的形状均由它们的控制点决定。因此,对于区域内点的取值,可以按比例
可以看到,这样的插值方式有时候并不完美,新构造的贝塞尔曲线可能会越过区域边界,但是暂时没想到更好的方法了。
最终的效果为:
从上图可以看到,在插值的时候,区域内部有些点没有被采样到,可以通过提高采样分辨率来提高覆盖率。但是有另外一种方式,就是使用已有数据构造一棵KDTree,在查询的时候,通过KDTree取最近邻值即可。
算法实际应用时的效果如下:
代码可以参考:https://github.com/mo-vic/xy-interpolation/blob/main/curve.py
现在回想起来,其实可以试一试蒙特卡洛方法的,但是今年是2023年了,不是2020年了。