找出折线拐点的算法


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)

分别对x和y坐标进行样条化以实现曲线的参数化。(该参数将称为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.