C++从点识别形状

C++ recognize shape from points

本文关键字:识别 C++      更新时间:2023-10-16

我正试图找到一种识别点阵列中圆的算法。

比方说,我有一个可以或不能存储圆的点数组(这也意味着数组不必只存储圆的值,在圆的数据之前或之后可能会有一些"额外"的点)。

我已经尝试了一些算法,但没有一个能正确处理这些"额外"点。你对如何处理这个问题有什么想法吗?

编辑//我以前没提过。我想把这个算法用于圆圈手势识别。我想我会有数组中的数据(最后几秒),通过分析每个跟踪帧中的数据,我可以判断是否有圆圈手势。

首先,我计算每个X和Y分量的几何平均值(而不是算术平均值)。我选择几何平均值是因为一个特点是数值很小​​(关于算术平均值)​​比大价值更有影响力。

这将我引向所有观点的理论中心:circ_center

然后我计算每个点到中心的距离的标准偏差:stddev。这给了我量化变化量的"指标"。圆的一个性质是,所有圆周点与圆心的距离相同。使用标准dev,我试图测试您的点是否(具有最大方差阈值:max_dispersion)距离相等。

最后,我计算了最大距离阈值内的点与中心的平均距离,这给了我圆的半径:avg_dest。

参数:max_dispersion表示"cicle精度"。更小意味着更精确。min_points_needed是被视为周长的有效点的最小数量。

这只是一次尝试,我没有尝试过。让我知道。

我将尝试这个(伪语言)

points_size = 100; //number_of_user_points
all_poins[points_size]; //coordinates of points
//thresholds to be defined by user
max_dispersion = 20; //value of max stddev accepted, expressed in geometric units
min_points_needed = 5; //minimum number of points near the circumference
stddev = 0; //standard deviation of points from center
circ_center; //estimated circumference center, using Geometric mean
num_ok_points = 0; //points with distance under standard eviation
avg_dist = 0; //distance from center of "ok points"
all_x = 1; all_y = 1;   
for(i = 0 ; i < points_size ; i++)
{
    all_x = all_x * all_poins[i].x;
    all_y = all_y * all_poins[i].y;
}
//pow(x, 1/y) = nth root
all_x = pow(all_x, 1 / points_size); //Geometric mean
all_y = pow(all_y, 1 / points_size); //Geometric mean
circ_center = make_point(all_x, all_y);
for(i = 0 ; i < points_size ; i++)
{
    dist = distance(all_poins[i], circ_center);
    stddev = stddev + (dist * dist);
}
stddev = square_root(stddev / points_size);
for(i = 0 ; i < points_size ; i++)
{
    if( distance(all_poins[i], circ_center) < max_dispersion )
    {
        num_ok_points++;
        avg_dist = avg_dist + distance(all_poins[i], circ_center);
    }
}
avg_dist = avg_dist / num_ok_points;
if(stddev <= max_dispersion && num_ok_points >= min_points_needed)
{
    circle recognized; it's center is circ_center; it's radius is avg_dist;
}

我们能假设点的阵列大多在圆的圆周上或附近吗?

圆有圆心和半径。如果可以通过两个弦的垂线的交点来确定圆的中心坐标,那么所有true圆点都应该与中心点等距(r)。

假点可以通过与中心点不等距(+-)公差来消除。

这种方法的弱点是你能在多大程度上确定中心和半径?您可能想要尝试最小二乘法来计算中心坐标。

要回答最初提出的问题,我的方法是迭代这些点,并从每一组连续的三点中导出圆心。然后,取创建圆心位于某个绝对范围内的圆的最长连续点子集。然后确定这些点是否始终围绕圆的平均值旋转。您总是可以对任何丢弃的数据执行一些基本的试探法,以确定一个圆是否真的是用户想要制作的。

既然你说你想进行手势识别,我建议你考虑一种完全不同的方法。就我个人而言,我会首先创建一种可以用来描述手势的基本语言。它应该非常简单;我唯一会考虑的词是:

  • 开始-表示笔划的开始
    • 角度-笔划的起始角度。这应该是八个主要方向之一(N、NW、W、SW、S、SE、E、NE)或Any表示未对齐手势。您也可以添加组合机制,或者"轴对齐"或其他类似的东西
  • 结束-表示笔划的结束
  • 行程-表示笔划中的直线路径
    • 距离-此特定操作将使用的路径总长度的百分比
  • 转弯-表示笔划中的转弯
    • 方向-转向的方向。可以选择"左"、"右"、"任意"、"上一个"或"相反"
    • 角度-转弯的角度。我建议你只使用三个方向(90度、180度、270度)
    • 公差-偏离指定角度的最大公差。这两个方向的默认角度都应该在45度左右,这样才有可能匹配签名中的角度
    • 类型-硬或径向。径向角度将是沿着半径的笔划。硬角度将是围绕一个点的转弯
    • 半径-如果转弯是径向的,这就是转弯的半径(单位是总路径长度的百分比,当然还有适当的转换)

显然,你可以使角度更精细,但范围越粗,对输入误差的容忍度就越高。不过,过于宽容可能会导致误解。

如果你应用一些模糊逻辑,就不难把任何手势分解成这样的语言。然后,您可以创建一组手势"签名",描述可以执行的各种手势。例如:

//Circle
Start Angle=Any
Turn Type=Radial Direction=Any Angle=180deg Radius=50%
Turn Type=Radial Direction=Previous Angle=180deg Radius=50%
End
//Box
Start Angle=AxisAligned
Travel Distance=25%
Turn Type=Hard Direction=Any Angle=90deg Tolerance=10deg
Travel Distance=25%
Turn Type=Hard Direction=Previous Angle=90deg Tolerance=10deg
Travel Distance=25%
Turn Type=Hard Direction=Previous Angle=90deg Tolerance=10deg
Travel Distance=25%
End

如果你愿意,我可以研究一种算法,它可以取一个点云,并将其退化为一系列这样的命令,这样你就可以将它们与预先生成的签名进行比较。