如何平滑手绘线条?

时间:2016-03-03 04:58:50

标签: math lines smoothing

所以我正在使用Kinect和Unity。

使用Kinect,我们会检测到一个手势,当它处于活动状态时,我们会在屏幕上画一条线,这条线就在手的前方。每次更新时,该位置都存储为一行中的最新(和最后)点。然而,线条通常看起来很不稳定。

以下是显示我想要实现的目标的总体情况:

Smoother versus Rough Lines

红色是原始线,紫色是新的平滑线。如果用户突然停止并转向方向,我们认为我们希望它不是那样做,而是快速转弯或循环。

我目前的解决方案是使用Cubic Bezier,并且仅使用相距X距离的点(使用Cubic Bezier将Y点放置在两点之间)。然而,这有两个问题,其中包括:

1)它通常不会将曲线保留在用户绘制它们的外部距离上,例如,如果用户突然停止一条线并反转方向,那么该线很可能不会延伸到用户改变了方向。

2)所选的“好”点实际上也可能是一个“坏”的随机跳跃点。

所以我考虑过其他解决方案。一个包括限制点之间的最大角度(0度是直线)。然而,如果该点具有超出极限的角度,则在尽可能地遵循绘制线的同时降低角度的数学似乎很复杂。但也许不是。无论哪种方式,我都不确定该怎么做并寻求帮助。

请记住,这需要在用户绘制线条时实时完成。

1 个答案:

答案 0 :(得分:1)

您可以尝试使用Ramer-Douglas-Peucker算法来简化曲线:

https://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm

这是一个简单的算法,参数化相当直观。您可以将其用作预处理步骤,也可以在一个或多个其他算法之后使用。无论如何,它是您工具箱中的一个很好的算法。

使用角度拒绝"跳跃"正如你所见,积分可能很棘手。一种选择是将N个线段的总长度与该N个线段的链的最末端点之间的直线距离进行比较。您可以阈值(totalLength / straightLineLength)的比率来标识要拒绝的线段。这将是一个快速计算,并且很容易理解。

如果要考虑线段长度和线段到线段角度,可以将线段视为矢量并计算叉积。如果你想象两个向量定义一个平行四边形,并且如果知道平行线的区域是接受/拒绝一个点的方法,那么十字产品是另一个简单而快速的计算。

https://www.math.ucdavis.edu/~daddel/linear_algebra_appl/Applications/Determinant/Determinant/node4.html

如果您只有几十个点,则可以一次随机消除一个点,生成样条拟合,然后计算所有原点的点到样条距离。给定所有这些点到样条距离,您可以生成一个您希望最小化的度量(例如平均距离):消除点(Pn,Pn + k,...)导致的最佳拟合样条拟合质量S.这种技术不会用更多的点进行很好的扩展,但是如果你将每个线段链分成每组可能有六个段,则可能值得一试。

虽然对于这个问题来说太过分了,但我还是提到欧拉曲线可以很好地适应“自然”和“#34;曲线。欧拉曲线的优点在于,您可以生成由空间中的两个点和空间中这两个点处的切线拟合的欧拉曲线。代码变得毛茸茸,但是欧拉曲线(如果我没记错的话,a.k.a。审美曲线)可以比Bezier n度样条生成更好和/或更有用的自然曲线拟合。

https://en.wikipedia.org/wiki/Euler_spiral