背景
上一篇博客中试水了一下华为机器学习服务,感觉效果还是不错的,但是也不知道这些能力到底能干嘛,于是乎……就给我找到了一个大哥写的一篇讲微笑抓拍的文章,改吧了一下代码,顿时就可以用作自定义表情抓拍了。
链接戳下面↓
如果想看原版可以看原版
但是我就觉得太啰嗦了,重新整理了一下,原文里面有具体的代码配置,这里我都不多说了哈
代码已经上传到某位师兄的github上了,talk is cheap
原文的代码链接戳这里
效果展示
这个是华为官方放出来的人脸识别,看得出来在实时性上表现的很不错,同时可以支持识别人脸的朝向,支持检测人脸的表情(高兴、厌恶、惊讶、伤心、愤怒、生气),支持检测人脸属性(性别、年龄、穿戴),支持检测是否睁眼闭眼,支持人脸以及鼻子、眼睛、嘴唇、眉毛等特征的坐标检测
实际过程
原文中写了很多代码级的如何将华为机器学习服务中的人脸识别服务抽离出来,然后将这个功能重新封装。简而言之就是几点:
1. 添加一些配置项
其中包括maven的依赖,sdk的依赖(可以单独只引入人脸识别模型而不用把其他模型全部引用进来),相机权限的开通等,这些配置项这位善良的大哥已经在po出来的代码中都修改好了,非常的良心。
2. 代码开发
在这一部分,我理解他是先设定一些参数,比如最小人脸在相机中的比例,关键点的数量等等,然后把这些参数传给一个叫 MLAnalyzerFactory.getInstance().getFaceAnalyzer的分析器,这个分析器是华为机器学习服务SDK中提供的,感觉好像重写了他的回调函数,应该……就好了吧……
看起来很简单的样子,所以我就稍微改了一下下:
2.1 主要代码如下:
public void transactResult(MLAnalyzer.Result<MLFace> result) {
SparseArray<MLFace> faceSparseArray = result.getAnalyseList();
int flag = 0;
for (int i = 0; i < faceSparseArray.size(); i++) {
MLFaceEmotion emotion = faceSparseArray.valueAt(i).getEmotions();
if (emotion.getSmilingProbability() > smilingPossibility) {
flag++;
}
}
if (flag > faceSparseArray.size() * smilingRate && safeToTakePicture) {
safeToTakePicture = false;
mHandler.sendEmptyMessage(TAKE_PHOTO);
}
}
faceSparseArray应该是SDK中提供的一种数据结构,里面包含了一系列的人脸检测的参数,包括表情,性别、年龄、穿戴,是否睁眼闭眼,鼻子、眼睛、嘴唇、眉毛等特征的坐标检测等等。
在这里那位大哥只调用了表情的参数,
MLFaceEmotion emotion = faceSparseArray.valueAt(i).getEmotions();
然后紧接着做了一个判断,我理解的是如果微笑的概率大于你设定的特定阈值才会认为是微笑。
emotion.getSmilingProbability() > smilingPossibility
最后一部分就比较好理解了,如果出现了微笑的话就take photo啦
mHandler.sendEmptyMessage(TAKE_PHOTO);
这里还有一个小点需要注意,判断语句中的flag的值其实是实际检测到笑脸的人脸个数(原来是支持多人脸的-_-||),底下的smilingRate是作者随意定义的一个值,原文设立的是0.8,也就是说如果相机上有五个人,只要四个人笑就能够拍照啦~
2.2 我的代码如下:
需要修改的第一个地方是handler,把原来的handler里面删掉~
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case SMILE:
Toast.makeText(LiveFaceAnalyseActivity.this, "Smile", Toast.LENGTH_SHORT).show();
break;
case ANGRY:
Toast.makeText(LiveFaceAnalyseActivity.this, "angry", Toast.LENGTH_SHORT).show();
break;
case DISGUST:
Toast.makeText(LiveFaceAnalyseActivity.this, "disgust", Toast.LENGTH_SHORT).show();
break;
case FEAR:
Toast.makeText(LiveFaceAnalyseActivity.this, "fear", Toast.LENGTH_SHORT).show();
break;
case SAD:
Toast.makeText(LiveFaceAnalyseActivity.this, "sad", Toast.LENGTH_SHORT).show();
break;
case SURPRISE:
Toast.makeText(LiveFaceAnalyseActivity.this, "surprise", Toast.LENGTH_SHORT).show();
break;
default:
break;
}
}
};
需要修改的第二个地方是
public void transactResult(MLAnalyzer.Result<MLFace> result) {
SparseArray<MLFace> faceSparseArray = result.getAnalyseList();
for (int i = 0; i < faceSparseArray.size(); i++) {
MLFaceEmotion emotion = faceSparseArray.valueAt(i).getEmotions();
if (emotion.getSmilingProbability() > smilingPossibility) {
mHandler.sendEmptyMessage(SMILE);
}
if (emotion.getAngryProbability() > 0.85f) {
mHandler.sendEmptyMessage(ANGRY);
}
if (emotion.getDisgustProbability() > 0.85f) {
mHandler.sendEmptyMessage(DISGUST);
}
if (emotion.getFearProbability() > 0.85f) {
mHandler.sendEmptyMessage(FEAR);
}
if (emotion.getSadProbability() > 0.85f) {
mHandler.sendEmptyMessage(SAD);
}
if (emotion.getSurpriseProbability() > 0.85f) {
mHandler.sendEmptyMessage(SURPRISE);
}
}
}
懂的人都知道我也没干啥,只是对着文档找到了支持的所有表情然后依次识别,看看你到底是什么表情~
具体的参数可以参考:
同时除了表情
里面提供了超级多的参数可以调用
具体调用如下:
总结
表情识别就这样做完啦,感谢那位大哥的分享,代码写的很优秀~ 一下子除了表情,开闭眼识别,帽子胡子识别都可以做了~ 哈哈哈哈哈
效果不错哟