找出折线拐点的算法


22

我试图找出拐点,即直线上的曲线的起点和终点。如果查看图像,绿线可能是道路或溪流,黑点是曲线的起点和终点。 在此处输入图片说明

自动生成这些点的高级步骤是什么?我有ArcGIS Desktop,并且对ArcObjects非常方便。


源数据是由线段组成的多段线,您想使其与曲线相邻,还是已经有弧段?
U2ros 2012年

当前,它由线段组成。
Devdatta Tengshe 2012年

1
该问题中的插图非常类似于esri.com/news/arcuser/0110/turning.html上发布的插图
ub

@whuber:非常敏锐的观察。那正是我用来创建图像的数据源。
Devdatta Tengshe

Answers:


15

当曲线由线段组成时,这些线段的所有内部点都是拐点,这并不有趣。取而代之的是,曲线应被认为是那些线段的顶点所近似的。通过将分段的两次可微分曲线样条化,然后可以计算曲率。严格来说,拐点就是曲率为零的地方。

在该示例中,存在一些曲率几乎为零的较长拉伸。这表明指示的点应近似于低曲率区域的这种延伸的末端。

因此,有效的算法将对顶点进行样条运算,沿着密集的中间点集计算曲率,确定接近零曲率的范围(使用对“接近”意味着的合理估计),并标记这些范围的端点。

这里是工作R代码来说明这些想法。让我们从表示为坐标序列的线串开始:

xy <- matrix(c(5,20, 3,18, 2,19, 1.5,16, 5.5,9, 4.5,8, 3.5,12, 2.5,11, 3.5,3, 
               2,3, 2,6, 0,6, 2.5,-4, 4,-5, 6.5,-2, 7.5,-2.5, 7.7,-3.5, 6.5,-8), ncol=2, byrow=TRUE)

分别对xy坐标进行样条化以实现曲线的参数化。(该参数将称为time。)

n <- dim(xy)[1]
fx <- splinefun(1:n, xy[,1], method="natural")
fy <- splinefun(1:n, xy[,2], method="natural")

插补样条线以进行绘图和计算:

time <- seq(1,n,length.out=511)
uv <- sapply(time, function(t) c(fx(t), fy(t)))

我们需要一个函数来计算参数化曲线的曲率。它需要估计样条曲线的一阶和二阶导数。对于许多样条曲线(例如三次样条曲线),这是一个简单的代数计算。 R自动提供前三个导数。(在其他环境中,可能需要数字计算导数。)

curvature <- function(t, fx, fy) {
  # t is an argument to spline functions fx and fy.
  xp <- fx(t,1); yp <- fy(t,1)            # First derivatives
  xpp <- fx(t,2); ypp <- fy(t,2)          # Second derivatives
  v <- sqrt(xp^2 + yp^2)                  # Speed
  (xp*ypp - yp*xpp) / v^3                 # (Signed) curvature
  # (Left turns have positive curvature; right turns, negative.)
}

kappa <- abs(curvature(time, fx, fy))     # Absolute curvature of the data

我建议根据曲线的范围估算零曲率的阈值。至少这是一个很好的起点;应该根据曲线的曲率进行调整(即,对于更长的曲线应增加)。以后将根据曲率将其用于为图着色。

curvature.zero <- 2*pi / max(range(xy[,1]), range(xy[,2])) # A small threshold
i.col <- 1 + floor(127 * curvature.zero/(curvature.zero + kappa)) 
palette(terrain.colors(max(i.col)))                        # Colors

现在已经对顶点进行了样条化并计算了曲率,剩下的只是找到拐点。为了显示它们,我们可以绘制顶点,绘制样条曲线并在其上标记拐点。

plot(xy, asp=1, xlab="x",ylab="y", type="n")
tmp <- sapply(2:length(kappa), function(i) lines(rbind(uv[,i-1],uv[,i]), lwd=2, col=i.col[i]))
points(t(sapply(time[diff(kappa < curvature.zero/2) != 0], 
       function(t) c(fx(t), fy(t)))), pch=19, col="Black")
points(xy)

情节

空心点是其中的原始顶点,xy黑色点是使用此算法自动识别的拐点。由于无法可靠地在曲线的端点处计算曲率,因此这些点没有特别标记。


也许我使用的术语是错误的。您假设的正是我想要的。您的答案看起来很有希望,我将不得不与R合作来处理我的Shapefile。
Devdatta Tengshe 2012年

3

您可以使用“ 增密”工具。在这种情况下,您选择按角度进行增密,然后选择直线上可接受的最大角度。然后将结果线应用于顶点处的工具“ 分割线”。最后,删除shape_length小于最小道路长度的线。

在此处输入图片说明

在这张照片中,我们看到三个步骤:

1-使用角度使线致密。我使用10度作为参数,我们使用了分割线。在图片中,曲线处于初始阶段。

arcpy.Densify_edit("line" , "ANGLE" , "","",10)
arcpy.SplitLine_management("line" , "line_split")

2-选择没有shape_length冗余的线段。正如我们在表中看到的,我没有选择那些多余的长度。然后,将它们选择到新的要素类中。

arcpy.Select_analysis("line_split" , "line_split_selected")

3-我们提取了位于线条边缘的顶点,这些顶点是拐点。

arcpy.FeatureVerticesToPoints_management("line_split_selected" , "line_split_pnt" , "DANGLE")

关于其他答案,我也有相同的评论和问题:这是一个好主意,但同时还不清楚是否会产生所需的结果,也不清楚如何选择阈值角度。您能否提供输出说明,以便读者评估该建议的实际作用?在推荐ESRI软件作为解决方案的一部分时,提供有效的示例尤为重要,因为通常不会记录其算法,因此无法确切知道它们在做什么。
Whuber

为了确保这是一个可行的解决方案,我需要对其进行测试,但是我无法对其进行测试,因为我丢失了数据,所以我认为ESRI提出的工具可以按预期工作,但是此答案需要进一步测试。
geogeek 2012年

我们可以
说出

1
那么,您要我将其添加为评论吗?顺便说一句,如果您想测试数据,可以开始使用我在答案中发布的坐标,因为它们与问题中的插图非常接近。但是,为什么不只使用方便的地理数据呢?
Whuber

2
是的,确实,此解决方案在仅提取直线时效果更好。
geogeek 2012年

1

您可以使用与原始行具有最大偏移量的Generalize工具作为参数,因此可以选择适合您情况的偏移量。

在此处输入图片说明

如果我们将原始行命名为“ line_cur”,而将广义行命名为“ line_gen”,则可以将“ line_cur”剪切为“ line_gen”。结果将是“ line_cur”的直线段。然后,我们可以通过使用sql查询删除一些非常短的路段来进行清理,该查询选择的Shape_length大于最小路段的长度。


这是一个好主意。不过,目前尚不清楚它在实践中的效果如何。您能否显示显示找到的拐点的示例?
ub

我进行了编辑以包括图片,图片说明了该工具如何使直线与直线段粘连,因此我们必须对旧直线进行剪辑,以仅提取直线段
geogeek

有什么不清楚的地方吗,我可以回答您的问题吗?
geogeek 2012年

我在图中没有看到任何拐点。他们到底在哪里?以及如何选择概括的容忍度?
ub

我需要一些数据来执行测试,但我认为我们应该通过实验选择公差
geogeek 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.