我正在尝试编写一个算法(在c#中),它将两个或多个不相关的高度图拼接在一起,因此地图之间没有可见的接缝。基本上我想模仿这个页面上的功能: http://www.bundysoft.com/wiki/doku.php?id=tutorials:l3dt:stitching_heightmaps
(你可以看一下这些图片来了解我所说的内容)
我还希望能够采用单个高度图并对其进行更改,以便可以平铺,以创建无尽的世界(所有这些都在Unity3d中使用)。但是,如果我可以将多个高度图拼接在一起,我应该能够轻松修改算法以对单个高度图进行操作,所以我并不担心这个部分。
任何形式的指导都会受到赞赏,因为我搜索并搜索了一个没有成功的解决方案。只是在正确的方向上简单的推动将非常感谢!我知道许多图像处理技术可以应用于高度图,但是无法找到产生我正在寻找的结果的图像处理算法。例如,image stitching似乎仅适用于具有重叠视野的图像,而不相关的高度图不是这种情况。
以某种方式使用FFT低通滤波器是否可行,或者仅在生成单个可平铺高度图时有用?
因为该算法将在Unit3d中使用,所以任何c#代码都必须限制在.Net 3.5中,因为我认为这是Unity使用的最新版本。 谢谢你的帮助!
答案 0 :(得分:1)
好吧,我之前尝试解决这个问题似乎是在正确的轨道上。我最初尝试将高度图拼接在一起涉及高度图上每个点的以下步骤:
1)找出高度图上的点与其相对点之间的平均值。相反的点只是在x轴(如果拼接水平边缘)或z轴(垂直边缘)上反射的第一个点。
2)使用以下公式找到该点的新高度:
newHeight = oldHeight + (average - oldHeight)*((maxDistance-distance)/maxDistance);
距离是从高度图上的点到最近的水平或垂直边缘的距离(取决于您要缝合的边缘)。任何距离小于maxDistance的点(这是一个影响地形变化程度的可调整值)都会根据此公式进行调整。
这是旧的公式,虽然它为大多数地形产生了非常好的结果,但它在高度贴图点的改变区域和未改变的高度图点的区域之间的区域中创建了明显的线条。我几乎立即意识到这是因为改变区域的斜率与未改变的区域相比太陡,因此在两者之间产生明显的对比。不幸的是,我开始以错误的方式解决这个问题,寻找有关如何模糊或平滑对比区域以消除线条的解决方案。
在使用平滑技术取得很少成功后,我决定尝试减少改变区域的斜率,希望它能更好地与未改变区域的斜率混合。我很高兴地报告这大大改进了我的拼接算法,删除了上面报道的99%的线。
旧公式的主要罪魁祸首是这部分:
(maxDistance-distance)/maxDistance
基于点到最近边缘的距离线性地产生0到1之间的值。随着高度贴图点与边缘之间的距离增加,高度贴图点将使用越来越少的平均值(如上所定义),并且越来越多地朝向其原始值移动。这种线性插值是过度斜率的原因,但幸运的是我在Unity的API的Mathf类中找到了一种内置方法,允许二次(我相信立方)插值。这是SmoothStep Method。
使用这种方法(我相信在Xna框架中可以找到类似的方法here),在确定高度图值时使用的平均值的变化在中间距离变得非常严重,但是该严重程度指数地减小距离越接近maxDistance,产生不太严重的斜率,更好地与未改变区域的斜率混合。新论坛看起来像这样:
//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使用线性插值在正确的轨道上!
答案 1 :(得分: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。 现在我们以2步为单位在10和1之间进行线性插值,我们的新拼接区域如下所示
stitch = [10, 07, 04, 01]
我们最终得到以下拼接线:
line = [11,11,11,10,07,04,01,02,02,02]
如果您将此应用于两张完整图片,则应该获得与您之前发布的结果类似的结果。