简介 准备工作 添加SDK到工程 Demo APP使用 开发示例 SDK详细接口说明
1 简介
商米AI识客SDK是一个可以配套商米AI识客摄像机(以下简称FS)和安卓收银硬件设备(简称POS),为商户提供完整会员识别解决方案的开发包,包括会员注册、会员进店实时提醒、会员到柜重识别等功能模块。当前提供的是安卓版本SDK,以aar包形式发布,并提供Demo APP以供参考。
详细说明:
1. C/C++ library实现人脸特征提取,人脸比对等算法功能以及人脸库管理(人脸库的添加、查询、删除等操作)等功能。 2. JNI层封装C/C++实现的功能,为Java上层提供native接口。 3. Java层 人脸识别API 使用native层提供的接口为上层 APP提供人脸特征提取、人脸比对以及人脸库管理等接口,AI识客API提供配置FS、向FS注册人脸和获取FS人脸识别消息的功能。 4. Demo APP,这里是示例代码,仅供开发者参考,非完美的APP,使用Java API层提供的功能实现人脸识别、人脸比对、人脸特征库管理、AI识客设备配置等业务层功能。
2 准备工作
SDK开发包采用一个设备一个Licence认证机制。先向商米售前技术团队申请SDK,而后通过SDK或Demo APP获取硬件指纹,再申请Licence。
2.1 申请SDK
步骤一: 联系商米售前技术团队,提供如下信息:
内容 说明 客户名称 软件商公司名称 业务场景 简单描述业务场景
步骤二 : 商米售前技术团队根据客户的申请,为客户提供SDK开发包。SDK开发包的内容如下:
序号 文件/文件名 说明 1 FaceSdkDemo Demo工程源码 2 facelib_xxxx.aar 人脸识别开发套件,xxxx为版本号。 3 ipcsdk_xxxx.aar FS开发套件,xxxx为版本号。 4 asset 人脸识别开发套件所需资源文件(人脸识别的模型文件、配置参数等) 5 readme.md SDK开发指南
2.2 申请Licence
获取SDK开发包后,按如下操作,提供硬件指纹信息给商米售前技术团队:
在POS设备上安装FaceDemo.apk,运行FaceDemo APP,给APP授权存储、摄像头权限。APP会在/sdcard目录生成一个硬件指纹信息文件device_fingerprint.txt。 或者集成SDK开发包后,调用SDK API SunmiFaceSDK.getDeviceFingerprint获取硬件指纹信息
商米售前技术团队会提供以下内容:
内容 说明 licence_valid.txt 用于激活人脸识别的SDK的Licence appid、secret_key、激活码 用于激活FS的通信使用
备注:
licence_valid.txt文件的使用方法请阅读章节3.4 ,放到指定的目录下即可。 appid、secret_key、激活码的使用请阅读章节4.1 ,替换源码中的内容编译出Demo APP。
2.3 开发调试环境
在软件正式发布上线之前,建议在UAT环境下与FS进行联调,请参考升级开发环境固件 将FS固件升级到UAT环境,因此商米首先提供UAT环境下的appid、secret_key和激活码 ,开发完成后再提供Release环境的 appid、secret_key和激活码 ,并参照升级线上环境固件 将FS固件升级到Release环境。
3 添加SDK到工程
SDK开发包开发环境:
开发工具:Android Studio
NDK版本:android-ndk-r14b (可以使用高版本)
Android版本:Android 7.0及以上
3.1 Android Studio导入SDK开发包
右键点击app,选择New->Module->Import .JAR/.AAR Package
点击Finish 即导入aar模块。
按同样的操作可以导入人脸识别facelib_xxxx.aar模块。
3.2 权限申明
SDK开发包涉及网络操作以及wifi相关操作,需要在 AndroidManifest.xml 增加以下权限:
‹uses-permission android:name="android.permission.INTERNET" /›
‹uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /›
‹uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /›
‹uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" /›
Demo APP还涉及到camera和存储器相关操作,还需要在AndroidManifest.xml增加以下权限:
‹uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/›
‹uses-permission
‹uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /›
‹uses-permission android:name="android.permission.CAMERA" /›
3.3 导入asset资源
运行SDK开发包还需要导入asset资源文件,用于初始化人脸识别SDK。
说明:资源文件在APP启动的时需要复制到APP的运行目录。
3.4 导入licence文件
获取到licence_valid.txt文件,可以放到asset资源目录,也可以放到sdcard目录。
放到assets资源目录,则需要把licence_valid.txt文件从资源文件复制到app的工作目录。 如果放到sdcard目录,则需要app申请sdcard读取权限。
无论哪一种情况,最后使用的时候,需要传递licence_valid.txt文件的路径,以激活人脸识别SDK。人脸识别SDK详细初始化代码如下:
public boolean initFaceSdkInstance(Context context, String licencePath) {
//初始化配置文件
int ret = SunmiFaceSDK.init(confPath);
if (licencePath == null) {
Log.d(TAG, "Please input licence");
return false;
}
File f = new File(licencePath);
if (!f.exists()) {
Log.d(TAG, "licence is not exist");
return false;
}
String licence = readToString(licencePath);
//验证Licence
ret = SunmiFaceSDK.verifyLicence(context, licence);
if (ret != 0) {
Log.d(TAG, "Licence is not OK ErrorCode " + ret);
return false;
}
//设置配置参数
SunmiFaceConfigParam param = new SunmiFaceConfigParam();
param.setDistance_threshold_(1.0f); //范围在1.0~1.2比较合适,越小,人脸识别越严格
param.setYaw_threshold_(50.f);//人脸姿态阈值,设置较小的人脸姿态阈值,阈值越小,人脸姿态要求越严格,保证相对正面的人脸姿态做识别
param.setPitch_threshold_(50.f);
param.setRoll_threshold_(50.f);
param.setMin_face_size(60);//最小人脸检测尺寸,较大较清晰的人脸识别较准确
param.setImage_quality_threshold_(10);//阈值越高,人脸清晰度越好,人脸识别越准确
param.setMin_luminance_(10);//最小光照
param.setMax_luminance_(180);//最大光照
param.setLiveness_on_(true);//开启人脸活体检测
param.setThread_num_(1); //使用一个cpu核心执行人脸检测,人脸识别
//设置配置参数
ret = SunmiFaceSDK.setConfig(param);
if (ret != 0) {
Log.d(TAG, "param is not init");
return false;
}
return true;
}
public void init(Context context) {
//设置licence_valid.txt为sd卡路径,也可以换成app运行工作目录。
String licencePath = Environment.getExternalStorageDirectory() + File.separator + "licence_valid.txt";
initFaceSdkInstance(context, licence_path);
// 调用IPCameraManager静态类getInstance初始化IPCManger对象
mIPCManager = IPCameraManager.getInstance(context);
}
4 Demo APP
4.1 编译Demo APP
(1) Android studio 导入Demo APP源代码,File->open,选中Demo APP工程目录。
(2)在文件local.properties文件增加ndk编译程序路径:ndk.dir=D\:\ndk\\android-ndk-r14b。路径地址为ndk存储路径。
(3)修改app module目录下的源代码MainActivity.java文件,激活FS设备。代码如下:
init函数的三个参数为app_id, secret_key, 激活码。这三个参数是由2.2 申请licence 获得。
//init三个参数为:app_id, secret_key, 激活码
manager.init("test", "123456", "123456");
(4)Build->Make Project,编译工程,生成APP。
4.2 Demo APP工程目录
4.2.1 app Module
app Module是Demo的入口。其中包含了各个模块的入口函数调用。
4.2.2 commonlib
commonlib Module包含了整个Demo通用的接口。其中包含摄像头管理,工具类。如下图:
4.2.2.1 FaceCameraManager
POS设备自带的摄像头采用Android系统提供的操作方式。外置USB 摄像头使用第三方UVC库提供的操作方式。 FaceCameraManager类统一管理Android POS设备自带的摄像头和外置USB摄像头,封装Android系统操作方式和UVC操作方式,对上层APP应用提供统一的方法:startPreview和 stopPreview。
注: 本文的摄像头 和AI识客摄像机 是两个概念。本文中的摄像头 指POS设备自带的摄像镜头和外置USB摄像头 (兼容UVC协议的USB摄像镜头)。 AI识客摄像机 是一款独立的设备,运行单独的操纵系统,能够独立的进行人脸识别。在此需要注意区分。
4.2.2.2 NormalCameraManager
NormalCameraManager使用Android系统提供的摄像头操作方式,实现startPreview和stopPreview。并提供获取摄像头每一帧数据的接口。
4.2.2.3 UVCCameraManager
UVCCameraManager使用第三方库UVC lib提供的方法用于操作外置USB摄像头,实现startPreview和stopPreview。 并提供获取摄像头每一帧数据的接口。
4.2.2.4 ByteUtils
ByteUtils提供Byte操作的一些通用方法。
4.2.2.5 DBHelper
DBHelper提供创建数据的方法。
4.2.2.6 ImageUtils
ImageUtils提供图片操作的一些方法。
4.3 libuvccamera
libuvccamera Module采用第三方库开源库libuvccamera。
4.4 facedemo
facedemo 使用人脸识别API和AI识客API实现会员注册、会员管理、会员查询等功能。
4.5 ipcdemo
ipcdemo 主要用于AI识客设备配置。
5 开发示例
5.1 配置FS
首次使用FS时,需要激活设备。激活FS时,FS必须连接互联网,进行在线激活。当FS激活后,可以离线使用。使用FS开发包按照以下步骤即使用FS:
5.1.1 FS开发包初始化
通过商米售前技术团队申请Licence后,会获取以下信息。使用以下信息进行SDK初始化:
app_id:激活与API调用校验使用的账号。
secret_key:API调用所需的签名密钥。
licence:激活API所需的激活码。
初始化代码如下:
IPCameraManager mIPCameraManager = IPCameraManager.getInstance(context);
mIPCameraManager.init(app_id, secret_key, licence);
5.1.2 FS设备配网
FS可以通过有线(以太网卡)和无线(wifi)接入互联网。无论哪种方式,FS必须和POS设备处于同一局域网下。两种接入方式配网方式如下:
有线接入:
有线接入只需通过网线把FS设备和POS设备接入到同一局域网即可,不需要其它设置。有线接入优先级高于无线接入。如果有线接入后,无线接入不可用。
无线接入:
无线接入方式相对要复杂点,需要进行无线配网,步骤如下:
Android POS设备连接AI识客设备AP热点
1. POS设备无线网卡扫描FS设备的AP热点,一般AP热点的名称为SUNMI_XXXX,其中XXXX为MAC地址最后2个字节的16进制数字,MAC地址可以通过设备机身后背的标贴或者包装盒的标贴查到,AP热点本身是无加密的。
2. POS设备的无线网卡连接到FS设备的AP热点。POS设备通过FS开发包提供的接口可以获取到FS设备信息,包含IP、MAC等,相关代码如下:
IPCameraManager.getInstance(context).registerListener(new IPCameraListener() {
//IPCameraInfo获取的即是FS的设备信息,包含IP、MAC等。
@Override
public void onDeviceOnline(IPCameraInfo device) {
showToast(getApplicationContext(), "[ " + device.getDeviceid() + " ]上线");
}
@Override
public void onDeviceOffline(IPCameraInfo device) {
showToast(getApplicationContext(), "[ " + device.getDeviceid() + " ]离线");
}
});
3. 调用getApListWithoutAuth 接口可以在POS设备上获取到FS设备扫描到的wifi热点:
// 获取FS设备扫描到的AP热点
private void getWifiList() {
BasicConfig.getInstance(context).getApListWithoutAuth(sunmiDevice.getDeviceid(),
new RPCCallback‹RPCResponse‹IpcApBean››() {
//扫描完成后调用onComplete,返回信息
@Override
public void onComplete(RPCResponse‹IpcApBean› result) {
if (result.code() == RPCErrorCode.SUCCESS) {
wifiListGetSuccess(result.data());
} else {
Log.i(TAG, "getApListWithoutAuth failed, errcode: " + result.code());
}
}
});
...
}
void wifiListGetSuccess(IpcApBean res) {
...
wifiList.clear();
//处理FS设备扫描到的AP热点信息
wifiList.addAll(res.ap_list);
initApList(wifiList);
}
4. 选中一个wifi热点后,调用setWifiConfWithoutAuth接口配置FS设备,使其能够连接到wifi热点,相关代码如下:
/*
* 输入wifi热点名,密码
*
*/
private void setIpcWifi(String ssid, String psw) {
BasicConfig.getInstance(context).setWifiConfWithoutAuth(sunmiDevice.getDeviceid(),ssid, psw, new RPCCallback‹RPCResponse›() {
//调用成功后会调用onCompelte, 返回值保存再RPCResponse
@Override
public void onComplete(RPCResponse result) {
if (result.code() == RPCErrorCode.SUCCESS) {
hideLoadingDialog();
shortTip("配置成功,请等待设备联网,联网后指示灯会变成蓝色");
createWaitDialog();
} else {
hideLoadingDialog();
shortTip("配置失败");
}
}
@Override
public void onError(Throwable t) {
hideLoadingDialog();
shortTip("配置失败");
}
});
}
5. 等待片刻后,AI识客设备通过无线连接上互联网,显示蓝灯。
5.1.3 FS设备激活
FS设备首次使用时,需要激活。如果FS设备没有激活,则会无法调用FS SDK的其他接口。激活设备需要连接互联网。如何连接互联网,可以参看 5.2 FS设备配网 。POS设备调用active接口即可以激活FS设备,激活代码如下:
//激活FS设备,并设置回调接口
DeviceManage.getInstance(context).activate(ipcList.get(postion).getDeviceid(),
new RPCCallback‹RPCResponse›() {
//FS返回相关错误码。
@Override
public void onComplete(RPCResponse result) {
if (result.code() == RPCErrorCode.SUCCESS || result.code() == RPCErrorCode.DEVICE_ACTIVATED) {
Log.i(TAG, "activate ipc success");
} else {
Log.i(TAG, "activate ipc failed");
}
}
//网络问题导致无法通信,会调用onError接口
@Override
public void onError(Throwable t) {
Log.i(TAG, "activate ipc failed");
}
});
5.1.4 FS设备画面调整
FS设备进行人脸识别时,对人脸图像质量有一定要求,因此在使用FS提醒功能之前,需要调整FS设备画面。FS设备支持RTSP协议用于画面预览。可以使用Demo APP提供的RTSP播放器播放预览画面,也可以自定义一款RTSP播放器。预览AI识客设备的画面时,可以对FS的摄像镜头进行调焦、对焦,调整画面的清晰度,以满足FS设备的人脸识别要求。主要步骤如下:
5.1.4.1 预览画面播放
调用接口 getLiveStream 获取RTSP预览视频流播放地址,然后使用RTSP播放器进行播放。代码如下:
private void openMediaPlayer() {
new Thread(new Runnable() {
@Override
public void run() {
//获取播放流 VideoStream.getInstance(context).getLiveStream(mDevice.getDeviceid(),
new RPCCallback‹RPCResponse‹RPCResponse.LiveAddressBean››() {
@Override
public void onComplete(RPCResponse‹RPCResponse.LiveAddressBean› result) {
if (result.code() == RPCErrorCode.SUCCESS) {
Log.i(TAG, "live url: " + result.data().fhd_live_url);
if (mPlayer == null) {
//Sunmi rtsp播放器
mPlayer = new SunmiPlayer(context);
mPlayer.setListener(new SunmiPlayerListener() {
@Override
public void onPrepared(IMediaPlayer iMediaPlayer) {
iMediaPlayer.start();
}
});
mPlayer.setSurface(mVideoView.getHolder().getSurface());
//获取到AI识客设备返回的播放流rtsp地址
String liveUrl = result.data().fhd_live_url.replaceFirst("^rtsp://", "rtsp://admin:admin@");
//Sunmi RTSP播放器开始播放rtsp视频流
mPlayer.setUp(liveUrl);
}
}
}
});
}
}).start();
}
5.1.4.2 FS设备调焦、对焦
画面预览时,如果画面不清晰,请调用接口 setZoom,autoFocus,manualFocus分别进行调整焦距、自动对焦、手动对焦。当画面清晰时,停止对焦。参考代码如下:
public void init() {
...
mBasicConfig = BasicConfig.getInstance(context);
...
}
// 调焦
private void func1(){
...
mBasicConfig.setZoom(mDevice.getDeviceid(), zfBean.zoom, new RPCCallback‹RPCResponse›() {
@Override
public void onComplete(RPCResponse result) {
Log.i(TAG, "setZoom, code:" + result.code());
}
});
...
}
// 自动对焦
private void func2() {
...
mBasicConfig.autoFocus(mDevice.getDeviceid(), xRelative, yRelative, new RPCCallback‹RPCResponse›() {
@Override
public void onComplete(RPCResponse result) {
Log.d(TAG, "autoFocus, code:" + result.code());
if (result.code() == RPCErrorCode.SUCCESS) {
mBasicConfig.getZoomFocusConf(mDevice.getDeviceid(), new RPCCallback‹RPCResponse‹RPCResponse.ZoomFocusBean››() {
@Override
public void onComplete(RPCResponse‹RPCResponse.ZoomFocusBean› result) {
if (result.code() == RPCErrorCode.SUCCESS) {
zfBean = result.data();
mSbZoom.setProgress(zfBean.zoom);
}
}
});
}
}
});
...
}
// 自动对焦如果不够清晰,可以手动对焦进行微调
private void func3() {
...
mBasicConfig.manualFocus(mDevice.getDeviceid(), focus, new RPCCallback‹RPCResponse›() {
@Override
public void onComplete(RPCResponse result) {
if (result.code() == RPCErrorCode.SUCCESS) {
zfBean.focus = focus;
}
}
});
....
}
5.1.5 FS设备客门线设置
首次FS设备时,需要设置门线位置。设置该门线位置是用于判定人脸进店。FS设备被换位置或者门线设置不正确时,也需要进行重新设置门线。调用接口setDoorLine
可以设置门线。参考代码如下:
private void func() {
...
PeopleFlowStats.getInstance(context).setDoorLine(mDevice.getDeviceid(), 0, lineStart[0],
lineStart[1], lineEnd[0], lineEnd[1], new RPCCallback‹RPCResponse›() {
@Override
public void onComplete(RPCResponse result) {
if (result.code() == RPCErrorCode.SUCCESS) {
stopPlay();
finish();
startActivity(new Intent(context, MainActivity.class));
}
}
});
...
}
完成以上步骤后,就配置好AI识客设备,可以使用AI识客设备提供的识客进店功能。
5.2 会员注册
输入会员的ID、分组、备注信息,并采集会员人脸,提取人脸特征,完成会员注册。POS设备完成会员注册的同时,会把人脸照片以及会员ID同步传递给AI识客设备。
5.2.1 采集人脸照片
POS设备调用自带摄像头或者外置USB摄像头进行人脸拍照。获取人脸照片。相关代码如下:
{
//根据摄像头是USB还是系统摄像头,调用不同的方法,获取bitmap数据
if (FaceCameraManager.getInstance().getCurCamera() == FaceCameraManager.CAMERA_USB)
bitmap = mUVCCameraView.captureStillImage();
else
bitmap = mTextureView.getBitmap();
}
5.2.2 注册会员信息和人脸信息
POS设备使用SDK提供的人脸识别功能,对人脸照片提取特征值,并注册会员。相关参考代码如下:
/*
* @bitmap 含有人脸bitmap
* @maxFace 返回最大人脸数
* @return 返回人脸特征值
*/
public ArrayList‹SunmiFaceFeature› getFeatures(Bitmap bitmap, int maxFace) {
int ret = 0;
//bitmap RGB图像转化为BRG
byte[] srcData = ImageUtils.getPixelsBGR(bitmap);
SunmiFaceImage image = new SunmiFaceImage(srcData, bitmap.getHeight(), bitmap.getWidth(), maxFace);
SunmiFaceImageFeatures features = new SunmiFaceImageFeatures();
ret = SunmiFaceSDK.getImageFeatures(image, features);
SunmiFaceFeature feature_ary = features.getFeatures();
ArrayList‹SunmiFaceFeature› arrayList = new ArrayList‹›();
if (features.getFeaturesCount() == 0) {
SunmiFaceSDK.releaseImageFeatures(features);
return arrayList;
}
for (int i = 0; i ‹ features.getFeaturesCount(); i++) {
SunmiFaceFeature sunmiFaceFeature = SunmiFaceLib.SunmiFaceFeatureArrayGetItem(feature_ary, i);
arrayList.add(sunmiFaceFeature);
}
SunmiFaceSDK.releaseImageFeatures(features);
return arrayList;
// return getFeature(srcData, bitmap.getWidth(),bitmap.getHeight(), 1);
}
/*
*向系统注册会员信息
*@groupname, 会员组
*@userNanem, 会员名
*@picPath, 会员照片存放路劲
*@userInfo, 会员详情
*@faceFeature, 会员照片提取的特征值
*/
public boolean registerUserIntoDBmanager(String groupName, String userName, String picPath,String userInfo, SunmiFaceFeature faceFeature) {
boolean isSuccess = false;
Group group = new Group();
group.setGroupId(groupName);
User user = new User();
user.setGroupId(groupName);
//final String uid = UUID.randomUUID().toString();
String uid = String.valueOf(System.currentTimeMillis());
user.setUserId(uid);
user.setUserName(userName);
user.setFeature(faceFeature.getFeature());
SunmiFaceDBRecord record = SunmiFaceSDK.faceFeature2FaceDBRecord(faceFeature);
record.setId(user.getUserId());
record.setName(user.getUserName());
//把人脸特征值添加到人脸特征库
int ret = SunmiFaceSDK.addDBRecord(record);
if (ret != 0) {
Log.d(TAG, "addDBRecord failed " + SunmiFaceSDK.getErrorString(ret));
return false;
}
user.setImageName(record.getImgId());
if (userInfo != null) {
user.setUserInfo(userInfo);
}
// 添加用户信息到数据库
boolean importUserSuccess = FaceManager.getInstance().userAdd(user);
if (importUserSuccess) {
// 如果添加到数据库成功,则添加用户组信息到数据库
// 如果当前图片组名和上一张图片组名相同,则不添加数据库到组表
if (FaceManager.getInstance().groupAdd(group)) {
isSuccess = true;
if (mIPCManager != null) {
Log.i(TAG, "picPath: " + picPath);
Log.i(TAG, "uid: " + uid);
// 添加用户的同时,把人脸照片、id同步到AI识客设备
mIPCManager.addFaceRecord(picPath, uid, new RPCCallback‹RPCResponse›() {
@Override
public void onComplete(RPCResponse result) {
}
@Override
public void onError(Throwable t) {
super.onError(t);
}
});
}
} else {
isSuccess = false;
}
} else {
isSuccess = false;
}
return isSuccess;
}
5.3 会员管理
包括会员列表、会员注册 、会员删除、会员查看。
会员注册:见 5.2.2 注册会员信息和人脸信息
会员删除:删除会员的时候,需要把删除信息同步到FS设备。相关参考代码如下:
/**
* 删除用户
*/
public boolean userDelete(String userId, String groupId) {
if (TextUtils.isEmpty(userId) || TextUtils.isEmpty(groupId)) {
return false;
}
User user = DBManager.getInstance().queryUser(groupId, userId);
if (user == null) {
Log.d(TAG, "Database has no user " + userId);
return false;
}
Log.d(TAG, "userDelete userId" + user.getUserId() + " userImage: " + user.getImageName());
//删除会员信息
boolean ret = DBManager.getInstance().deleteUser(userId, groupId);
DBManager.getInstance().deleteUserEventByUserId(userId);
//从人脸库中删除人脸特征值
int result = SunmiFaceSDK.deleteDBRecord(user.getImageName());
if (mIPCManager != null) {
//删除会员时,同步删除AI识客设备上的人脸数据信息
mIPCManager.deleteFaceRecord(userId,new RPCCallback‹RPCResponse‹RPCResponse.FaceDeleteSubResult››() {
@Override
public void onComplete(RPCResponse‹RPCResponse.FaceDeleteSubResult› result) {
Log.i(TAG, "deleteFaceRecord, code:" + result.code());
if (result.code() != 0){
ToastUtils.showToast(context, "删除人脸失败 code: " + result.code());
} else {
ToastUtils.showToast(context, "删除人脸成功");
}
}
@Override
public void onError(Throwable t) {
super.onError(t);
Log.i(TAG, "addFaceRecord, Exception:" + t.getMessage());
}
});
}
return ret;
}
会员查看:主要显示会员ID、组、会员描述信息以及会员注册头像。
5.4 会员实时查询
主要功能实现了实时的获取POS设备自带摄像头 或者外置USB摄像头 的预览数据,并且对获取的图像数据做实时人脸特征提取,并查询根据人脸特征信息查询会员信息。主要使用到的功能有:实时获取摄像头预览数据 ,人脸特征提取 ,人脸识别 等功能
5.4.1 实时获取摄像头数据
POS设备实时获取摄像头数据相关代码如下:
//开启摄像头预览
FaceCameraManager.getInstance().startPreview(getApplicationContext(), this, FaceCameraManager.getInstance().getCurCamera(), cameraView, PREVIEW_WIDTH, PREVIEW_HEIGHT, cameraDataCallback);
//摄像头数据回调接口
CameraDataCallback cameraDataCallback = new CameraDataCallback() {
@Override
public void onImageDataArrival(Bitmap bitmap, int width, int height) {
if (mBackgroundHandler != null) {
if (mClickAction == 1 && !faceDetectState.get()) {
//在一个独立线程中对获取到的图像数据进行人脸特征提取、识别
mBackgroundHandler.post(new MotionDetector(bitmap, width, height));
} else {
bitmap.recycle();
}
}
}
};
5.4.2 特征提取功能
使用开发包提供的人脸特征提取功能,相关参考代码如下:
/*
* @bitmap 含有人脸bitmap
* @maxFace 返回最大人脸数
* @return 返回人脸特征值
*/
public ArrayList‹SunmiFaceFeature› getFeatures(Bitmap bitmap, int maxFace) {
int ret = 0;
//bitmap的RGB数据转化成BGR数据
byte[] srcData = ImageUtils.getPixelsBGR(bitmap);
//通过BGR数据构造SunmifaceImage对象
SunmiFaceImage image = new SunmiFaceImage(srcData, bitmap.getHeight(), bitmap.getWidth(), maxFace);
SunmiFaceImageFeatures features = new SunmiFaceImageFeatures();
//从SunmifaceImage数据中提取人脸特征
ret = SunmiFaceSDK.getImageFeatures(image, features);
//返回人脸特征数组
SunmiFaceFeature feature_ary = features.getFeatures_();
ArrayList‹SunmiFaceFeature› arrayList = new ArrayList‹›();
if (features.getFeatures_count_() == 0) {
SunmiFaceSDK.releaseImageFeatures(features);
return arrayList;
}
for (int i = 0; i ‹ features.getFeatures_count_(); i++) {
SunmiFaceFeature sunmiFaceFeature = SunmiFaceLib.SunmiFaceFeatureArray_getitem(feature_ary, i);
arrayList.add(sunmiFaceFeature);
}
SunmiFaceSDK.releaseImageFeatures(features);
return arrayList;
// return getFeature(srcData, bitmap.getWidth(),bitmap.getHeight(), 1);
}
5.4.3 人脸识别
提取人脸特征后,查询人脸特征数据库,返回用户信息,相关代码如下:
public User getUserByFeature(SunmiFaceFeature feature) {
SunmiFaceDBRecord record = SunmiFaceSDK.faceFeature2FaceDBRecord(feature);
SunmiFaceDBIdInfo info = new SunmiFaceDBIdInfo();
//在人脸特征数据查询对应的特征值
int ret = SunmiFaceSDK.searchDB(record, info);
if (!info.getIsMatched()) {
return null;
} else {
//查询到匹配的特征值后,查询用户信息,并返回用户信息。
return DBManager.getInstance().queryUser("default", info.getId());
}
}
6 SDK详细接口说明
本SDK开发包包含人脸识别和FS设备SDK。请分别详细查阅以下链接了解API接口详细内容。
人 脸识别API 和 FS设备API