匹配细分的最佳算法是什么?
我正在尝试匹配来自两个地图源的相应线段,一种较不准确,但具有线段名称,一种较准确,不具有线段名称。我想将半段名称自动应用到更准确的地图上。
所请求的算法的描述非常模糊,因为“匹配”的定义不明确,并且在不同情况下,许多因素(方向,相对长度,距离)可能具有不同的权重;但是,我正在寻找有关处理此问题的一般方法的基础知识。
热烈欢迎开源环境(PostGIS,shapely等)的可行实现。
示例片段:请参见下面的图片描述。
匹配细分的最佳算法是什么?
我正在尝试匹配来自两个地图源的相应线段,一种较不准确,但具有线段名称,一种较准确,不具有线段名称。我想将半段名称自动应用到更准确的地图上。
所请求的算法的描述非常模糊,因为“匹配”的定义不明确,并且在不同情况下,许多因素(方向,相对长度,距离)可能具有不同的权重;但是,我正在寻找有关处理此问题的一般方法的基础知识。
热烈欢迎开源环境(PostGIS,shapely等)的可行实现。
示例片段:请参见下面的图片描述。
Answers:
的Hausdorff距离可以被使用:匹配线段可以根据该距离“关闭”段。在段上计算非常简单。
JTS中提供了免费的Java实现-请参见JTS Distance Package。您还可以查看JCS Conflation Suite(现已废弃,其源副本,例如https://github.com/oschrenk/jcs)。
我不知道什么是“最佳”,因为这取决于细分受众群的具体情况。
通常的好方法是将片段散列为关键的几何信息。至少包括中心的位置(x,y),方向(0到180度)和长度。施加适当的权重,并对方向进行细化处理(因为将180“环绕”回零),然后可以将几乎所有统计聚类算法应用于所有段的集合。(K均值将是一个不错的选择,但是大多数分层方法应该都能很好地工作。此类聚类分析往往快速且易于应用。)理想情况下,分段将成对出现(或对于不匹配的分段为单例),其余部分成对出现。简单。
解决方向问题的一种方法是复制标记的片段。如果第一个副本的方向小于90度,则将其增加180度,否则将其减去180度。(显然)这会扩大数据集,但不会以任何方式更改算法。
需要权重是因为坐标,长度和方向的差异可能意味着与它们相应段的相似性完全不同的事物。在许多应用中,段之间的差异是由于其端点位置的差异引起的。作为粗略的近似,我们可以预期段长度的典型变化与其端点之间的典型变化大致相同。因此,与x,y和长度关联的权重应大致相同。棘手的部分是加权方向,因为方向不能等同于距离,更糟糕的是,短片段比长片段更容易错位。考虑一种反复试验的方法,该方法将一些方向错误的现象等同于段之间的典型间隙的大小,然后对其进行调整,直到该过程似乎运行良好为止。作为指导,让L是典型的段长度。以较小的角度t度改变方向会扫出大约L / 2 * t / 60 的距离 (60近似于一个弧度的度数),即 L / 120乘以t。这建议从x,y和长度的单位权重以及方向的L / 120 权重开始。
总之,此建议是:
制作带标签的段的副本(如关于对齐方向的段落中所述)。
将每个段转换为四倍(x,y,长度,L / 120 *方向),其中L是典型的段长度。
对四元组执行聚类分析。使用一个好的统计软件包(R是免费的)。
将聚类分析输出用作查找表,以将标记的细分与附近的未标记细分相关联。
大约5年前,我从事了一个具有类似要求的项目。它涉及将来自街道中心线的坐标(坐标精度较高)与高速公路性能监控系统(HPMS)交通网络链接相结合。
当时,FHWA没有提供任何工具来执行此类操作。情况可能已经改变,您可能要检查一下。即使您不使用高速公路数据,这些工具也可能仍然有用。
我用ArcGIS编写了该算法,但是该算法应该在开源环境下工作,只要它提供类似于ISegmentGraph的跟踪功能:
// features is a collection of features with higher geometry
// Links are a collection features with attributes but low res geometry
For each Link in lowResFeatureclass
point startPoint = SnapToClosestPoint(Link.StartPoint, hiResfeatures);
if(startPoint == null)
continue;
point endPoint = SnapToClosest(Link.EndPoint, hiResfeatures);
if(endPoint == null)
continue;
polyline trace = Trace(hiResfeatures,startPoint,endPoint);
if(polyline != null)
{
// write out a link with high precision polyline
Write(Link,polyline);
}
Next Link
这里有个主意
如果将其中一个线串拆开以进行比较并测试顶点是否与另一个线串相距一定距离以进行比较,则可以通过多种方式控制测试。
这些示例在PostGIS中起作用(谁能猜到:-))
首先,如果说table_1的线串中的所有顶点都是0.5米(地图单位)或更接近table_2的线串,则存在匹配项:
SELECT a.id, b.id FROM
(SELECT ST_NPoints(the_geom) as num_of_points,
(ST_Dumppoints(the_geom)).geom as p, id FROM table_1) a
INNER JOIN
table_2 b
ON ST_DWithin(a.p, b.the_geom, 0.5) GROUP BY a.id, b.id
HAVING COUNT(*)=num_of_points;
那么我们可以说,如果table_1的线串中的vertex_points的60%以上在table_2的线串的距离内,则存在匹配项
SELECT a.id, b.id FROM
(SELECT ST_NPoints(the_geom) as num_of_points,
(ST_Dumppoints(the_geom)).geom as p, id FROM table_1) a
INNER JOIN
table_2 b
ON ST_DWithin(a.p, b.the_geom, 0.5) GROUP BY a.id, b.id
HAVING COUNT(b.id)/num_of_points::float > 0.6
或者我们可以接受一点不在范围内:
SELECT a.id, b.id FROM
(SELECT ST_NPoints(the_geom) as num_of_points,
(ST_Dumppoints(the_geom)).geom as p, id FROM table_1) a
INNER JOIN
table_2 b
ON ST_DWithin(a.p, b.the_geom, 0.5) GROUP BY a.id, b.id
HAVING COUNT(b.id)-num_of_points <= 1;
您还必须以相反的角色对table_1和table_2运行查询。
我不知道它将有多快。ST_Dumppoints当前是PostGIS中的sql函数,而不是C函数,这使其比预期的要慢。但我认为无论如何都会很快。
空间索引将有助于ST_Dwithin发挥作用。
HTH尼克拉斯
我已经编写了代码来处理边界生成器中的草率线段匹配(并使它们重叠)。我在这里写下了它的(相当基本的)数学公式:http : //blog.shoutis.org/2008/10/inside-boundary-generator-computational.html。该代码是开源的,并通过该博客文章进行链接。
该代码遵循一种非常简单的方法:
这种方法的主要优点是您可以得到精确的旋钮,以获取有效的角度,距离和重叠长度。不利的一面是,它不是一种通常测量两个线段相似度的方法,因此,例如进行统计聚类来确定可能的匹配要困难得多-您被精确的旋钮卡住了。
注意:我猜想如果有足够的SQL印章,您可以将分段测试塞入WHERE子句... :)
干杯!