最近由于公司业务方面的需要,简单研究了一下人脸识别方面的问题,在这里分享一下最近使用的心得和一些技术要点,主要分为以下几个方面:
- 人脸识别的api接口提供商
- 本文使用api接口
- 相关文档的使用
- 静默拍照的集成
人脸识别的api接口提供商
①GOOGLE CLOUD VISION API
②FACE++
③阿里
④汉王智远
⑤云从科技
这些是网上几家比较有名的可以提供人脸识别接口的供应商,根据我们的业务需求,最后从GOOGLE和FACE++这两家选择了服务,因为谷歌的api接口里没有提供年龄的这一项数据,所以最终就确定了使用face++作为我们以后开发一个方向。
本文使用api接口
本文使用的是face++的新接口,有一点比较坑的是这里得说明一下,face++现在新的接口已经改版,之前的api还可以使用但是已经没办法申请key了,网上关于face++的说明文档大部分都是使用他们以前过时的api。
之前本来这块在githup上面down了几个demo,然后在各大博客里也找到了一些文档的使用方法,然后把demo直接导进我的项目了就直接用了,但是后来发现了个问题,就是照片识别的速度特别慢,当时猜测可能是申请的key过时了,所以自己又去face官网注册了账号,然后申请了免费试用的key,居然发现他这个免费的key居然不和你的application绑定使用(虽然申请key时候他有这个选项,但是根本没什么鸟用)但是后来想一想既然是试用的key所以绑不绑定都无所谓了,所以直接把key和secret直接粘贴了进去,窝巢,居然不好使,通过我最后和他们客服技术支持的交流,终于发现了,原来是接口的问题,现在的key不适用于以前的接口,那个demo用的是老接口。所以,知道了这个原因之后,索性直接去看他们的官方文档说明了,然后参考了hyman的代码,自己改了改基本上完成的差不多了。
相关文档的使用
第一步
来到face++官方网站,注册账号,如果是弄demo的话自己注册一个免费的key,然后还有一个secret,这很简单,我就不贴图片了。
第二步
插入一个小插曲,每天都用这个gradle,一直不知道是干啥的,今天查了查用处。
(gradle是一个工程构建工具,java代码,和资源文件需要经过sdk里的一些程序如aapt等处理,才能形成apk包。gradle就是把那些步骤变得简单化。相当于eclipse中的ant吧!一句话概括就是:依赖管理和任务执行。像Ruby里面的bundler+rake,像iOS中的cocoapods,像node中的npm+grunt.通俗的讲就是:你的项目需要哪些第三方库,它帮你把它们都下载下来,并且编译好放到指定的位置,你就直接可以import后用了。它本身是基于Apache的an…)
我调用的是Detect API 这里是接口官方文档的说明
https://console.faceplusplus.com.cn/documents/4888373
简单说一下请求参数,api_key和api_secret就是你申请的key和secret,
url需要说明一下,现在只能通过post方式上传url,可以上传网络url地址或者是图片的二进制文件。官网并没有提供此方面的demo,只给了一个离线sdk的demo,这里提供一些核心代码。
//CommonOperate类是Face++提供的网络请求封装类jar包里的,传入key和secret
CommonOperate commonOperate = new CommonOperate(KEY, SECRET);
//得到bitmap
Bitmap bmSmall = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight());
//字节输出流
ByteArrayOutputStream stream = new ByteArrayOutputStream();
//bitmap图片压缩,这里表示不压缩
bmSmall.compress(Bitmap.CompressFormat.JPEG, 100, stream);
//获取图片的字节数组
byte[] arrays = stream.toByteArray();
//调用接口返回数据 CommonOperate.detectByte里面封装了 post方法
String content = new String(commonOperate.detectByte(arrays, 0, "gender,age").getContent());
//得到网络返回的数据
JSONObject jsonObject = new JSONObject(content);
静默拍照的集成
这是最后一个功能,简单说两句,核心思想就是把SurfaceView调成很小很小,以及权限的使用,此外连续拍照的时候要注意及时回收Camera相机资源,以及设置线程休眠,给相机充分的打开时间,贴出部分代码在这里
<!-- 调用相机权限 -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.INTERNET"/>
<!-- 读写SD卡权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
// 对焦并拍照
private void autoFocus() {
try {
// 因为开启摄像头需要时间,这里让线程睡两秒
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 自动对焦
myCamera.autoFocus(myAutoFocus);
// 对焦后拍照
myCamera.takePicture(null, null, myPicCallback);
}
// 初始化surface
@SuppressWarnings("deprecation")
private void initSurface() {
// 初始化surfaceview
if (mySurfaceView == null && myHolder == null) {
mySurfaceView = (SurfaceView) findViewById(R.id.camera_surfaceview);
// 初始化surfaceholder
myHolder = mySurfaceView.getHolder();
}
}
/**
* 开始拍照
*/
private void startTakePhoto() {
//初始化surface
initSurface();
//这里得开线程进行拍照,因为Activity还未显示完全的时候是无法进行拍照的,SurfacaView必须先显示
new Thread() {
@Override
public void run() {
super.run();
//如果存在摄像头
if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
//获取摄像头
if (openFacingFrontCamera()) {
Log.i(TAG, "openCameraSuccess");
//进行对焦
autoFocus();
} else {
Log.i(TAG, "openCameraFailed");
}
}
}
}.start();
}
// 自动对焦回调函数(空实现)
private Camera.AutoFocusCallback myAutoFocus = new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
}
};
Demo地址已经上传:
http://download.csdn.net/download/baidu_33776259/9792475