【问题标题】:Finding a "movement direction" (angle) of a point找到一个点的“运动方向”(角度)
【发布时间】:2015-07-31 18:14:26
【问题描述】:

我正在从事一个非常酷的项目,我正在收集有关光标移动的数据,但我遇到了一个问题,我认为我可以使用一些帮助。我不断地读取有关光标 x 和 y 位置的数据(以及其他相关数据),一旦光标在 y 维度上超过某个阈值,我需要计算移动方向(角度)。让我用我画的图来说明:

往往会发生的情况是光标沿一条直线移动,但随后向移动的末端弯曲。我需要计算 theta,即蓝色矢量相对于正 x 轴的角度。我想出的想法是使用最后 2 个样本来很大程度上确定运动方向是什么,否则如果我使用太多样本,我会扭曲实际角度。举一个极端的例子,让我用另一张照片跟进:

这里每个点代表一个样本。请注意,如果我使用 BOTH 点,我想要的真实角度将是错误的(再次,我需要找到光标最后移动的方向,即在行尾绘制的矢量)。我不希望这种情况出现太多,但想知道如果出现这种情况是否有办法解决。

最后,请注意这些运动可以发生在第一象限或第二象限,如果有影响的话。

我真的很感激这里的任何帮助。我正在用 C++ 编写代码,但我想我可以翻译任何答案。谢谢。

【问题讨论】:

  • 您至少需要两个点才能找到方向。除非您的采样非常精细,否则您无法避免此问题。
  • 如果您使用光标的分辨率,则移动方向不能与最后两点之间的计算方向不同。但是如果您用于计算的分辨率小于光标的分辨率(光标的移动),则可能会出现第二个数字。
  • 这是有道理的。你能帮我解决第一个案例吗,用两点?如果我想使用超过 2 个怎么办?我想我不会,我实际上只是感兴趣。
  • 以弧度表示的角度等于atan2(y2-y1, x2-x1)
  • 如果你想用超过 2 个点来确定方向,你就会为自己创建一个线拟合问题。解决方法很多,不简单。

标签: c++ algorithm matlab math angle


【解决方案1】:

这应该让你开始http://jsfiddle.net/0ao9oa7a/

  • 获取所有记录点
  • 过滤掉靠近的点(我使用 5 个像素)
  • 找出每对连续点的角度 (atan2)
  • 找出每对连续角度之间的绝对差
    • 丢弃最大差之前的所有角度
  • 平均剩余角度(平均所有点向量,然后将 atan2 返回到一个角度)

代码

function process(points) {
    if(points.length === 0) { 
        txt = "Not enough points\n" + txt;
        return null; 
    }
    // compress points, removing those that are too close together
    var newPoints = [];
    newPoints.push(points[0]);
    for(var i = 1; i < points.length; i++) {
        if(Math.sqrt(Math.pow(points[i].x - newPoints[newPoints.length - 1].x, 2) + Math.pow(points[i].y - newPoints[newPoints.length - 1].y, 2)) > 5) {
            newPoints.push(points[i]);
        }
    }
    points = newPoints;
    if(points.length < 2) { 
        txt = "Not enough points\n" + txt;
        return null; 
    }
    // get all of the angles
    var angles = [];
    for(var i=0; i < points.length - 1; i++) {
        var rad = Math.atan2(points[i + 1].y - points[i].y, points[i + 1].x - points[i].x);
        angles[i] = rad;
        txt += "x: " + (points[i].x|0) + " y: " + (points[i].y|0) + " x: " + (points[i+1].x|0) + " y: " + (points[i+1].y|0) + " [" + ((rad * 180 / Math.PI)|0) + "]" + "\n";
    }
    txt += "\n";
    // get all of the diffs between angles
    // save the index of the max diff
    var absDiffs = [];
    var maxDiff = -1;
    var maxDiffAngleIndex = -1;
    for(var i=0; i < points.length - 1; i++) {
        var delta = Math.abs(angles[i] - angles[i + 1]);
        if(delta >= maxDiff) {
            maxDiff = delta;
            maxDiffAngleIndex = i + 1;
        }
    }
    if(maxDiffAngleIndex == -1) {
        txt = "Angle: " + angles[0] + " : " + (angles[0] * 180 / Math.PI) + "\n" + txt;
        return angles[0];
    } else if(maxDiffAngleIndex == angles.length - 1) {
        txt = "Angle: " + angles[angle.length - 1] + " : " + (angles[angles.length - 1] * 180 / Math.PI) + "\n" + txt;
        return angles[angles.length - 1];
    } else {
        // find the average angle from the index to the end
        var sumX = 0;
        var sumY = 0;
        for(var i = maxDiffAngleIndex; i < angles.length; i++) {
            sumX += Math.cos(angles[i]);
            sumY += Math.sin(angles[i]);
        }
        var avgX = sumX / (angles.length - maxDiffAngleIndex);
        var avgY = sumY / (angles.length - maxDiffAngleIndex);
        //
        var avgAngle = Math.atan2(avgY, avgX);
        txt = "Angle: " + avgAngle + " : " + (avgAngle * 180 / Math.PI) + "\n" + txt;
        return avgAngle;
    }
}

【讨论】:

    【解决方案2】:

    如我所见,一个点的“运动方向”(角度)将是两个点的角度系数,向量末端的一个点另一个在开始时。

    因为我们只能找到两个点的角度,所以我们可以画一条线,因为方向向量是(B-A),其中AB 是我已经告诉过你的点。

    我们可以用直线的角系数公式来计算

    m = Tan θ = Δy / Δx

    这很简单:

    Tan θ = (yB – yA) / (xB – xA)

    其中θ是“运动方向”(角度)(x,y)是A点和B点的坐标

    说到象限,你只需要使用三角圆就可以知道 Tan θ 值的正弦,所以看看这张图片:

    当然,在你找到 Tan θ 的值之后,你需要用它来找到arctan θ,这将是你的最终答案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-05
      • 1970-01-01
      • 2017-07-21
      • 2015-12-23
      • 1970-01-01
      相关资源
      最近更新 更多