在下面的曲线(蓝线)中,我试图检测应该位于x = 2.5周围的“膝盖/肘部”
这是我正在使用的一组值:
我已经尝试过Kneedle algorithm和formal definition of the curvature of a graph(有符号曲率)。我与Kneedle算法有关的问题是,在实时应用程序(嵌入式系统)中,我不知道哪个将是y轴的最大值,因此我无法正确地标准化这些点,也无法找到一个斜率值适用于所有情况。当使用图形曲率的形式定义时,我尝试使用5阶多项式(绿线)拟合曲线,然后获取导数的值以计算曲率。然而,由于多项式,该方法在x = -2附近找到了曲率,因为在该点附近存在曲率。
有人可以建议我一种方法来检测膝盖/肘部吗?
最佳答案
这不是连续曲线,也不是连续曲线的近似值,因此我们不必在这里浪费时间:您拥有一个简单的多边形。等效于“曲率半径”的多边形是入射角和折射角之差:该差越小,“曲率”的半径越大。
只要您正确采样数据,我们就可以计算每个数据点的角度差:
for (i=1, i<p.length -1):
vector1 = p[i] - p[i-1] // assuming your language of choice has points as primitives
vector2 = p[1+1] - p[i] // if not, you'll have to extract x/y separately.
p[i].angle = findAngle(vector1,vector2)
findAngle
函数应该很容易实现,有上百万的教程介绍如何用您喜欢的语言实现该功能(在许多语言中甚至是某些语言中都是内置的)。就是这样,我们已经将我们的2D数据转换为具有(x,y,z)坐标的3D数据,其中z
表示穿越该点的局部角度。为了找到任何“膝盖”,我们可以查看三个数据点(x-1),(x)和(x + 1)的所有集合,并考虑那些
x
,其中本地角度差大于的角度差。它的邻居。差异最大的x
是“优胜者”:您已经找到了自己的膝盖。 (或者实际上,是一个膝盖,因为点数据使零 promise 不会多次上升和下降,从而导致具有大量拐点的面)knee = undefined
max_diff = 0;
for (i=1, i<p.length -1):
a = p[i].angle
a1 = p[i-1].angle
d1 = a1-a
a3 = p[i+1].angle
d2 = a3-a
diff = ... // there's a few ways to compute this
p[i].diff = diff // always useful if we need to do more work later
if (diff > max_diff):
max_diff = diff
knee = p[i]
我把差异计算留给了您,因为也许您只想要d1 + d2或(d1 + d2)/2,或者您可能想根据d1或d2(但不是全部)都为0进行切换,等等。 。
当然,这里要注意的重要一点是,在收集数据点时,我们可以一次性完成所有这些事情,因为新点不会影响旧点的位置,因此在某个点处
n
,我们我们已经知道到n-1
的角度,并且我们已经知道到n-2
的膝盖,因此我们可以在一次线性传递中计算所有这些值。尼斯和高效。这种方法类似于找到数据拟合曲线的导数的根,但是当我们拥有的只是数值数据时,有时最正确的方法是使用该数据,而不是使用“推定重构”。您从中获得数据的原始事物”。在这种情况下,您不知道采样点之间数据源在做什么。也许它表现得很好,也许不是,但是你不知道,所以不浪费时间使问题复杂化,而直接使用已知的属性(当然,它们的作用是真的)是值得的。是传感器的读数,并且您的传感器可能绝对嘈杂,甚至有故障)。
关于algorithm - 如何实时检测曲线中的 "knee/elbow"(最大曲率),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47623915/