前言
我之前发的那一篇我发现了一些代码中的问题也进行修改和优化,我这里就只展示优化和修改的部分,需要的工具类请看此文章Springboot整合百度人脸识别功能实现注册和登录_人脸识别登录功能-CSDN博客
问题和优化
问题
上面的这篇文章中我的代码中用到了OSS文件存储服务器来保存注册的人脸识别照片方便登录时进行比对,但是后面我在阅读官方的API文档的时候发现其实我们并不需要保存注册时的人脸照片,我们只需要获取到注册人脸照片时返回值中的人脸照片唯一标识即可。
优化
如上是进行注册人脸识别成功之后的返回值,在上面的返回值中我们只需要获取到一个名为face_token的值即可,这个值即人脸照片的唯一标识,我们只需要将其存入数据库中对应用户的信息里即可,在每次进行比对时传入根据登录的账号进行查询获取到这个唯一标识然后传递给百度AI比对即可,代码如下。
package com.baidu.controller;
import com.baidu.aip.face.AipFace;
import com.baidu.aip.face.MatchRequest;
import com.baidu.compents.CodeCompents;
import com.baidu.config.BaiduAiConfig;
import com.baidu.pojo.UserBaiduai;
import com.baidu.service.UserBaiduAIService;
import com.baidu.util.Base64Util;
import com.baidu.util.OssUtil;
import org.apache.commons.lang3.ObjectUtils;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
@RestController
@RequestMapping("/baiduAI")
public class UserBaiduAIController {
@Autowired
private UserBaiduAIService userBaiduAIService;
/*
以下代码有两个方案
方案一:人脸注册照片存储在OSS,数据库中存储照片的URL,比对是将URL传递给百度API
方案二:人脸照片不需要自己存储,获取注册人脸的唯一标识face_token存入数据库,比对时将face_token传递给百度API
总结:
方案一需要多一个OSS文件存储服务器且数据库中存储的是URL每次比对的时候都需要百度API去获取图片
方案二不需要OSS文件存储服务器数据库中存储注册图片的唯一标识每次比对的时候直接传递唯一标识即可
推荐使用方案二!
*/
/**
* 账号+人脸校验
* @param userName
* @param file
* @throws Exception
*/
@PostMapping("/loginBaiduAi")
public void loginBaiduAi(String userName, MultipartFile file) throws Exception {
// 传入appId、apiKey、secretkey。创建Java代码和百度云交互的Client对象
AipFace client = new AipFace(BaiduAiConfig.AppId, BaiduAiConfig.AK, BaiduAiConfig.SK);
// 登录图片
// MultipartFile类型转换Base64字符串格式
String loginImageBase64 = Base64Util.multipartFileToBase64(file);
// 根据用户名获取用户信息
UserBaiduai one = userBaiduAIService.findByName(userName);
if (!ObjectUtils.isEmpty(one)){
/*
判断该用户是否注册了人脸
如果没有注册则不进行校验
如果注册了则进行校验
*/
if (!ObjectUtils.isEmpty(one.getPhoto())){
// 用户注册的人脸的照片存储路径--方案一
// String comparedImageUrl = one.getPhoto();
// 用户注册的人脸的照片唯一标识--方案二
String comparedFaceToken = one.getPhoto();
/*
传入参数进行校验
返回值为两张照片的相似度
*/
//方案一
// Double faceComparison = faceComparison(client, loginImageBase64, comparedImageUrl);
//方案二
Double faceComparison = faceComparison(client, loginImageBase64, comparedFaceToken);
if (faceComparison > 85) {
System.out.println(one.getUsername());
System.out.println("人脸识别登录成功");
} else {
System.out.println("人脸识别登录失败");
}
}else {
System.out.println("请先录入人脸信息");
}
}else {
System.out.println("账号或人脸信息不正确");
}
}
/**
* 账号+人脸 进行绑定
* @param userName
* @param file
* @throws IOException
* @throws JSONException
*/
@PostMapping("registerBaiduAi")
public void registerBaiduAi(String userName,MultipartFile file) throws IOException, JSONException {
// 传入appId、apiKey、secretkey 创建Java代码和百度云交互的Client对象
AipFace client = new AipFace(BaiduAiConfig.AppId, BaiduAiConfig.AK, BaiduAiConfig.SK);
// 根据用户名获取用户信息
// redis项目可以删除userName参数,直接从redis或者token中获取用户名
UserBaiduai one = userBaiduAIService.findByName(userName);
// 判断用户是否注册过人脸识别--方案一
// if(!ObjectUtils.isEmpty(one.getPhoto())){
// // 如果有则先删除原来注册的人脸照片
// // 假设图片URL是https://canghai0190.oss-cn-beijing.aliyuncs.com/img/1714270552688.png
// // 那么我们要截取com/后面的文件路径名称传入方法进行删除
// int index = one.getPhoto().indexOf("com/");
// String fileName = null;
// if (index != -1) {
// fileName = one.getPhoto().substring(index + 4); // 截取 "com/" 后面的内容
// } else {
// fileName = "";
// }
// System.out.println(fileName);
// OssUtil.deleteFileToOss(fileName);
// }
// MultipartFile类型转换Base64字符串格式
String registerImageBase64 = Base64Util.multipartFileToBase64(file);
// 传入可选参数调用接口
HashMap<String, String> options = new HashMap<String, String>();
options.put("user_info", "user's info");
options.put("quality_control", "NORMAL");
options.put("liveness_control", "LOW");
options.put("action_type", "REPLACE");
/*
调用api方法完成人脸注册
image 图片的url或者base64字符串
imageType 图片形式(URL,BASE64)
groupId 组Id(固定一个字符串)
userId 用户Id
options hashMap基本参数配置
*/
JSONObject res = client.addUser(registerImageBase64, CodeCompents.baidu_ai_imageType, CodeCompents.baidu_ai_groupId, userName, options);
if (res.getInt("error_code")==0){
//上传人脸识别图片到oss--方案一
// String url = OssUtil.uploadFileToOss(file);
//将人脸识别信息和用户信息绑定存入数据库--方案一
// one.setPhoto(url);
//获取注册的人脸的唯一标识--方案二
String faceToken = res.getJSONObject("result").getString("face_token");
//将人脸信息的唯一标识存入该用户的数据库--方案二
one.setPhoto(faceToken);
//更新数据库
userBaiduAIService.update(one);
//更新redis中的用户信息
// updateUser(hmsUser);
System.out.println("人脸注册成功");
}else {
System.out.println("人脸注册失败");
}
System.out.println(res.toString(2));
}
static Double faceComparison(AipFace client, String loginImageBase64, String comparedFaceToken) throws Exception {
// 将图片的URL传递给百度API--方案一
// MatchRequest req2 = new MatchRequest(comparedImageUrl, "URL");
//将注册时人脸的唯一标识传递给百度API--方案二
MatchRequest req2 = new MatchRequest(comparedFaceToken, "FACE_TOKEN");
// 将前端传过来的图片传递给百度API
MatchRequest req1 = new MatchRequest(loginImageBase64, CodeCompents.baidu_ai_imageType);
// 讲MatchRequest信息存入list集合中
ArrayList<MatchRequest> requests = new ArrayList<>();
requests.add(req1);
requests.add(req2);
// 进行人脸比对 返回值是json串
JSONObject match = client.match(requests);
System.out.println(match.toString(2));
// 返回两张照片的相似度
return match.getJSONObject("result").getDouble("score");
}
}
后言
我还想制作一个关于百度人脸搜索的教程,但是由于最近在找工作而且人脸搜索的代码还没有完全摸索清楚所以更新的可能比较慢,不过百度AI官方API中的代码你复制过来就可以直接运行着急的话可以直接去看官方的API。
这个人脸搜索的意义是在你进行登录的时候不在需要去查数据库获取唯一值或者照片链接也不需要登录账号这个操作,只需要传入登录时的照片上传到百度之后,便会在你指定的组中寻找匹配度最高的人脸进行比对然后进行返回,返回之后进行判断相似分数是否足够高即可,足够高则为登录成功,低则登录识别。我们还可以在注册人脸时将用户的信息存入的人脸照片的返回值中,这样我们在比对成功之后即可直接获取到用户信息为用户做登录处理,这样就不用去查询数据库了。