1

我正在尝试编写一个算法(在 c# 中),它将两个或多个不相关的高度图拼接在一起,因此地图之间没有可见的接缝。基本上我想模仿这个页面上的功能: http ://www.bundysoft.com/wiki/doku.php?id=tutorials:l3dt:stitching_heightmaps

(你可以只看图片来了解我在说什么)

我还希望能够获取单个高度图并对其进行更改,以便可以平铺,以创建一个无尽的世界(所有这些都是为了在 Unity3d 中使用)。但是,如果我可以将多个高度图拼接在一起,我应该能够轻松地修改算法以作用于单个高度图,所以我并不担心这部分。

任何形式的指导都将不胜感激,因为我已经搜索并搜索了没有成功的解决方案。只需向正确的方向轻推,将不胜感激!我知道许多图像处理技术可以应用于高度图,但一直无法找到产生我正在寻找的结果的图像处理算法。例如,图像拼接似乎只适用于具有重叠视野的图像,而不相关的高度图则不是这种情况。

以某种方式使用 FFT 低通滤波器会起作用,还是仅在生成单个可平铺高度图时有用?

因为该算法将在 Unit3d 中使用,所以任何 c# 代码都必须限于 .Net 3.5,因为我相信这是 Unity 使用的最新版本。谢谢你的帮助!

4

2 回答 2

1

好的,看来我之前尝试解决这个问题的方法是正确的。我最初尝试将高度图拼接在一起涉及高度图上每个点的以下步骤:

1) 求高度图上的一点与其相对点之间的平均值。对立点只是在 x 轴(如果缝合水平边缘)或 z 轴(对于垂直边缘)上反射的第一个点。

2) 使用以下公式找到该点的新高度:

newHeight = oldHeight + (average - oldHeight)*((maxDistance-distance)/maxDistance);

其中距离是从高度图上的点到最近的水平或垂直边缘的距离(取决于您要缝合的边缘)。任何距离小于 maxDistance 的点(这是一个影响地形改变程度的可调整值)都将根据此公式进行调整。

那是旧公式,虽然它对大多数地形产生了非常好的结果,但它在改变高度图点的区域和未改变高度图点的区域之间的区域中创建了明显的线。我几乎立即意识到这是因为与未改变区域相比,改变区域的坡度太陡了,从而在两者之间形成了明显的对比。不幸的是,我以错误的方式解决了这个问题,寻找如何将对比区域模糊或平滑在一起以去除线条的解决方案。

在平滑技术的成功率很低之后,我决定尝试降低改变区域的坡度,希望它能够更好地与未改变区域的坡度融合。我很高兴地报告,这极大地改进了我的拼接算法,删除了上面报告的 99% 的行。

旧公式的罪魁祸首是这部分:

(maxDistance-distance)/maxDistance

它根据点到最近边缘的距离线性地产生一个介于 0 和 1 之间的值。随着高度图点和边缘之间的距离增加,高度图点将使用越来越少的平均值(如上定义),并且越来越接近其原始值。这种线性插值是导致斜率过大的原因,但幸运的是,我在 Unity API 的 Mathf 类中找到了一个内置方法,该方法允许进行二次(我相信是三次)插值。这是SmoothStep 方法

使用这种方法(我相信可以在此处找到的 Xna 框架中找到类似的方法),用于确定高度图值的平均值的变化在中距离变得非常严重,但这种严重性随着距离越近而呈指数级降低。距离达到最大距离,创建一个不太严重的坡度,更好地与未改变区域的坡度融合。新的论坛看起来像这样:

//Using Mathf - Unity only?
float weight = Mathf.SmoothStep(1f, 0f, distance/maxDistance);

//Using XNA
float weight = MathHelper.SmoothStep(1f, 0f, distance/maxDistance);

//If you can't use either of the two methods above
float input = distance/maxDistance;
float weight = 1f + (-1f)*(3f*(float)Math.Pow(input, 2f) - 2f*(float)Math.Pow(input, 3f));

//Then calculate the new height using this weight
newHeight = oldHeight + (average - oldHeight)*weight;

可能有更好的插值方法可以产生更好的拼接。如果我找到这样的方法,我肯定会更新这个问题,所以任何想要进行高度图拼接的人都可以找到他们需要的信息。感谢 rincewound 通过线性插值走在正确的轨道上!

于 2013-05-09T03:13:52.893 回答
0

您发布的图像中所做的对我来说很像简单的线性插值。所以基本上:您拍摄两张图像(左,右)并定义一个拼接区域。对于线性插值,您可以获取左侧图像的最左侧像素(在拼接区域中)和右侧图像的最右侧像素(也在拼接区域中)。然后用插值填充中间的空间。

举个例子——我在这里用一行来展示这个想法:

Left = [11,11,11,10,10,10,10]
Right= [01,01,01,01,02,02,02]

假设我们的重叠是 4 像素宽:

 Left = [11,11,11,10,10,10,10]
 Right=          [01,01,01,01,02,02,02]
                   ^  ^  ^  ^ overlap/stitiching region.

左图最左边的值为 10 右图最右边的值为 1。现在我们分两步在 10 和 1 之间进行线性插值,我们的新拼接区域如下所示

stitch = [10, 07, 04, 01]

我们最终得到以下缝合线:

line = [11,11,11,10,07,04,01,02,02,02]

如果您将此应用于两个完整的图像,您应该会得到与您之前发布的类似的结果。

于 2013-05-08T07:02:04.157 回答