项目目录结构
随着人工智能和大数据分析技术越来越广泛,众多的生活场景都存在着这些技术的身影,比如像现在比较流行的人脸识别技术,其底层的算法实现的支撑,为众多的业务场景铺垫了基础,像支付宝的刷脸支付,本文是百度的人脸识别的demo。
1、用户注册,即首次刷脸之前需通过应用层向人脸数据库提交个人原始照片;
2、人脸数据库经过计算分析保存人脸数据的元数据信息;
3、注册成功后,假如业务需要用户刷脸,应用只需要调用刷脸识别接口或者自己实现一套刷脸识别算法,对比当前用户扫脸的数据,如果是调用第三方的API,只需调用响应接口进行比对,通过,即可进行后续操作;
其实最有难度的还是底层的关于人脸识别的算法,那些技术算法我们暂时无从得知,但是大致的原理还是可以理解的,通过提取人的面部特征信息,作为元数据进行保存,下一次进行对比的人脸照片,同样的算法解析后直接和元信息进行对比,根据算法分析的相关度得分进行后面的业务操作;
下面来说说百度人脸识别的开源API实现,百度在AI领域也算起步比较早的,和科大讯飞类似很早就开始在人工智能方面进行研究,我们可以借鉴百度的人脸识别API结合到我们自己的业务中做相关的应用,前提是需要对其实现有一定的了解,
1、首先,你需要登录到 https://ai.baidu.com 百度AI主页去注册一个百度账号,如果你有了百度云账号,可以直接进入到控制台里面去,创建一个应用,创建成功后,会分配给你一个应用信息,包含
AppID ,API Key,Secret Key,这些是你调用人脸识别API的凭证,妥善保管,
2、打开API 文档,需要我们了解每个接口的大致作用,要注意的是你的应用归属的版本,人脸识别的API接口文档有多个版本,我这里使用的是V3版本,每个版本的具体使用可能会有点差异,
首先使用所有人脸相关接口前,都是必须要先注册,注册后才能根据每个人的照片去识别。且在使用所有接口前都是需要access_token,这个是通过APPID、APIKEY、SECRETKEY获取。根据官方文档这个access_token有效期是一个月,提供的SDK中已经在调用所有接口前,只要初始化这个ApiFace类即可。如果想要阅读课查看官方文档或者SDK中的BaseClientl类查看源码。我这里将源码贴出。
protected synchronized void getAccessToken(AipClientConfiguration config) {
if (!this.needAuth()) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(String.format("app[%s] no need to auth", this.appId));
}
} else {
JSONObject res = DevAuth.oauth(this.aipKey, this.aipToken, config);
if (res == null) {
LOGGER.warn("oauth get null response");
} else {
if (!res.isNull("access_token")) {
this.state.transfer(true);
this.accessToken = res.getString("access_token");
LOGGER.info("get access_token success. current state: " + this.state.toString());
Integer expireSec = res.getInt("expires_in");
Calendar c = Calendar.getInstance();
c.add(13, expireSec);
this.expireDate = c;
String[] scope = res.getString("scope").split(" ");
boolean hasRight = false;
String[] arr$ = scope;
int len$ = scope.length;
for(int i$ = 0; i$ < len$; ++i$) {
String str = arr$[i$];
if (AipClientConst.AI_ACCESS_RIGHT.contains(str)) {
hasRight = true;
break;
}
}
this.state.transfer(hasRight);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("current state after check priviledge: " + this.state.toString());
}
} else if (!res.isNull("error_code")) {
this.state.transfer(false);
LOGGER.warn("oauth get error, current state: " + this.state.toString());
}
}
}
}
注册人脸代码
ScanUserServiceImpl实现层类
/**
* 人脸注册
* @param file 文件
* @return String
* @author lst
* @since 2019-12-18
*/
@Override
@Transactional
public String resisterFace(MultipartFile file) {
//先将文件上传到服务器路径
String fileName = file.getOriginalFilename();
String suffix = fileName.substring(fileName.lastIndexOf(".") + 1);
String saveFileName = FileUtil.getFileName(suffix);
try {
//上传文件到本地服务器
if (!FileUtil.saveFile(userFilesPath + File.separator, saveFileName, file.getInputStream())) {
logger.info("文件上传失败");
return "注册失败,内部错误请联系管理员";
}
//实际保存到服务器上的图片路径
String filePath = userFilesPath + saveFileName;
ScanUser insertUser = new ScanUser();
String userId = IdGenerate.generateId();
//调用百度的人脸识别的注册接口
JSONObject jsonObject = new ScanUtils().doRegister(filePath, userId, GROUP_ID);
//注册成功的图片保存在百度人脸库中的唯一标识
String faceToken = jsonObject.getJSONObject("result").getString("face_token");
//如果之前用户已经注册过,则需做更新操作
QueryWrapper queryWrapper = new QueryWrapper<>();
queryWrapper.eq("face_token", faceToken);
ScanUser dbUser = scanUserMapper.selectOne(queryWrapper);
if (dbUser != null) {
dbUser.setImageUrl(filePath);
dbUser.setFaceToken(faceToken);
dbUser.setUpdateDate(new Date());
scanUserMapper.updateById(dbUser);
return userId;
}
//没有注册过,则重新注册
insertUser.setFaceToken(faceToken);
insertUser.setId(userId);
insertUser.setGroupId(GROUP_ID);
insertUser.setImageUrl(filePath);
insertUser.setUserInfo("用户扫脸注册的信息");
insertUser.setCreateBy(userId);
insertUser.setUpdateBy(userId);
insertUser.setCreateDate(new Date());
insertUser.setUpdateDate(new Date());
insertUser.setDelFlag("0");
scanUserMapper.insert(insertUser);
return userId;
} catch (Exception e) {
logger.error("文件上传失败");
return "注册失败";
}
}
ScanUtils工具类
/**
* 人脸注册
* @param imageUrl
* @param userId 用户id
* @param groupId 用户分组
* @return
*/
public JSONObject doRegister(String imageUrl, String userId, String groupId) {
// 传入可选参数调用接口
HashMap options = new HashMap();
options.put("user_info", "user1");
options.put("quality_control", "NORMAL");
options.put("liveness_control", "LOW");
options.put("action_type", "REPLACE");
//image 取决于image_type参数,传入BASE64字符串或URL字符串或FACE_TOKEN字符串
String image = FileUtil.getImageBase64(imageUrl);
String imageType = "BASE64";
// 人脸注册
JSONObject res = client.addUser(image, imageType, groupId, userId, options);
logger.info("注册接口返回的信息:{}",res);
return res;
}
人脸注册有一个很重要的字段,就是face_token,这个相当于是这张人脸照片的唯一标识,如果继续注册相同的照片会提示已经存在,这个face_token后续可以作为业务字段存放在我们本地的业务数据库中进行后续的使用, 其他的参数大家可结合API的使用文档进行详细参考。
ScanUserServiceImpl实现层类
/**
* 人脸对比
* @param file 文件
* @param userId 用户ID
* @return String
* @author lst
* @since 2019-12-18
*/
@Override
public String compareFace(MultipartFile file, String userId) {
String newImagePath = getFilePath(file);
ScanUser dbUser = scanUserMapper.selectById(userId);
String oldImagePath = dbUser.getImageUrl();
JSONObject object = new ScanUtils().compareFace(newImagePath, oldImagePath);
//获取对比的分数
Double compareScore = object.getJSONObject("result").getDouble("score");
//对比过后将删除临时文件夹的图片
deleteTempFile(userFilesPathTemp);
if (compareScore > 95) {
return "success";
}
return "fail";
}
ScanUtils工具类
/**
* 人脸对比
* @param image1 拍照的图片
* @param image2 底图
* @return JSONObject
* @author lst
* @since 2019-12-18
*/
public JSONObject compareFace(String image1, String image2) {
String image1Base1 = FileUtil.getImageBase64(image1);
String image1Base2 = FileUtil.getImageBase64(image2);
// image1/image2也可以为url或facetoken, 相应的imageType参数需要与之对应。
MatchRequest req1 = new MatchRequest(image1Base1, "BASE64");
MatchRequest req2 = new MatchRequest(image1Base2, "BASE64");
ArrayList requests = new ArrayList();
requests.add(req1);
requests.add(req2);
JSONObject res = client.match(requests);
logger.info("人脸对比返回的信息:{}",res);
return res;
}
人脸对比返回的res数据中有一个score字段,这个值越大说明比对的越精确。
以上就是百度的注册和人脸识别接口的demo,其他接口可在此源码上进行添加测试。
需要源码的伙伴可前往自行下载,附上下载地址: https://download.csdn.net/download/qq_33612228/12038889