187
|
Unheilig Adonis González · 技术社区 · 11 年前 |
1
418
有时花点时间重新发明轮子真的很有用。正如您可能已经注意到的那样,有很多框架,但在不引入所有复杂性的情况下实现一个简单但有用的解决方案并不难。(请不要误解我的意思,出于任何严肃的目的,最好使用一些成熟且已证明稳定的框架)。 我将首先介绍我的结果,然后解释它们背后简单明了的想法。
您将在我的实现中看到,不需要分析每一个点并进行复杂的计算。这个想法是为了发现一些有价值的元信息。我会使用 tangent 例如:
让我们确定一个简单明了的模式,这是所选形状的典型模式:
因此,基于该思想实现圆检测机制并不难。请参阅下面的工作演示(对不起,我使用Java作为提供这个快速且有点脏的示例的最快方法):
在iOS上实现类似的行为应该不是问题,因为您只需要几个事件和坐标。类似以下内容(请参见 example ):
有几种可能的增强功能。 从任何一点开始 由于以下简化,目前的要求是从顶部中点开始绘制圆:
请注意的默认值
顺时针和逆时针 为了支持这两种模式,您需要使用先前增强中的循环缓冲区,并在两个方向上进行搜索:
绘制椭圆
您已经拥有了所需的一切
只需使用这些数据:
其他手势(可选)
最后,您只需要正确处理以下情况
使现代化 这个小PoC得到了相当高的关注,所以我确实更新了一些代码,以使其顺利工作,并提供了一些绘图提示、突出显示支持点等: 这是代码:
|
2
16
用于检测形状的经典计算机视觉技术是霍夫变换。霍夫变换的一个优点是它对部分数据、不完美数据和噪声都非常宽容。将霍夫用于圆: http://en.wikipedia.org/wiki/Hough_transform#Circle_detection_process 考虑到你的圆圈是手绘的,我认为霍夫变换可能很适合你。 这是一个“简化”的解释,我很抱歉没有那么简单。其中大部分来自我多年前做的一个学校项目。 霍夫变换是一个投票方案。分配一个二维整数数组,所有元素都设置为零。每个元素对应于正在分析的图像中的单个像素。该阵列被称为累加器阵列,因为每个元素都将累积信息、投票,指示像素可能位于圆或弧的原点的可能性。 将梯度算子边缘检测器应用于图像,并记录边缘像素或边缘。边缘像素是相对于其相邻像素具有不同强度或颜色的像素。差异的程度称为梯度幅度。对于足够大小的每个边缘,应用将递增累加器阵列的元素的表决方案。被递增(投票支持)的元素对应于通过所考虑的边缘的圆的可能起源。理想的结果是,如果存在弧,那么真正的起源将比虚假的起源获得更多的选票。 注意,为了投票而访问的累加器阵列的元素围绕所考虑的边缘形成一个圆圈。计算要投票的x,y坐标与计算正在绘制的圆的x,y坐标相同。 在手绘图像中,您可以直接使用设置的(彩色)像素,而不是计算边缘。 现在,对于位置不完全的像素,您不一定会得到一个具有最大票数的累加器数组元素。您可能会得到一个相邻数组元素的集合,其中包含一堆投票,即一个集群。这个星团的重心可能为原点提供了一个很好的近似值。 请注意,您可能需要对半径R的不同值运行霍夫变换。产生更密集的投票簇的是“更好”的拟合。 有各种各样的技术可以用来减少虚假来源的选票。例如,使用扁边的一个优点是,它们不仅有大小,而且还有方向。在投票时,我们只需要在适当的方向上对可能的起源进行投票。接受投票的地点将形成一个弧形,而不是一个完整的圆圈。 这是一个例子。我们从一个半径为1的圆和一个初始化的累加器数组开始。由于每个像素都被视为潜在的原点,因此被投票支持。真正的原籍国获得的选票最多,在这种情况下是四票。
|
3
6
这是另一种方式。使用UIView touchesBegan、touchesMoved、touchesEnded和向数组添加点。将数组一分为二,并测试一个数组中的每个点与另一个数组的对应点的直径是否与其他所有对的直径大致相同。
听起来还好吗?:) |
4
3
我不是形状识别专家,但以下是我如何处理这个问题。 首先,在将用户的路径显示为徒手时,秘密地累积点(x,y)样本列表以及时间。您可以从拖动事件中获取这两个事实,将它们封装到一个简单的模型对象中,并将它们堆积在一个可变数组中。 你可能想经常取样,每0.1秒取样一次。另一种可能性是开始 真正地 频繁,可能每0.05秒一次,并观察用户拖动的时间;如果它们拖的时间超过一定的时间,那么将采样频率降低(并丢弃任何可能错过的采样)到0.2秒左右。 (不要把我的数字当成福音,因为我刚刚把它们从帽子里拿出来。实验一下,找到更好的值。) 其次,对样本进行分析。 你会想要得到两个事实。首先,形状的中心,它(IIRC)应该只是所有点的平均值。第二,每个样本距该中心的平均半径。 如果如@user1118321猜测的那样,您想要支持多边形,那么分析的其余部分包括做出决定:用户是想要画一个圆还是一个多边形。您可以将样本视为一个多边形来开始进行确定。 您可以使用以下几个标准:
第三步也是最后一步是创建以先前确定的中心点为中心、具有先前确定的半径的形状。 不能保证我上面说的任何话都会奏效或有效,但我希望它至少能让你走上正轨。如果有人比我更了解形状识别(这是一个很低的门槛),请随时发表评论或自己的回答。 |
5
3
一旦确定用户在开始绘制形状的位置完成绘制,就可以对用户绘制的坐标进行采样,并尝试将其拟合到一个圆中。 这里有一个MATLAB解决方案来解决这个问题: http://www.mathworks.com.au/matlabcentral/fileexchange/15060-fitcircle-m 这是基于论文 圆和椭圆的最小二乘拟合 作者Walter Gander、Gene H.Golub和Rolf Strebel: http://www.emis.de/journals/BBMS/Bulletin/sup962/gander.pdf 新西兰坎特伯雷大学的Ian Coope博士发表了一篇论文摘要:
http://link.springer.com/article/10.1007%2FBF00939613 MATLAB文件可以计算非线性TLS和线性LLS问题。 |
6
2
我有一个训练有素的1美元识别器,运气很好( http://depts.washington.edu/aimgroup/proj/dollar/ ). 我用它来画圆、线、三角形和正方形。 这是很久以前的事了,在UIGestureRecognizer之前,但我认为创建合适的UIGesture Recognizer子类应该很容易。 |
7
0
以下是一种相当简单的使用方法:
假设这个矩阵网格:
将一些UIViews放在“X”位置,并测试它们是否命中(按顺序)。如果他们都按顺序被击中,我认为让用户说“干得好,你画了一个圆圈”可能是公平的 听起来还好吗?(而且很简单) |
8
0
用户触摸的像素是x-y坐标的集合。Ian Coope在这里提出了一种用于非迭代拟合圆的线性最小二乘算法: https://ir.canterbury.ac.nz/handle/10092/11104 其思想是使用变量的简单变化来使拟合线性化。 我做了一个简单的python实现,如下所述: https://scikit-guess.readthedocs.io/en/latest/generated/skg.nsphere_fit.html . 你可以在GitHub上找到来源: https://github.com/madphysicist/scikit-guess/blob/master/src/skg/nsphere.py 。由于该函数只有大约20行长,只要您可以访问允许反转矩阵的库,就可以将其翻译成您选择的语言。事实上,这里描述的问题只需要反转3x3矩阵,这可以通过算术运算手动完成。 这里有一个针对2D情况的简单Java实现。我没有包括缩放,这对于生产应用程序来说可能是个好主意,或者如果你有大量的像素,但这是一个非常简单的预处理和后处理步骤,留给读者练习:
这是我画的一个手绘圆的样本,以及当所有黑色像素的坐标都通过时,这个解决方案的拟合:
|