计算和检测曲线

我如何检测曲线的“陡度”? 例如,如果用户用手指在屏幕上划一条曲线,检测曲线几乎是半圆形,还是直线是最好的方法是什么?

是否也可以扩展到可能识别多个曲线(例如S形)?

感谢您的任何建议

我建议使用方向直方图。 首先,收集曲线上的样本点,确保它们相距足够远。 例如,select10像素的最小距离。

然后迭代点三元组[A,B,C]并计算方向变化:

v1 = (B - A).normalize(); v2 = C - B; f = atan2(-v2.x * v1.x -v2.y * v1.y, v2.x * v1.y - v2.y * v1.x); 

现在f包含BCAB之间的方向差异。 atan2()在这里是非常重要的,以避免被零除。

现在你可以比较连续的方向变化,比如[Jesse Emond]建议的。 但是,计算直方图会更稳健:

 float histo[32]; memset(histo, 0, sizeof(histo)); /* ... */ histo[31 - (int)((M_PI - f) * (32.0 / 2.0 / M_PI))] += weight(A, B, C); 

(我使用M_PI - f而不是f + M_PI因为M_PI值是包含的,可能导致整数溢出)。

float weight(A, B, C)是一种计算笔划重量的方法。 一个简单的权重函数将返回AC的长度,但是您可以决定给较长的笔画一个更小的权重。

最后,分析直方图。 如果你获得了histo[15]histo[16]大部分值,这意味着用户做了一条直线。 如果它们在histo[13]周围,​​则意味着一个大的逆时针圆弧, histo[18]意味着一个顺时针的圆, histo[11]意味着一个更小的圆,任何低于histo[8]或高于histo[24]意味着残酷的方向变化…

对于曲线或直线问题,我想我会保留旧input的位置列表。 然后,我会检查每个点之间的斜率(delta Y / delta X)。 如果斜率变化不大,那么可能是一条线。 如果变化很大,那可能是曲线。 您可以使用表示斜率差的限制来确定input是线还是曲线。

所以,如果我必须实现这样的function,我想我会这样做:

 List<Vector2> inputPositions = new List<Vector2>();//the old input positions 

那么我会find每个位置之间的斜坡:

 float deltaY = 0f; float deltaX = 0f; List<float> slopes = new List<float>(); for (int i = 0; i < inputPositions.Count - 1; ++i)//check all the positions except the last one { deltaY = inputPositions[i + 1].Y - inputPositions[i].Y;//next pos.Y - current.Y deltaX = inputPositions[i + 1].X - inputPositions[i].X;//next pos.X - current.X if (deltaX != 0.0f)//prevent division by 0 { slopes.Add(deltaY / deltaX); } else { //I'm not really sure about using these values, but basically it //means that the movement was vertical slopes.Add(deltaY > 0.0f ? float.MaxValue : float.MinValue); } } 

那么你可以分析结果,看看斜率差异是否太大。

 bool IsLine(List<float> slopes) { const float IS_NOT_LINE_SLOPE_DIFF = 0.05f;//find an appropriate constant for your program float slopeVariation = 0f; for (int i = 0; i < slopes.Count - 1; ++i)//check all but the last element { slopeVariation = slopes[i] - slopes[i + 1]; if (Math.Abs(slopeVariation) >= IS_NOT_LINE_SLOPE_DIFF) return false; } return true; } 

你甚至可以得到斜率变化的中位数以得到更一般的结果。

当然,这不是最干净的,当然也不是解决问题的最好方法,但这是我要去做的方法。