将矢量轮廓区域(边界)转换为光栅图(像素网格)

Posted

技术标签:

【中文标题】将矢量轮廓区域(边界)转换为光栅图(像素网格)【英文标题】:Converting vector-contoured regions (borders) to a raster map (pixel grid) 【发布时间】:2009-11-06 11:43:03 【问题描述】:

我有一张地图,它按边界(轮廓)分割成多个区域,就像世界地图上的国家一样。每个区域都有一个特定的地表覆盖等级 S(例如 0 代表水,0.03 代表草......)。边界由以下方式定义:

S 的值在它的任一侧(在下面的示例中,一侧为 0.03,另一侧为 0.0) 边框由多少个点组成(n=7 在下面的示例中),以及 n 个坐标对 (x, y)。

这是一个例子。

0.0300      0.0000           7
2660607.5   6332685.5   2660565.0   6332690.5   2660541.5   6332794.5 
2660621.7   6332860.5   2660673.8   6332770.5   2660669.0   6332709.5 
2660607.5   6332685.5

我想制作一个光栅图,其中每个像素的值 S 对应于像素中心所在的区域。

注意,边框代表S中的step变化。 S 的各种值代表离散的类别(例如草或水),并且不是可以平均的值(即没有湿草!)。

另请注意,并非所有边框都是像上面的示例一样的闭环。这有点像国家边界:例如美加边界不是一个封闭的循环,而是一条线,在每一端与另外两个边界相连:加拿大-海洋和美国-海洋“边界”。 (不过,闭环边界do exist!)

谁能给我指出一个可以做到这一点的算法?我不想重新发明***!

【问题讨论】:

【参考方案1】:

以矢量形式处理这种几何图形的一般情况可能非常困难,特别是因为您描述的结构并不需要几何图形保持一致。但是,由于您只是想对其进行栅格化,因此将问题视为线段的 Voronoi 图会更加稳健。

可以在 OpenGL 中通过将每个线段绘制为一对构成帐篷形状的四边形来以图形方式逼近 Voronoi 图。 z 缓冲区用于使最近的四边形优先,从而根据最接近的线对像素进行着色。此处的不同之处在于,您将希望根据多边形所在的线条的哪一侧而不是它们代表的线条为多边形着色。一篇讨论类似算法的好论文是 Hoff 等人的 Fast Computation of Generalized Voronoi Diagrams Using Graphics Hardware

3d 几何图形看起来像这个带有 3 个红色/黄色段和 1 个蓝色/绿色段的草图:

此过程不需要您将任何东西转换成闭环,也不需要任何花哨的几何库。一切都由 z-buffer 处理,并且应该足够快以在任何现代显卡上实时运行。一种改进是使用齐次坐标使基础投影到无穷远。

我在http://www.pasteall.org/9062/python 的 Python 脚本中实现了这个算法。一个有趣的警告是,在不扭曲锥体形状的情况下,使用锥体来覆盖线条的末端是行不通的,因为代表线段端点的锥体是 z 轴冲突的。对于您提供的示例几何,输出如下所示:

【讨论】:

这是我第二喜欢的答案。感谢您花时间演示!【参考方案2】:

我建议您使用像 CGAL 这样的几何算法库。特别是参考手册的“2D 多边形”页面中的the second example 应该为您提供所需的内容。您可以将每个“边界”定义为多边形并检查某些点是否在多边形内。所以基本上它会像

for every y in raster grid
  for every x in raster grid
    for each defined polygon p
      if point(x,y) is inside polygon p
        pixel[X][Y] = inside_color[p]

我不太确定如何处理outside_color,因为外部区域会重叠,不是吗?无论如何,看看你的例子,每个外部区域都可能是水,所以你可以做一个决赛

    if pixel[X][Y] still undefined then pixel[X][Y] = water_value

(或者作为替代方案,在遍历多边形列表之前将 pixel[X][Y] 设置为 water_value)

【讨论】:

如果我所有的边界都是封闭的多边形,这可以完成这项工作......关于如何将它们转换为此类的任何提示? 你无法判断你是在里面还是外面的东西没有关闭。你必须使用封闭的多边形来描述你的地图,不要描述两个项目之间的边界,而是每个项目的边界,这将是一组封闭的形状。【参考方案3】: 首先,将所有边界转换为闭环(可能包括地图的边缘),并识别内部颜色。这必须是可能的,否则您的数据会不一致 使用 bresenham 算法在地图上以一种未使用的颜色绘制所有边界线 在执行此操作时存储所有“边框像素”的列表 然后对于每个边框 对其进行三角测量 (delaunay) 遍历三角形,直到找到一个中心在边界内的三角形(多边形内点测试) 用边界的内部颜色填充您的地图 填写完所有内部区域后,遍历边框像素列表,查看每个像素应该是哪种颜色

【讨论】:

【参考方案4】: 选择两种未使用的颜色作为标记“空”和“边框” 用“空”颜色填充所有区域 按“边框”颜色绘制所有区域边框 遍历点以找到第一个具有“空”颜色的点 确定它属于哪个区域(谷歌“点在多边形内”,可能您需要按照 Martin DeMello 的建议关闭边界) 使用区域的颜色从该点执行填充算法 转到下一个“空”点(无需重新开始搜索 - 继续) 以此类推,直到不再有“空”点为止

【讨论】:

这不会给我留下有限(不幸的是非零)数量的“边框”彩色像素吗? 是的……看起来是这样。对于每个这样的点,您可以执行与第 5 步中的点相同的检查。或者您甚至可以修改洪水填充算法来检查呈现为分析段而不是点集的边界 呵呵,我想我“可以”。我只是希望我可以避免重新发明***。肯定有人已经在某个地方解决了这个任务。【参考方案5】:

我解决的方法如下:

    沿着每个路段行军;定期停止L。 在每个停靠点,立即在路段的左侧和右侧放置一个跟踪点(与路段相距一定的小距离 d)。示踪点分别归属于左右 S 值。 进行最近邻插值。栅格网格上的每个点都归属于最近的示踪点的 S。

即使有非封闭线,这也有效,例如在地图的边缘。

这不是一个“完美”的分析算法。有两个参数:Ld。只要 d L,该算法就可以很好地工作。否则,您可能会在段交叉点附近出现不准确(通常是单像素),尤其是那些具有锐角的点。

【讨论】:

以上是关于将矢量轮廓区域(边界)转换为光栅图(像素网格)的主要内容,如果未能解决你的问题,请参考以下文章

光栅化阶段:三角形设置、三角形遍历、像素着色、合并

哪里可以下载免费行政边界矢量地图

将点转换为矢量线的算法。 (光栅到矢量)

一般打印光栅和/或矢量图像

从矢量数据生成地理图块

计算机图形学——多边形的扫描转换