看过上一篇「
一个很糙的字母手势识别方案
」文章并尝试了的同学,就一定知道,「糙手势」的识别是有多糙,糙的只能识别字母「C」。
今天这篇就用 Android 自带的 gesture API 来实现更为精准的识别。
看到这里,有的同学可能就会说了,「标题党,哪有机器学习!」。别急,认真看,认真学。先上效果图,注意底部识别分数变化,至于为什么粉红色,这是「社会人」小猪佩奇的颜色好吧~
编不下去了,这个画板源码部分借鉴了 github 下面链接的控件,TA用的就是粉色,我没改~
https://github.com/imaiya/PainterView
故事的开端
即使在「糙手势」方案中学习到了手势识别的大概套路:「先存储后识别」,但心痛于其感人的识别率,在还没写上一篇文章之前,就开始搜寻更为精准的方案。
可能是从未接触过此类功能, 苦苦搜寻之下才找到了一个网友的帖子,其中的关键字「GestureLibrary」引起了我的注意。
我在 AndroidXref 中查询了一下,还真有这个类,大概了解并确定怎么用后,将「更精准的方案」之类的字眼写入前一篇文章的末尾,给大家留有悬念,并开始研究了起来。
送上一张 gesture API 的全家福:
一开始我直接投入研究如何使用这些API了,所以并未注意到其中的 「Instance.java」和「Learner.java」两个类。这两个类的命名是有玄机的。
如何使用?
我们知道,一个手势,是个平面,多数情况下是个字符,字则由笔画组成。笔画是一条线。笔画又是由点组成。
GesturePoint.java
-> 是「点」,它除了x,y属性还有时间戳属性。
GestureStroke.java
-> 是「线」,它由GesturePoint组成。
Gesture.java
-> 是「面」,它由一个或多个GestureStroke组成。
以上三个类是基本,构成了整个手势数据结构体系。如果你也想写个佩奇色的画板,那你就需要知道这三个类的关系。直接使用下面这个类就不需要关注。
GestureOverlayView.java
-> 为了方便画图,你可以在 xml 中直接使用 GestureOverlayView。使用这个 View 的好处是:不需要接触到 point 和 stroke 的概念,注册的回调会直接返回 Gesture。可以参考下面这个链接。
http://www.runoob.com/w3cnote/android-tutorial-gestures.html
无论哪种,手势数据采集好后都需要存储下来。
GestureStore.java
-> 提供存储手势的接口,以及识别接口。一个手势名,可对应多个手势数据。从addGesture()方法可以看出,一个手势名,对应着一个手势ArrayList。
GestureLibrary.java
-> 抽象类,持有GestureStore对象,封装了其大部分public方法。我认为目的是为了分离GestureStore中的复杂实现。每一个library对象都对应一个数据集文件。
GestureLibraries.java
-> 进一步封装了GestureLibrary,内部提供两个GestureLibrary私有实现类,以四个public static 方法暴露出来,方便数据的存储和加载,如下截图。
Prediction.java
-> 简单的类,代表预测结果值。name -> 手势名,score -> 得分。得分越高,越相似。
gesture API 中的机器学习
没错,gesture api 内部是通过机器学习来进行手势识别的,说是手势预测更贴切些。
一开始我是不知道的。由于好奇它的实现方式,以及对比方式,我阅读了它的源码,才得以发现。
机器学习中有三种学习技巧,分别是:
监督式学习(Supervised learning)
半监督式学习(Semi-supervised learning)
非监督式学习(Unsupervised learning)
其中难度从上到下依次递增。
gesture API 则为「监督式学习」。为什么?
为了更好的理解,先来了解下机器学习的基本术语。
机器学习术语:
监督式机器学习:机器学习系统通过学习如何组合输入信息来对从未见过的数据做出有用的预测。
标签:我们要预测的事物。在本篇文章中,假如我们要 A 字母进行识别预测,那 A 就是标签。更通俗点,每一个「手势名」就是一个「标签」。
特征:特征是输入的变量。这篇中,我们录入的每一个「手势数据」就是一个「特征」。
样本:样本表示数据的特定实例。样本分为两类:有标签样本和无标签样本
有标签样本:同时包含「标签」和「特征」。在本篇中,一个有标签样本就是「手势名」+「你画的手势数据」。通常有标签样本用来进行模型的训练。
无标签样本:不包含「标签」,只包含「特征」的样本。在本篇中,无标签样本就是我后面要识别的手势,仅有「手势数据」。根据训练出来的模型推断出此样本的「标签」,也就是「手势名」。
模型:模型定义了特征与标签之间的关系。主要分为两个阶段:训练与推断
训练:表示创建或学习模型。也就是说,向模型展示有标签样本,让模型逐渐学习特征与标签之间的关系。
推断:表示将训练后的模型应用于无标签样本,做出有用的预测。
对于不同的问题,模式种类也不同:对于连续性问题,使用回归模型;对于离散问题,使用分类模型。
gesture API 是一个分类模型,其中的分类器根据不同配置(超参数),采用取不同的相似性算法:欧氏距离(Euclidean Distance) 和 夹角余弦(Cosine)
涉及的类主要是:
有兴趣的同学可以继续研究。我没有太过于深入,因为已经到最深层的具体实现细节了。
最后
领取专属 10元无门槛券
私享最新 技术干货