-
注意这个手势不是GestureDetector,而是机器学习,视觉识别,识别出手势,从而进行不同的响应。
-
想到机器学习,就想到tensorflow,pytouch,那么适合移动端使用的,pytouch有TorchVision移动版、Mobile Interpreter,tensorflow可以使用TensorFlow Lite。
-
都是可以的,查了一下,google的开源项目比较多,文档和资源也比较丰富。所以采用了tflite。
-
下面开始整个过程:
-
查询google的开源项目,发现一个有意思的机器学习工具组件:MediaPipe。
这是它的官方介绍,一句话说的挺大啊MediaPipe offers open source cross-platform, customizable ML solutions for live and streaming media.
-
查看详细资料,不得了啊,支持的内容相当丰富呐。
人脸识别,面部动作捕捉,虹膜,手势识别,人体姿势识别等等,简直丰富极了。
因为之前使用过tf的ObjectDetection,整个过程充满了python、算法、参数、编译、高性能计算机等等,让人头大的厉害,这么多功能集成到一起,这个组件是不是得相当庞大啊! -
往下看,有各种移动端的实现,看样子不应该那么复杂啊。
因为移动端一般性能不太高,开发过程也相对SDK化,看它支持这么多,应该可以了解一下!
-
找到手势识别这一章节,发现google果然是google啊,使用方式那叫一个简单!解释的那叫一个清楚!甚至人家都给出了样例代码!
-
没错,你看到的就是将来你要使用的!这些代码,我猜你都修改不了其中的20% !
看看效果,嗯,这是人家google的:
-
说干就干,代码撸起来!
-
…漫长的封控,可恶的新冠,可恶的他!!!!
-
写完了。展示一下效果先(图两张,大gif等待下载中…):
注意等待!这里有一张贴图,特别大!
^
|
|
| -
嗯,看到这里的朋友,很有耐心。下面说一说这个项目里边的坑。
-
首先就是google本身也不是神,他们的东西有些也不是很合理。比如在hands这个项目中,用到了摄像头。google封装的工具类中,居然只支持前置和后置摄像头!!!
嗯,朋友你会说,这有什么问题呐,确实,如果是移动端专指手机的话,一般来说没有什么问题。近十年的手机都有前置和后置摄像头。但是,现在不够用!因为会有一些设备,比如电视盒子,比如车载设备,比如音箱,没有摄像头!
我不是胡扯,你先别说没有摄像头搞什么飞机的问题。我先解决一下没有摄像头的问题,我就买了一台USB摄像头,UVC标准摄像头。插上就可以用那种,嗯,电视盒子虽然不带摄像头,但是也有一个相机APP, 接上外置摄像头,打开就可以拍照的那种。既然相机可以使用,那么是不是我们就可以用它来做手势识别呢?错!默认人家不支持usb camera!
google封装的sdk也不好使了,mediapipe居然只有两个摄像头!front–back,肿么办?
改呗,找到几个关键类,找到关键算法,增加一个摄像头类型,external,这才可以。 -
其次,还有一些小问题。
比如mediapipe并不是原生支持手势识别,你说识别多少种手势那种。他们使用机器学习,深度学习的方法,利用人工智能,结合复杂神经网络,将人的手分割开来,识别出手的位置,并且把手切分为5个手指和一个原点。这个原点就是手腕位置,然后每个手指头使用4个点(指节两端)来标识。
有意思极了,如果某个人的一只手只有4根手指会怎么样呢?嗯,他会凭空想象出来那一根手指的位置,并且不断的颤抖。
在此基础之上,如果你想要它识别手势,就需要自己进行定义。比如,中国人表示的十个数字,外国人经常用的OK,蜘蛛人,兰花指等等。无非是判断哪根手指打开,哪根手指闭合,哪根手指跟哪根手指距离相近等等。
我的应用控制比较简单,只需要:拳头、五、OK,左、 右五个基本手势就可以了,但是左右两个手势可不是那么简单。因为你可以用拇指导向左边表示左,也可以用食指导向左边表示左,甚至可以用中指…🖕…
需要一点点算法。 -
最后就是一些小bug,比如经常会碰到的 EGL 0x300d错误的问题,也是他们sdk的一个bug。摄像头使用的是cameraX,原理是将摄像头的生命周期,与当前的Activity(页面)进行绑定,随着它生命周期变化而变化,息屏、退出时关闭摄像头,打开,继续显示时打开摄像头等等。
小bug就是有时候不好使。抛错EGL 0x300d,查google也不好使,找不到对应解决方案。解决这个问题时也有点钻牛角尖,坚决认为既然打开了摄像头,就要关闭它,有始有终,结果求而不得。最终发现,原来是tm操作干多了!不需要那么多操作。
于是改之!好在java是开源的(kotlin还不熟),反编译一下,改好了之后用咱自己的类,原理就是上面说的,跟页面绑定,页面打开时,摄像头自动打开,反之,如果想关闭摄像头,只需要解绑这个页面就好了。解绑之后,摄像头认为已经没有人需要它了,所以就自动关闭。
-
期间还遇到frameBuffer错误(framebuffer status (return 36054) ),也是比较难解决,看起来没有什么特别用处的代码,删了就是不好使。翻了半天历史,才找到根本原因,人家egl封装的挺好的,buffer没有处理完毕只是表象,根本原因是你切掉了人家处理的部分。。。。好吧,都是泪。
就这些吧,想起来的时候再补上。
欢迎遇到同样问题,或者类似诡异问题的朋友留言一起讨论。
评论区