3.8 人脸识别登陆Controller
1、效果图
后台获取的数据
{"face_token":"efb5996c1707850f81e884ef190c984b","user_list":[{"score":91.080505371094,"group_id":"group1","user_id":"1","user_info":""}]}
2、注册百度ai
百度ai地址https://login.bce.baidu.com/?redirect=https%3A%2F%2Fconsole.bce.baidu.com%2F%3Ffromai%3D1#/aip/overviewhttps://login.bce.baidu.com/?redirect=https%3A%2F%2Fconsole.bce.baidu.com%2F%3Ffromai%3D1#/aip/overview
2.1 、使用免费百度ai步骤
1、点击人脸识别:跳转到服务
2、其间会有一些验证,创建应用
3、查看人脸库
4、新建组、用户
5、添加人脸照片
3、代码实现逻辑
基于Springboot框架搭建的,前端使用Vue,通过摄像机拍下照片后,请求后端人脸识别登陆服务,后台调用百度API人脸识别接口,进入百度
大脑搜索人脸识别即可获取官网的Secret Key,将前端获取的人脸信息的base64信息和你本地数据库里的人脸信息传到百度人脸识别的接口
进行人脸比对,返回一个json数据,result参数 带别人脸相似度, result可自己定义,从而实现人脸识别登录。
核心代码块
3.1、导入Maven依赖
com.baidu.aip
java-sdk
4.15.1
3.2、 创建FaceUtil,获取ApiFace【单例】
package com.ruoyi.common.utils.face.utils;
import com.baidu.aip.face.AipFace;
import com.baidu.aip.util.base64Util;
public class FaceUtil {
private static final String APP_ID = "25236971";
private static final String APP_KEY = "zLIZGY15wiEQh2utjwAGGW9C";
private static final String SECRET_KEY = "Pzi4Ew6eWfZPINBkshlCO22OqADa777I";
private static volatile AipFace client = new AipFace(APP_ID, APP_KEY, SECRET_KEY);
// 创建单例避免多次获取sdk
public static AipFace getClient(){
client.setConnectionTimeoutInMillis(2000);
client.setSocketTimeoutInMillis(60000);
return client;
}
public static String encodebase64(byte[] form){
return base64Util.encode(form);
}
public static byte[] decodebase64(String data){
return base64Util.decode(data);
}
}
3.3 创建FaceResultUtil,统一处理请求
package com.ruoyi.common.utils.face.utils;
import com.ruoyi.common.utils.face.BizException;
import com.ruoyi.common.utils.face.constant.ErrorEnum;
import com.ruoyi.common.utils.face.constant.FaceConstant;
import com.ruoyi.common.utils.face.dto.FaceResult;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class FaceResultUtil {
private static final Logger logger = LoggerFactory.getLogger("百度API接口请求结果解析");
public static FaceResult isSuccess(JSonObject res){
FaceResult result = parseJsonObject(res);
if (!result.isSuccess()){
// 对错误进行分类
ErrorEnum errorEnum = ErrorEnum.getInstance(result.getErrorCode());
if (errorEnum == null){
throw new BizException("百度接口请求失败" + result.getErrorMsg());
}else {
throw new BizException(errorEnum.getCnDesc());
}
}
return result;
}
private static FaceResult parseJsonObject(JSonObject res){
FaceResult faceResult = FaceResult.builder().build();
try {
String logId = res.has(FaceConstant.LOG_ID) ? res.get(FaceConstant.LOG_ID).toString() : "0";
int errorCode = res.has(FaceConstant.ERROR_CODE) ? res.getInt(FaceConstant.ERROR_CODE) : -1;
String errorMsg = res.has(FaceConstant.ERROR_MSG) ? res.getString(FaceConstant.ERROR_MSG) : "";
int cached = res.has(FaceConstant.CACHED) ? res.getInt(FaceConstant.CACHED) : 0;
long timestamp = res.has(FaceConstant.TIMESTAMP) ? res.getLong(FaceConstant.TIMESTAMP) : 0;
Object dataString = res.has(FaceConstant.RESULT) ? res.get(FaceConstant.RESULT) : "";
com.alibaba.fastjson.JSonObject data = null;
if (dataString != null) {
data = com.alibaba.fastjson.JSONObject.parseObject(dataString.toString());
}
faceResult.setLogId(logId);
faceResult.setErrorCode(errorCode);
faceResult.setErrorMsg(errorMsg);
faceResult.setCached(cached);
faceResult.setTimestamp(timestamp);
faceResult.setData(data);
}catch (Exception e){
logger.error("JSONObject解析失败", e);
}
return faceResult;
}
}
3.4 创建FaceResult
package com.ruoyi.common.utils.face.dto;
import com.alibaba.fastjson.JSONObject;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class FaceResult implements Serializable {
private String logId;
private String errorMsg;
private int cached;
private int errorCode;
private long timestamp;
private JSonObject data;
public boolean isSuccess(){
return 0 == this.errorCode ? true : false;
}
}
3.5 创建ImageU
package com.ruoyi.common.utils.face.dto;
import com.ruoyi.common.utils.face.constant.ImageTypeEnum;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ImageU implements Serializable {
private ImageTypeEnum imageTypeEnum;
private String data;
}
3.6 创建FaceUserDTO
package com.ruoyi.common.utils.face.dto;
import com.ruoyi.common.utils.face.constant.FaceConstant;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class FaceUserDTO implements Serializable {
private String userId;
private String groupId = FaceConstant.DEFAULT_GROUP_ID;
private String faceToken;
private T user;
}
3.7 创建FaceManage[关键类](重点)
package com.ruoyi.common.utils.face;
import com.alibaba.fastjson.JSON;
import com.baidu.aip.face.FaceVerifyRequest;
import com.baidu.aip.face.MatchRequest;
import com.ruoyi.common.utils.face.constant.ActionTypeEnum;
import com.ruoyi.common.utils.face.constant.FaceConstant;
import com.ruoyi.common.utils.face.constant.LivenessControlEnum;
import com.ruoyi.common.utils.face.constant.QualityControlEnum;
import com.ruoyi.common.utils.face.dto.FaceResult;
import com.ruoyi.common.utils.face.dto.FaceUserDTO;
import com.ruoyi.common.utils.face.dto.ImageU;
import com.ruoyi.common.utils.face.utils.FaceResultUtil;
import com.ruoyi.common.utils.face.utils.FaceUtil;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Objects;
public class FaceManage {
private static final Logger logger = LoggerFactory.getLogger(FaceManage.class);
public static void faceRegister(FaceUserDTO userDTO, ImageU imageU){
// 传入可选参数调用接口
HashMap options = new HashMap();
// 用户资料
options.put("user_info", JSON.toJSonString(userDTO));
// 图片质量
options.put("quality_control", QualityControlEnum.LOW.name());
// 活体检测控制
options.put("liveness_control", LivenessControlEnum.NONE.name());
// 操作方式
options.put("action_type", ActionTypeEnum.REPLACe.name());
String image = imageU.getData();
String imageType = imageU.getImageTypeEnum().name();
String groupId = userDTO.getGroupId();
String userId = userDTO.getUserId();
// 人脸注册
JSonObject res = FaceUtil.getClient().addUser(image, imageType, groupId, userId, options);
FaceResultUtil.isSuccess(res);
logger.info("人脸注册成功");
}
public static void faceUpdate(FaceUserDTO userDTO, ImageU imageU) {
HashMap options = new HashMap();
// 用户资料
options.put("user_info", JSON.toJSonString(userDTO));
// 图片质量
options.put("quality_control", QualityControlEnum.LOW.name());
// 活体检测控制
options.put("liveness_control", LivenessControlEnum.NONE.name());
// 操作方式
options.put("action_type", ActionTypeEnum.REPLACE.name());
String image = imageU.getData();
String imageType = imageU.getImageTypeEnum().name();
String groupId = userDTO.getGroupId();
String userId = userDTO.getUserId();
// 人脸更新
JSonObject res = FaceUtil.getClient().updateUser(image, imageType, groupId, userId, options);
FaceResultUtil.isSuccess(res);
logger.info("人脸更新成功 {}", res.toString(2));
}
public static void faceDelete(String userId, String groupId, String faceToken) {
// 传入可选参数调用接口
HashMap options = new HashMap();
// 人脸删除
JSonObject res = FaceUtil.getClient().faceDelete(userId, groupId, faceToken, options);
FaceResultUtil.isSuccess(res);
logger.info("人脸删除成功 {}", res.toString(2));
}
public static FaceUserDTO findUser(String userId, String groupId) {
HashMap options = new HashMap<>();
// 用户信息查询
JSonObject res = FaceUtil.getClient().getUser(userId, groupId, options);
FaceResult result = FaceResultUtil.isSuccess(res);
return JSON.parseObject(result.getData().toJSonString(), FaceUserDTO.class);
}
public static FaceResult faceGetList(String userId, String groupId){
HashMap options = new HashMap();
// 获取用户人脸列表
JSonObject res = FaceUtil.getClient().faceGetlist(userId, groupId, options);
return FaceResultUtil.isSuccess(res);
}
public static FaceResult listUserByGroupId(String groupId) {
HashMap options = new HashMap();
options.put("start", "0");
options.put("length", "50");
// 获取用户列表
JSonObject res = FaceUtil.getClient().getGroupUsers(groupId, options);
return FaceResultUtil.isSuccess(res);
}
public static void deleteUser(String userId, String groupId) {
HashMap options = new HashMap();
// 删除用户
JSonObject res = FaceUtil.getClient().deleteUser(groupId, userId, options);
FaceResultUtil.isSuccess(res);
logger.info("用户删除成功 {}", res.toString(2));
}
public static void addGroup(String groupId) {
HashMap options = new HashMap();
// 创建用户组
JSonObject res = FaceUtil.getClient().groupAdd(groupId, options);
FaceResultUtil.isSuccess(res);
logger.info("创建用户组 {}", res.toString(2));
}
public static void deleteGroup(String groupId){
HashMap options = new HashMap();
// 删除用户组
JSonObject res = FaceUtil.getClient().groupDelete(groupId, options);
FaceResultUtil.isSuccess(res);
logger.info("删除用户组 {}", res.toString(2));
}
public static FaceResult listGroup() {
HashMap options = new HashMap();
options.put("start", "0");
options.put("length", "50");
// 组列表查询
JSonObject res = FaceUtil.getClient().getGroupList(options);
return FaceResultUtil.isSuccess(res);
}
public static FaceResult personVerify(String idCardNumber, String realName, ImageU imageU){
HashMap options = new HashMap();
options.put("quality_control", QualityControlEnum.LOW.name());
options.put("liveness_control", LivenessControlEnum.NONE.name());
// 身份验证
JSonObject res = FaceUtil.getClient().personVerify(imageU.getData(), imageU.getImageTypeEnum().name(), idCardNumber, realName, options);
return FaceResultUtil.isSuccess(res);
}
public static int faceMatchScore(ImageU imageU1, ImageU imageU2){
MatchRequest req1 = new MatchRequest(imageU1.getData(), imageU1.getImageTypeEnum().name());
MatchRequest req2 = new MatchRequest(imageU2.getData(), imageU2.getImageTypeEnum().name());
ArrayList requests = new ArrayList();
requests.add(req1);
requests.add(req2);
JSonObject res = FaceUtil.getClient().match(requests);
FaceResult result = FaceResultUtil.isSuccess(res);
// 对结果进行特殊处理
Integer score = result.getData().getInteger(FaceConstant.SCORE);
return score == null ? 0 : score;
}
public static boolean isfaceMatch(ImageU imageU1, ImageU imageU2, Integer score){
int defaultScore = FaceConstant.MATCH_SCORE;
if (Objects.nonNull(score)){
defaultScore = score;
}
return faceMatchScore(imageU1, imageU2) > defaultScore ? true : false;
}
public static FaceResult faceDetect(ImageU imageU) {
HashMap options = new HashMap();
options.put("face_field", "age");
options.put("max_face_num", "2");
options.put("face_type", "LIVE");
// 人脸检测
JSonObject res = FaceUtil.getClient().detect(imageU.getData(), imageU.getImageTypeEnum().name(), options);
return FaceResultUtil.isSuccess(res);
}
public static FaceResult faceSearch(String groupIds, ImageU imageU) {
HashMap options = new HashMap();
options.put("max_face_num", "1");
options.put("max_user_num", "1");
options.put("quality_control", QualityControlEnum.LOW.name());
options.put("liveness_control", LivenessControlEnum.NONE.name());
// 人脸搜索
JSonObject res = FaceUtil.getClient().search(imageU.getData(), imageU.getImageTypeEnum().name(), groupIds, options);
return FaceResultUtil.isSuccess(res);
}
public static FaceResult faceverify(ImageU imageU) {
FaceVerifyRequest req = new FaceVerifyRequest(imageU.getData(), imageU.getImageTypeEnum().name());
ArrayList list = new ArrayList();
list.add(req);
JSonObject res = FaceUtil.getClient().faceverify(list);
return FaceResultUtil.isSuccess(res);
}
}
3.8、测试
package com.ruoyi.common.utils.face;
import com.alibaba.fastjson.JSON;
import com.example.common.face.FaceManage;
import com.example.common.face.constant.FaceConstant;
import com.example.common.face.constant.ImageTypeEnum;
import com.example.common.face.dto.FaceResult;
import com.example.common.face.dto.FaceUserDTO;
import com.example.common.face.dto.ImageU;
import com.example.common.face.utils.FaceUtil;
import com.example.common.utils.FilesUtil;
import org.apache.commons.io.IOUtils;
import org.junit.Test;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.HashMap;
public class FaceIdentificationTest {
@Test
public void test00() throws Exception{
FaceUserDTO userDTO = new FaceUserDTO<>();
userDTO.setGroupId("group2");
String filePath = "/Users/cxx/Downloads/entryPhoto/";
File[] files = FilesUtil.listFile(filePath);
int j = 0;
for (File file : files) {
int id = 7000 + j;
j++;
userDTO.setUserId(String.valueOf(id));
InputStream is = new FileInputStream(new File(filePath + file.getName()));
byte[] bytes = IOUtils.toByteArray(is);
String data = FaceUtil.encodebase64(bytes);
ImageU imageU = ImageU.builder().data(data).imageTypeEnum(ImageTypeEnum.base64).build();
userDTO.setUser("用户信息 group1 - " + id);
try {
FaceManage.faceRegister(userDTO, imageU);
}catch (Exception e){
System.out.println("注册失败 msg:" + e.getMessage());
continue;
}
}
}
@Test
public void test01() {
FaceUserDTO userDTO = new FaceUserDTO<>();
userDTO.setGroupId("group1");
userDTO.setUserId("6031");
String image = "https://download.2dfire.com/mis/permanent/img2.jpg";
ImageU imageU = ImageU.builder().data(image).imageTypeEnum(ImageTypeEnum.URL).build();
userDTO.setUser("用户信息1");
FaceManage.faceRegister(userDTO, imageU);
}
@Test
public void test02() {
FaceUserDTO userDTO = new FaceUserDTO();
userDTO.setGroupId("group1");
userDTO.setUserId("6031");
String image = "https://download.2dfire.com/mis/permanent/img2.jpg";
ImageU imageU = ImageU.builder().data(image).imageTypeEnum(ImageTypeEnum.URL).build();
userDTO.setUser("用户信息1");
// 人脸更新
FaceManage.faceUpdate(userDTO, imageU);
}
@Test
public void test03() {
String userId = "6030";
String groupId = "group1";
String faceToken = "5a1a8c17c40ea41264e8830017134972";
FaceManage.faceDelete(userId, groupId, faceToken);
}
@Test
public void test04() {
HashMap options = new HashMap<>();
String userId = "6030";
String groupId = "group1";
// 用户信息查询
FaceUserDTO userDTO = FaceManage.findUser(userId, groupId);
System.out.println("用户信息:" + JSON.toJSonString(userDTO));
}
@Test
public void test05() {
String userId = "6030";
String groupId = "group1";
// 获取用户人脸列表
FaceResult result = FaceManage.faceGetList(userId, groupId);
String data = result.getData().getString(FaceConstant.FACE_LIST);
System.out.println("人脸列表"+data);
}
@Test
public void test06() {
String groupId = "group1";
FaceResult result = FaceManage.listUserByGroupId(groupId);
// 获取用户列表
String userIds = result.getData().getString(FaceConstant.USER_ID_LIST);
System.out.println("userIds" + userIds);
}
@Test
public void test07() {
HashMap options = new HashMap();
String groupId = "group1";
String userId = "6031";
// 删除用户
FaceManage.deleteUser(userId, groupId);
}
@Test
public void test08() {
String groupId = "group2";
FaceManage.addGroup(groupId);
}
@Test
public void test09() {
String groupId = "group2";
FaceManage.deleteGroup(groupId);
}
@Test
public void test10() {
FaceResult result = FaceManage.listGroup();
String groupIds = result.getData().getString(FaceConstant.GROUP_ID_LIST);
System.out.println(groupIds);
}
@Test
public void test11() {
String image = "https://download.2dfire.com/mis/permanent/img1.jpg";
ImageU imageU = ImageU.builder().data(image).imageTypeEnum(ImageTypeEnum.URL).build();
String idCardNumber = "235151251";
String name = "陈星星";
FaceManage.personVerify(idCardNumber, name, imageU);
}
@Test
public void test12() {
String image1 = "https://download.2dfire.com/mis/permanent/img1.jpg";
String image2 = "https://download.2dfire.com/mis/permanent/img2.jpg";
ImageU imageU1 = ImageU.builder().data(image1).imageTypeEnum(ImageTypeEnum.URL).build();
ImageU imageU2 = ImageU.builder().data(image2).imageTypeEnum(ImageTypeEnum.URL).build();
boolean match = FaceManage.isfaceMatch(imageU2, imageU1, 80);
int matchScore = FaceManage.faceMatchScore(imageU2, imageU1);
System.out.println("是否匹配:" + match);
System.out.println("匹配等分:" + matchScore);
}
@Test
public void test13() {
String image = "https://download.2dfire.com/mis/permanent/img1.jpg";
ImageU imageU = ImageU.builder().data(image).imageTypeEnum(ImageTypeEnum.URL).build();
FaceResult result = FaceManage.faceDetect(imageU);
String data = result.getData().getString(FaceConstant.FACE_LIST);
System.out.println(data);
}
@Test
public void test14() {
String image = "https://download.2dfire.com/mis/permanent/img1.jpg";
ImageU imageU = ImageU.builder().data(image).imageTypeEnum(ImageTypeEnum.URL).build();
String groupIds = "group1,group2";
FaceResult result = FaceManage.faceSearch(groupIds, imageU);
String users = result.getData().getString(FaceConstant.USER_LIST);
System.out.println(users);
}
@Test
public void test15() {
String image = "https://download.2dfire.com/mis/permanent/img1.jpg";
ImageU imageU = ImageU.builder().data(image).imageTypeEnum(ImageTypeEnum.URL).build();
FaceResult result = FaceManage.faceverify(imageU);
String users = result.getData().toJSonString();
System.out.println(users);
}
}
3.9人脸识别登陆Controller
@PostMapping( "/facelogin")
@ResponseBody
public AjaxResult facelogin(@RequestParam("file") String file,@RequestParam("groupId") String groupId) throws Exception {
MultipartFile multipartFile = base64DecodeMultipartFile.base64Convert(file);//很长
if (multipartFile.isEmpty()) {
throw new BizException("上传文件不能为空");
}
String groupIds = "group1";
String data = FaceUtil.encodebase64(multipartFile.getBytes());
ImageU imageU = ImageU.builder().data(data).imageTypeEnum(ImageTypeEnum.base64).build();
FaceResult result = FaceManage.faceSearch(groupIds, imageU);
String users = result.getData().getString(FaceConstant.USER_LIST);
if (StringUtils.isEmpty(users)){
return AjaxResult.error("用户不存在");
}
JSonArray array = JSONObject.parseArray(users);
JSonObject object = JSONObject.parseObject(array.get(0).toString());
Integer score = object.getInteger(FaceConstant.SCORE);
if (score == null){
return AjaxResult.error("登录失败");
}
if (score >= FaceConstant.MATCH_SCORE){
System.out.println(result.getData().toString());
Long user_id = object.getLong("user_id");
SysUser sysUser = sysUserService.selectUserById(user_id);
AjaxResult ajax = loginService.login(0,sysUser.getUserName());
return ajax;
}
return AjaxResult.error("用户不存在");
}
3.10 枚举,用到的一些辅助类
package com.ruoyi.common.utils.face;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.base64Decoder;
import java.io.*;
import java.util.UUID;
public class base64DecodeMultipartFile implements MultipartFile {
private final byte[] imgContent;
private final String header;
public base64DecodeMultipartFile(byte[] imgContent, String header) {
this.imgContent = imgContent;
this.header = header.split(";")[0];
}
@Override
public String getName() {
return System.currentTimeMillis() + Math.random() + "." + header.split("/")[1];
}
@Override
public String getOriginalFilename() {
return System.currentTimeMillis() + (int) Math.random() * 10000 + "." + header.split("/")[1];
}
@Override
public String getContentType() {
return header.split(":")[1];
}
@Override
public boolean isEmpty() {
return imgContent == null || imgContent.length == 0;
}
@Override
public long getSize() {
return imgContent.length;
}
@Override
public byte[] getBytes() throws IOException {
return imgContent;
}
@Override
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(imgContent);
}
@Override
public void transferTo(File dest) throws IOException, IllegalStateException {
new FileOutputStream(dest).write(imgContent);
}
public static MultipartFile base64Convert(String base64) {
String[] baseStrs = base64.split(",");
base64Decoder decoder = new base64Decoder();
byte[] b = new byte[0];
try {
b = decoder.decodeBuffer(baseStrs[1]);
} catch (IOException e) {
e.printStackTrace();
}
for (int i = 0; i < b.length; ++i) {
if (b[i] < 0) {
b[i] += 256;
}
}
return new base64DecodeMultipartFile(b, baseStrs[0]);
}
}
package com.ruoyi.common.utils.face;
public class BizException extends RuntimeException {
private static final long serialVersionUID = 1L;
private String msg;
private int code = 500;
public BizException(String msg) {
super(msg);
this.msg = msg;
}
public BizException(String msg, Throwable e) {
super(msg, e);
this.msg = msg;
}
public BizException(String msg, int code) {
super(msg);
this.msg = msg;
this.code = code;
}
public BizException(String msg, int code, Throwable e) {
super(msg, e);
this.msg = msg;
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
}
package com.ruoyi.common.utils.face.constant;
public enum ActionTypeEnum {
APPEND("重复注册"),
REPLACE("会用新图替换");
ActionTypeEnum(String desc){
this.desc = desc;
}
private String desc;
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
package com.ruoyi.common.utils.face.constant;
public enum ErrorEnum {
ERROR_ENUM_1(1, "Unknown error", "服务器内部错误,请再次请求"),
ERROR_ENUM_13(13, "Get service token failed", "获取token失败"),
ERROR_ENUM_222202(222202, "pic not has face", "图片中没有人脸"),
ERROR_ENUM_222203(222203, "image check fail", "无法解析人脸"),
ERROR_ENUM_222207(222207, "match user is not found", "未找到匹配的用户"),
ERROR_ENUM_222209(222209, "face token not exist", "face token不存在"),
ERROR_ENUM_222301(222301, "get face fail", "获取人脸图片失败"),
ERROR_ENUM_223102(223102, "user is already exist", "该用户已存在"),
ERROR_ENUM_223106(223106, "face is not exist", "该人脸不存在"),
ERROR_ENUM_223113(223113, "face is covered", "人脸模糊"),
ERROR_ENUM_223114(223114, "face is fuzzy", "人脸模糊"),
ERROR_ENUM_223115(223115, "face light is not good", "人脸光照不好"),
ERROR_ENUM_223116(223116, "incomplete face", "人脸不完整");
ErrorEnum(int errorCode, String desc, String cnDesc){
this.errorCode = errorCode;
this.desc = desc;
this.cnDesc = cnDesc;
}
private int errorCode;
private String desc;
private String cnDesc;
public static ErrorEnum getInstance(int errorCode){
for (ErrorEnum value : ErrorEnum.values()) {
if (value.errorCode == errorCode){
return value;
}
}
return null;
}
public int getErrorCode() {
return errorCode;
}
public void setErrorCode(int errorCode) {
this.errorCode = errorCode;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public String getCnDesc() {
return cnDesc;
}
public void setCnDesc(String cnDesc) {
this.cnDesc = cnDesc;
}
}
package com.ruoyi.common.utils.face.constant;
public class FaceConstant {
public static final String DEFAULT_GROUP_ID = "60030";
public static final int MATCH_SCORE = 80;
public static final String RESULT = "result";
public static final String LOG_ID = "log_id";
public static final String ERROR_MSG = "error_msg";
public static final String CACHED = "cached";
public static final String ERROR_CODE = "error_code";
public static final String TIMESTAMP = "timestamp";
public static final String SCORE = "score";
public static final String FACE_LIST = "face_list";
public static final String FACE_TOKEN = "face_token";
public static final String USER_ID_LIST = "user_id_list";
public static final String GROUP_ID_LIST = "group_id_list";
public static final String USER_LIST = "user_list";
}
package com.ruoyi.common.utils.face.constant;
public enum ImageTypeEnum {
base64("base64", 2),
URL("URL", 0),
FACE_TOKEN("FACE_TOKEN", 0);
ImageTypeEnum(String key, int size){
this.key = key;
this.size = size;
}
private String key;
private int size;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
}
package com.ruoyi.common.utils.face.constant;
public enum LivenessControlEnum {
NONE("不进行控制"),
LOW("较低的活体要求(高通过率 低攻击拒绝率)"),
NORMAL("一般的活体要求(平衡的攻击拒绝率, 通过率)"),
HIGH("较高的活体要求");
LivenessControlEnum(String desc){
this.desc = desc;
}
private String desc;
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
package com.ruoyi.common.utils.face.constant;
public enum QualityControlEnum {
NONE("不进行控制"),
LOW("较低的质量要求"),
NORMAL("一般的质量要求"),
HIGH("较高的质量要求");
QualityControlEnum(String desc){
this.desc = desc;
}
private String desc;
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
4、前端实现
管理系统
记住密码
登 录
登 录 中...
立即注册
Copyright © 2018-2021 nexauto All Rights Reserved.
.login {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
background-image: url("../assets/images/login-background.jpg");
background-size: cover;
}
.title {
margin: 0px auto 30px auto;
text-align: center;
color: #707070;
}
.login-form {
border-radius: 6px;
background: #ffffff;
width: 400px;
padding: 25px 25px 5px 25px;
.el-input {
height: 38px;
input {
height: 38px;
}
}
.input-icon {
height: 39px;
width: 14px;
margin-left: 2px;
}
}
.login-tip {
font-size: 13px;
text-align: center;
color: #bfbfbf;
}
.login-code {
width: 33%;
height: 38px;
float: right;
img {
cursor: pointer;
vertical-align: middle;
}
}
.el-login-footer {
height: 40px;
line-height: 40px;
position: fixed;
bottom: 0;
width: 100%;
text-align: center;
color: #fff;
font-family: Arial;
font-size: 12px;
letter-spacing: 1px;
}
.login-code-img {
height: 38px;
}
.testTrackingWrapper {
height: 300px;
width: 200px;
position: relative;
}
video,
canvas {
position: absolute;
left: 0;
right: 0;
top: 0;
}
.buttonWrapper {
position: absolute;
left: 0;
right: 0;
bottom: 7%;
}
写的不好的地方,可以纠正,如出问题,鄙人可以交流学习:
package com.ruoyi.common.utils.face.utils;
import com.baidu.aip.face.AipFace;
import com.baidu.aip.util.base64Util;
public class FaceUtil {
private static final String APP_ID = "25236971";
private static final String APP_KEY = "zLIZGY15wiEQh2utjwAGGW9C";
private static final String SECRET_KEY = "Pzi4Ew6eWfZPINBkshlCO22OqADa777I";
private static volatile AipFace client = new AipFace(APP_ID, APP_KEY, SECRET_KEY);
// 创建单例避免多次获取sdk
public static AipFace getClient(){
client.setConnectionTimeoutInMillis(2000);
client.setSocketTimeoutInMillis(60000);
return client;
}
public static String encodebase64(byte[] form){
return base64Util.encode(form);
}
public static byte[] decodebase64(String data){
return base64Util.decode(data);
}
}
3.3 创建FaceResultUtil,统一处理请求
package com.ruoyi.common.utils.face.utils;
import com.ruoyi.common.utils.face.BizException;
import com.ruoyi.common.utils.face.constant.ErrorEnum;
import com.ruoyi.common.utils.face.constant.FaceConstant;
import com.ruoyi.common.utils.face.dto.FaceResult;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class FaceResultUtil {
private static final Logger logger = LoggerFactory.getLogger("百度API接口请求结果解析");
public static FaceResult isSuccess(JSonObject res){
FaceResult result = parseJsonObject(res);
if (!result.isSuccess()){
// 对错误进行分类
ErrorEnum errorEnum = ErrorEnum.getInstance(result.getErrorCode());
if (errorEnum == null){
throw new BizException("百度接口请求失败" + result.getErrorMsg());
}else {
throw new BizException(errorEnum.getCnDesc());
}
}
return result;
}
private static FaceResult parseJsonObject(JSonObject res){
FaceResult faceResult = FaceResult.builder().build();
try {
String logId = res.has(FaceConstant.LOG_ID) ? res.get(FaceConstant.LOG_ID).toString() : "0";
int errorCode = res.has(FaceConstant.ERROR_CODE) ? res.getInt(FaceConstant.ERROR_CODE) : -1;
String errorMsg = res.has(FaceConstant.ERROR_MSG) ? res.getString(FaceConstant.ERROR_MSG) : "";
int cached = res.has(FaceConstant.CACHED) ? res.getInt(FaceConstant.CACHED) : 0;
long timestamp = res.has(FaceConstant.TIMESTAMP) ? res.getLong(FaceConstant.TIMESTAMP) : 0;
Object dataString = res.has(FaceConstant.RESULT) ? res.get(FaceConstant.RESULT) : "";
com.alibaba.fastjson.JSonObject data = null;
if (dataString != null) {
data = com.alibaba.fastjson.JSONObject.parseObject(dataString.toString());
}
faceResult.setLogId(logId);
faceResult.setErrorCode(errorCode);
faceResult.setErrorMsg(errorMsg);
faceResult.setCached(cached);
faceResult.setTimestamp(timestamp);
faceResult.setData(data);
}catch (Exception e){
logger.error("JSONObject解析失败", e);
}
return faceResult;
}
}
3.4 创建FaceResult
package com.ruoyi.common.utils.face.dto;
import com.alibaba.fastjson.JSONObject;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class FaceResult implements Serializable {
private String logId;
private String errorMsg;
private int cached;
private int errorCode;
private long timestamp;
private JSonObject data;
public boolean isSuccess(){
return 0 == this.errorCode ? true : false;
}
}
3.5 创建ImageU
package com.ruoyi.common.utils.face.dto;
import com.ruoyi.common.utils.face.constant.ImageTypeEnum;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ImageU implements Serializable {
private ImageTypeEnum imageTypeEnum;
private String data;
}
3.6 创建FaceUserDTO
package com.ruoyi.common.utils.face.dto;
import com.ruoyi.common.utils.face.constant.FaceConstant;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class FaceUserDTO implements Serializable {
private String userId;
private String groupId = FaceConstant.DEFAULT_GROUP_ID;
private String faceToken;
private T user;
}
3.7 创建FaceManage[关键类](重点)
package com.ruoyi.common.utils.face;
import com.alibaba.fastjson.JSON;
import com.baidu.aip.face.FaceVerifyRequest;
import com.baidu.aip.face.MatchRequest;
import com.ruoyi.common.utils.face.constant.ActionTypeEnum;
import com.ruoyi.common.utils.face.constant.FaceConstant;
import com.ruoyi.common.utils.face.constant.LivenessControlEnum;
import com.ruoyi.common.utils.face.constant.QualityControlEnum;
import com.ruoyi.common.utils.face.dto.FaceResult;
import com.ruoyi.common.utils.face.dto.FaceUserDTO;
import com.ruoyi.common.utils.face.dto.ImageU;
import com.ruoyi.common.utils.face.utils.FaceResultUtil;
import com.ruoyi.common.utils.face.utils.FaceUtil;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Objects;
public class FaceManage {
private static final Logger logger = LoggerFactory.getLogger(FaceManage.class);
public static void faceRegister(FaceUserDTO userDTO, ImageU imageU){
// 传入可选参数调用接口
HashMap options = new HashMap();
// 用户资料
options.put("user_info", JSON.toJSonString(userDTO));
// 图片质量
options.put("quality_control", QualityControlEnum.LOW.name());
// 活体检测控制
options.put("liveness_control", LivenessControlEnum.NONE.name());
// 操作方式
options.put("action_type", ActionTypeEnum.REPLACe.name());
String image = imageU.getData();
String imageType = imageU.getImageTypeEnum().name();
String groupId = userDTO.getGroupId();
String userId = userDTO.getUserId();
// 人脸注册
JSonObject res = FaceUtil.getClient().addUser(image, imageType, groupId, userId, options);
FaceResultUtil.isSuccess(res);
logger.info("人脸注册成功");
}
public static void faceUpdate(FaceUserDTO userDTO, ImageU imageU) {
HashMap options = new HashMap();
// 用户资料
options.put("user_info", JSON.toJSonString(userDTO));
// 图片质量
options.put("quality_control", QualityControlEnum.LOW.name());
// 活体检测控制
options.put("liveness_control", LivenessControlEnum.NONE.name());
// 操作方式
options.put("action_type", ActionTypeEnum.REPLACE.name());
String image = imageU.getData();
String imageType = imageU.getImageTypeEnum().name();
String groupId = userDTO.getGroupId();
String userId = userDTO.getUserId();
// 人脸更新
JSonObject res = FaceUtil.getClient().updateUser(image, imageType, groupId, userId, options);
FaceResultUtil.isSuccess(res);
logger.info("人脸更新成功 {}", res.toString(2));
}
public static void faceDelete(String userId, String groupId, String faceToken) {
// 传入可选参数调用接口
HashMap options = new HashMap();
// 人脸删除
JSonObject res = FaceUtil.getClient().faceDelete(userId, groupId, faceToken, options);
FaceResultUtil.isSuccess(res);
logger.info("人脸删除成功 {}", res.toString(2));
}
public static FaceUserDTO findUser(String userId, String groupId) {
HashMap options = new HashMap<>();
// 用户信息查询
JSonObject res = FaceUtil.getClient().getUser(userId, groupId, options);
FaceResult result = FaceResultUtil.isSuccess(res);
return JSON.parseObject(result.getData().toJSonString(), FaceUserDTO.class);
}
public static FaceResult faceGetList(String userId, String groupId){
HashMap options = new HashMap();
// 获取用户人脸列表
JSonObject res = FaceUtil.getClient().faceGetlist(userId, groupId, options);
return FaceResultUtil.isSuccess(res);
}
public static FaceResult listUserByGroupId(String groupId) {
HashMap options = new HashMap();
options.put("start", "0");
options.put("length", "50");
// 获取用户列表
JSonObject res = FaceUtil.getClient().getGroupUsers(groupId, options);
return FaceResultUtil.isSuccess(res);
}
public static void deleteUser(String userId, String groupId) {
HashMap options = new HashMap();
// 删除用户
JSonObject res = FaceUtil.getClient().deleteUser(groupId, userId, options);
FaceResultUtil.isSuccess(res);
logger.info("用户删除成功 {}", res.toString(2));
}
public static void addGroup(String groupId) {
HashMap options = new HashMap();
// 创建用户组
JSonObject res = FaceUtil.getClient().groupAdd(groupId, options);
FaceResultUtil.isSuccess(res);
logger.info("创建用户组 {}", res.toString(2));
}
public static void deleteGroup(String groupId){
HashMap options = new HashMap();
// 删除用户组
JSonObject res = FaceUtil.getClient().groupDelete(groupId, options);
FaceResultUtil.isSuccess(res);
logger.info("删除用户组 {}", res.toString(2));
}
public static FaceResult listGroup() {
HashMap options = new HashMap();
options.put("start", "0");
options.put("length", "50");
// 组列表查询
JSonObject res = FaceUtil.getClient().getGroupList(options);
return FaceResultUtil.isSuccess(res);
}
public static FaceResult personVerify(String idCardNumber, String realName, ImageU imageU){
HashMap options = new HashMap();
options.put("quality_control", QualityControlEnum.LOW.name());
options.put("liveness_control", LivenessControlEnum.NONE.name());
// 身份验证
JSonObject res = FaceUtil.getClient().personVerify(imageU.getData(), imageU.getImageTypeEnum().name(), idCardNumber, realName, options);
return FaceResultUtil.isSuccess(res);
}
public static int faceMatchScore(ImageU imageU1, ImageU imageU2){
MatchRequest req1 = new MatchRequest(imageU1.getData(), imageU1.getImageTypeEnum().name());
MatchRequest req2 = new MatchRequest(imageU2.getData(), imageU2.getImageTypeEnum().name());
ArrayList requests = new ArrayList();
requests.add(req1);
requests.add(req2);
JSonObject res = FaceUtil.getClient().match(requests);
FaceResult result = FaceResultUtil.isSuccess(res);
// 对结果进行特殊处理
Integer score = result.getData().getInteger(FaceConstant.SCORE);
return score == null ? 0 : score;
}
public static boolean isfaceMatch(ImageU imageU1, ImageU imageU2, Integer score){
int defaultScore = FaceConstant.MATCH_SCORE;
if (Objects.nonNull(score)){
defaultScore = score;
}
return faceMatchScore(imageU1, imageU2) > defaultScore ? true : false;
}
public static FaceResult faceDetect(ImageU imageU) {
HashMap options = new HashMap();
options.put("face_field", "age");
options.put("max_face_num", "2");
options.put("face_type", "LIVE");
// 人脸检测
JSonObject res = FaceUtil.getClient().detect(imageU.getData(), imageU.getImageTypeEnum().name(), options);
return FaceResultUtil.isSuccess(res);
}
public static FaceResult faceSearch(String groupIds, ImageU imageU) {
HashMap options = new HashMap();
options.put("max_face_num", "1");
options.put("max_user_num", "1");
options.put("quality_control", QualityControlEnum.LOW.name());
options.put("liveness_control", LivenessControlEnum.NONE.name());
// 人脸搜索
JSonObject res = FaceUtil.getClient().search(imageU.getData(), imageU.getImageTypeEnum().name(), groupIds, options);
return FaceResultUtil.isSuccess(res);
}
public static FaceResult faceverify(ImageU imageU) {
FaceVerifyRequest req = new FaceVerifyRequest(imageU.getData(), imageU.getImageTypeEnum().name());
ArrayList list = new ArrayList();
list.add(req);
JSonObject res = FaceUtil.getClient().faceverify(list);
return FaceResultUtil.isSuccess(res);
}
}
3.8、测试
package com.ruoyi.common.utils.face;
import com.alibaba.fastjson.JSON;
import com.example.common.face.FaceManage;
import com.example.common.face.constant.FaceConstant;
import com.example.common.face.constant.ImageTypeEnum;
import com.example.common.face.dto.FaceResult;
import com.example.common.face.dto.FaceUserDTO;
import com.example.common.face.dto.ImageU;
import com.example.common.face.utils.FaceUtil;
import com.example.common.utils.FilesUtil;
import org.apache.commons.io.IOUtils;
import org.junit.Test;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.HashMap;
public class FaceIdentificationTest {
@Test
public void test00() throws Exception{
FaceUserDTO userDTO = new FaceUserDTO<>();
userDTO.setGroupId("group2");
String filePath = "/Users/cxx/Downloads/entryPhoto/";
File[] files = FilesUtil.listFile(filePath);
int j = 0;
for (File file : files) {
int id = 7000 + j;
j++;
userDTO.setUserId(String.valueOf(id));
InputStream is = new FileInputStream(new File(filePath + file.getName()));
byte[] bytes = IOUtils.toByteArray(is);
String data = FaceUtil.encodebase64(bytes);
ImageU imageU = ImageU.builder().data(data).imageTypeEnum(ImageTypeEnum.base64).build();
userDTO.setUser("用户信息 group1 - " + id);
try {
FaceManage.faceRegister(userDTO, imageU);
}catch (Exception e){
System.out.println("注册失败 msg:" + e.getMessage());
continue;
}
}
}
@Test
public void test01() {
FaceUserDTO userDTO = new FaceUserDTO<>();
userDTO.setGroupId("group1");
userDTO.setUserId("6031");
String image = "https://download.2dfire.com/mis/permanent/img2.jpg";
ImageU imageU = ImageU.builder().data(image).imageTypeEnum(ImageTypeEnum.URL).build();
userDTO.setUser("用户信息1");
FaceManage.faceRegister(userDTO, imageU);
}
@Test
public void test02() {
FaceUserDTO userDTO = new FaceUserDTO();
userDTO.setGroupId("group1");
userDTO.setUserId("6031");
String image = "https://download.2dfire.com/mis/permanent/img2.jpg";
ImageU imageU = ImageU.builder().data(image).imageTypeEnum(ImageTypeEnum.URL).build();
userDTO.setUser("用户信息1");
// 人脸更新
FaceManage.faceUpdate(userDTO, imageU);
}
@Test
public void test03() {
String userId = "6030";
String groupId = "group1";
String faceToken = "5a1a8c17c40ea41264e8830017134972";
FaceManage.faceDelete(userId, groupId, faceToken);
}
@Test
public void test04() {
HashMap options = new HashMap<>();
String userId = "6030";
String groupId = "group1";
// 用户信息查询
FaceUserDTO userDTO = FaceManage.findUser(userId, groupId);
System.out.println("用户信息:" + JSON.toJSonString(userDTO));
}
@Test
public void test05() {
String userId = "6030";
String groupId = "group1";
// 获取用户人脸列表
FaceResult result = FaceManage.faceGetList(userId, groupId);
String data = result.getData().getString(FaceConstant.FACE_LIST);
System.out.println("人脸列表"+data);
}
@Test
public void test06() {
String groupId = "group1";
FaceResult result = FaceManage.listUserByGroupId(groupId);
// 获取用户列表
String userIds = result.getData().getString(FaceConstant.USER_ID_LIST);
System.out.println("userIds" + userIds);
}
@Test
public void test07() {
HashMap options = new HashMap();
String groupId = "group1";
String userId = "6031";
// 删除用户
FaceManage.deleteUser(userId, groupId);
}
@Test
public void test08() {
String groupId = "group2";
FaceManage.addGroup(groupId);
}
@Test
public void test09() {
String groupId = "group2";
FaceManage.deleteGroup(groupId);
}
@Test
public void test10() {
FaceResult result = FaceManage.listGroup();
String groupIds = result.getData().getString(FaceConstant.GROUP_ID_LIST);
System.out.println(groupIds);
}
@Test
public void test11() {
String image = "https://download.2dfire.com/mis/permanent/img1.jpg";
ImageU imageU = ImageU.builder().data(image).imageTypeEnum(ImageTypeEnum.URL).build();
String idCardNumber = "235151251";
String name = "陈星星";
FaceManage.personVerify(idCardNumber, name, imageU);
}
@Test
public void test12() {
String image1 = "https://download.2dfire.com/mis/permanent/img1.jpg";
String image2 = "https://download.2dfire.com/mis/permanent/img2.jpg";
ImageU imageU1 = ImageU.builder().data(image1).imageTypeEnum(ImageTypeEnum.URL).build();
ImageU imageU2 = ImageU.builder().data(image2).imageTypeEnum(ImageTypeEnum.URL).build();
boolean match = FaceManage.isfaceMatch(imageU2, imageU1, 80);
int matchScore = FaceManage.faceMatchScore(imageU2, imageU1);
System.out.println("是否匹配:" + match);
System.out.println("匹配等分:" + matchScore);
}
@Test
public void test13() {
String image = "https://download.2dfire.com/mis/permanent/img1.jpg";
ImageU imageU = ImageU.builder().data(image).imageTypeEnum(ImageTypeEnum.URL).build();
FaceResult result = FaceManage.faceDetect(imageU);
String data = result.getData().getString(FaceConstant.FACE_LIST);
System.out.println(data);
}
@Test
public void test14() {
String image = "https://download.2dfire.com/mis/permanent/img1.jpg";
ImageU imageU = ImageU.builder().data(image).imageTypeEnum(ImageTypeEnum.URL).build();
String groupIds = "group1,group2";
FaceResult result = FaceManage.faceSearch(groupIds, imageU);
String users = result.getData().getString(FaceConstant.USER_LIST);
System.out.println(users);
}
@Test
public void test15() {
String image = "https://download.2dfire.com/mis/permanent/img1.jpg";
ImageU imageU = ImageU.builder().data(image).imageTypeEnum(ImageTypeEnum.URL).build();
FaceResult result = FaceManage.faceverify(imageU);
String users = result.getData().toJSonString();
System.out.println(users);
}
}
3.9人脸识别登陆Controller
@PostMapping( "/facelogin")
@ResponseBody
public AjaxResult facelogin(@RequestParam("file") String file,@RequestParam("groupId") String groupId) throws Exception {
MultipartFile multipartFile = base64DecodeMultipartFile.base64Convert(file);//很长
if (multipartFile.isEmpty()) {
throw new BizException("上传文件不能为空");
}
String groupIds = "group1";
String data = FaceUtil.encodebase64(multipartFile.getBytes());
ImageU imageU = ImageU.builder().data(data).imageTypeEnum(ImageTypeEnum.base64).build();
FaceResult result = FaceManage.faceSearch(groupIds, imageU);
String users = result.getData().getString(FaceConstant.USER_LIST);
if (StringUtils.isEmpty(users)){
return AjaxResult.error("用户不存在");
}
JSonArray array = JSONObject.parseArray(users);
JSonObject object = JSONObject.parseObject(array.get(0).toString());
Integer score = object.getInteger(FaceConstant.SCORE);
if (score == null){
return AjaxResult.error("登录失败");
}
if (score >= FaceConstant.MATCH_SCORE){
System.out.println(result.getData().toString());
Long user_id = object.getLong("user_id");
SysUser sysUser = sysUserService.selectUserById(user_id);
AjaxResult ajax = loginService.login(0,sysUser.getUserName());
return ajax;
}
return AjaxResult.error("用户不存在");
}
3.10 枚举,用到的一些辅助类
package com.ruoyi.common.utils.face;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.base64Decoder;
import java.io.*;
import java.util.UUID;
public class base64DecodeMultipartFile implements MultipartFile {
private final byte[] imgContent;
private final String header;
public base64DecodeMultipartFile(byte[] imgContent, String header) {
this.imgContent = imgContent;
this.header = header.split(";")[0];
}
@Override
public String getName() {
return System.currentTimeMillis() + Math.random() + "." + header.split("/")[1];
}
@Override
public String getOriginalFilename() {
return System.currentTimeMillis() + (int) Math.random() * 10000 + "." + header.split("/")[1];
}
@Override
public String getContentType() {
return header.split(":")[1];
}
@Override
public boolean isEmpty() {
return imgContent == null || imgContent.length == 0;
}
@Override
public long getSize() {
return imgContent.length;
}
@Override
public byte[] getBytes() throws IOException {
return imgContent;
}
@Override
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(imgContent);
}
@Override
public void transferTo(File dest) throws IOException, IllegalStateException {
new FileOutputStream(dest).write(imgContent);
}
public static MultipartFile base64Convert(String base64) {
String[] baseStrs = base64.split(",");
base64Decoder decoder = new base64Decoder();
byte[] b = new byte[0];
try {
b = decoder.decodeBuffer(baseStrs[1]);
} catch (IOException e) {
e.printStackTrace();
}
for (int i = 0; i < b.length; ++i) {
if (b[i] < 0) {
b[i] += 256;
}
}
return new base64DecodeMultipartFile(b, baseStrs[0]);
}
}
package com.ruoyi.common.utils.face;
public class BizException extends RuntimeException {
private static final long serialVersionUID = 1L;
private String msg;
private int code = 500;
public BizException(String msg) {
super(msg);
this.msg = msg;
}
public BizException(String msg, Throwable e) {
super(msg, e);
this.msg = msg;
}
public BizException(String msg, int code) {
super(msg);
this.msg = msg;
this.code = code;
}
public BizException(String msg, int code, Throwable e) {
super(msg, e);
this.msg = msg;
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
}
package com.ruoyi.common.utils.face.constant;
public enum ActionTypeEnum {
APPEND("重复注册"),
REPLACE("会用新图替换");
ActionTypeEnum(String desc){
this.desc = desc;
}
private String desc;
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
package com.ruoyi.common.utils.face.constant;
public enum ErrorEnum {
ERROR_ENUM_1(1, "Unknown error", "服务器内部错误,请再次请求"),
ERROR_ENUM_13(13, "Get service token failed", "获取token失败"),
ERROR_ENUM_222202(222202, "pic not has face", "图片中没有人脸"),
ERROR_ENUM_222203(222203, "image check fail", "无法解析人脸"),
ERROR_ENUM_222207(222207, "match user is not found", "未找到匹配的用户"),
ERROR_ENUM_222209(222209, "face token not exist", "face token不存在"),
ERROR_ENUM_222301(222301, "get face fail", "获取人脸图片失败"),
ERROR_ENUM_223102(223102, "user is already exist", "该用户已存在"),
ERROR_ENUM_223106(223106, "face is not exist", "该人脸不存在"),
ERROR_ENUM_223113(223113, "face is covered", "人脸模糊"),
ERROR_ENUM_223114(223114, "face is fuzzy", "人脸模糊"),
ERROR_ENUM_223115(223115, "face light is not good", "人脸光照不好"),
ERROR_ENUM_223116(223116, "incomplete face", "人脸不完整");
ErrorEnum(int errorCode, String desc, String cnDesc){
this.errorCode = errorCode;
this.desc = desc;
this.cnDesc = cnDesc;
}
private int errorCode;
private String desc;
private String cnDesc;
public static ErrorEnum getInstance(int errorCode){
for (ErrorEnum value : ErrorEnum.values()) {
if (value.errorCode == errorCode){
return value;
}
}
return null;
}
public int getErrorCode() {
return errorCode;
}
public void setErrorCode(int errorCode) {
this.errorCode = errorCode;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public String getCnDesc() {
return cnDesc;
}
public void setCnDesc(String cnDesc) {
this.cnDesc = cnDesc;
}
}
package com.ruoyi.common.utils.face.constant;
public class FaceConstant {
public static final String DEFAULT_GROUP_ID = "60030";
public static final int MATCH_SCORE = 80;
public static final String RESULT = "result";
public static final String LOG_ID = "log_id";
public static final String ERROR_MSG = "error_msg";
public static final String CACHED = "cached";
public static final String ERROR_CODE = "error_code";
public static final String TIMESTAMP = "timestamp";
public static final String SCORE = "score";
public static final String FACE_LIST = "face_list";
public static final String FACE_TOKEN = "face_token";
public static final String USER_ID_LIST = "user_id_list";
public static final String GROUP_ID_LIST = "group_id_list";
public static final String USER_LIST = "user_list";
}
package com.ruoyi.common.utils.face.constant;
public enum ImageTypeEnum {
base64("base64", 2),
URL("URL", 0),
FACE_TOKEN("FACE_TOKEN", 0);
ImageTypeEnum(String key, int size){
this.key = key;
this.size = size;
}
private String key;
private int size;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
}
package com.ruoyi.common.utils.face.constant;
public enum LivenessControlEnum {
NONE("不进行控制"),
LOW("较低的活体要求(高通过率 低攻击拒绝率)"),
NORMAL("一般的活体要求(平衡的攻击拒绝率, 通过率)"),
HIGH("较高的活体要求");
LivenessControlEnum(String desc){
this.desc = desc;
}
private String desc;
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
package com.ruoyi.common.utils.face.constant;
public enum QualityControlEnum {
NONE("不进行控制"),
LOW("较低的质量要求"),
NORMAL("一般的质量要求"),
HIGH("较高的质量要求");
QualityControlEnum(String desc){
this.desc = desc;
}
private String desc;
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
4、前端实现
管理系统
记住密码
登 录
登 录 中...
立即注册
Copyright © 2018-2021 nexauto All Rights Reserved.
.login {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
background-image: url("../assets/images/login-background.jpg");
background-size: cover;
}
.title {
margin: 0px auto 30px auto;
text-align: center;
color: #707070;
}
.login-form {
border-radius: 6px;
background: #ffffff;
width: 400px;
padding: 25px 25px 5px 25px;
.el-input {
height: 38px;
input {
height: 38px;
}
}
.input-icon {
height: 39px;
width: 14px;
margin-left: 2px;
}
}
.login-tip {
font-size: 13px;
text-align: center;
color: #bfbfbf;
}
.login-code {
width: 33%;
height: 38px;
float: right;
img {
cursor: pointer;
vertical-align: middle;
}
}
.el-login-footer {
height: 40px;
line-height: 40px;
position: fixed;
bottom: 0;
width: 100%;
text-align: center;
color: #fff;
font-family: Arial;
font-size: 12px;
letter-spacing: 1px;
}
.login-code-img {
height: 38px;
}
.testTrackingWrapper {
height: 300px;
width: 200px;
position: relative;
}
video,
canvas {
position: absolute;
left: 0;
right: 0;
top: 0;
}
.buttonWrapper {
position: absolute;
left: 0;
right: 0;
bottom: 7%;
}
写的不好的地方,可以纠正,如出问题,鄙人可以交流学习:
package com.ruoyi.common.utils.face.dto;
import com.alibaba.fastjson.JSONObject;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class FaceResult implements Serializable {
private String logId;
private String errorMsg;
private int cached;
private int errorCode;
private long timestamp;
private JSonObject data;
public boolean isSuccess(){
return 0 == this.errorCode ? true : false;
}
}
3.5 创建ImageU
package com.ruoyi.common.utils.face.dto;
import com.ruoyi.common.utils.face.constant.ImageTypeEnum;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ImageU implements Serializable {
private ImageTypeEnum imageTypeEnum;
private String data;
}
3.6 创建FaceUserDTO
package com.ruoyi.common.utils.face.dto;
import com.ruoyi.common.utils.face.constant.FaceConstant;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class FaceUserDTO implements Serializable {
private String userId;
private String groupId = FaceConstant.DEFAULT_GROUP_ID;
private String faceToken;
private T user;
}
3.7 创建FaceManage[关键类](重点)
package com.ruoyi.common.utils.face;
import com.alibaba.fastjson.JSON;
import com.baidu.aip.face.FaceVerifyRequest;
import com.baidu.aip.face.MatchRequest;
import com.ruoyi.common.utils.face.constant.ActionTypeEnum;
import com.ruoyi.common.utils.face.constant.FaceConstant;
import com.ruoyi.common.utils.face.constant.LivenessControlEnum;
import com.ruoyi.common.utils.face.constant.QualityControlEnum;
import com.ruoyi.common.utils.face.dto.FaceResult;
import com.ruoyi.common.utils.face.dto.FaceUserDTO;
import com.ruoyi.common.utils.face.dto.ImageU;
import com.ruoyi.common.utils.face.utils.FaceResultUtil;
import com.ruoyi.common.utils.face.utils.FaceUtil;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Objects;
public class FaceManage {
private static final Logger logger = LoggerFactory.getLogger(FaceManage.class);
public static void faceRegister(FaceUserDTO userDTO, ImageU imageU){
// 传入可选参数调用接口
HashMap options = new HashMap();
// 用户资料
options.put("user_info", JSON.toJSonString(userDTO));
// 图片质量
options.put("quality_control", QualityControlEnum.LOW.name());
// 活体检测控制
options.put("liveness_control", LivenessControlEnum.NONE.name());
// 操作方式
options.put("action_type", ActionTypeEnum.REPLACe.name());
String image = imageU.getData();
String imageType = imageU.getImageTypeEnum().name();
String groupId = userDTO.getGroupId();
String userId = userDTO.getUserId();
// 人脸注册
JSonObject res = FaceUtil.getClient().addUser(image, imageType, groupId, userId, options);
FaceResultUtil.isSuccess(res);
logger.info("人脸注册成功");
}
public static void faceUpdate(FaceUserDTO userDTO, ImageU imageU) {
HashMap options = new HashMap();
// 用户资料
options.put("user_info", JSON.toJSonString(userDTO));
// 图片质量
options.put("quality_control", QualityControlEnum.LOW.name());
// 活体检测控制
options.put("liveness_control", LivenessControlEnum.NONE.name());
// 操作方式
options.put("action_type", ActionTypeEnum.REPLACE.name());
String image = imageU.getData();
String imageType = imageU.getImageTypeEnum().name();
String groupId = userDTO.getGroupId();
String userId = userDTO.getUserId();
// 人脸更新
JSonObject res = FaceUtil.getClient().updateUser(image, imageType, groupId, userId, options);
FaceResultUtil.isSuccess(res);
logger.info("人脸更新成功 {}", res.toString(2));
}
public static void faceDelete(String userId, String groupId, String faceToken) {
// 传入可选参数调用接口
HashMap options = new HashMap();
// 人脸删除
JSonObject res = FaceUtil.getClient().faceDelete(userId, groupId, faceToken, options);
FaceResultUtil.isSuccess(res);
logger.info("人脸删除成功 {}", res.toString(2));
}
public static FaceUserDTO findUser(String userId, String groupId) {
HashMap options = new HashMap<>();
// 用户信息查询
JSonObject res = FaceUtil.getClient().getUser(userId, groupId, options);
FaceResult result = FaceResultUtil.isSuccess(res);
return JSON.parseObject(result.getData().toJSonString(), FaceUserDTO.class);
}
public static FaceResult faceGetList(String userId, String groupId){
HashMap options = new HashMap();
// 获取用户人脸列表
JSonObject res = FaceUtil.getClient().faceGetlist(userId, groupId, options);
return FaceResultUtil.isSuccess(res);
}
public static FaceResult listUserByGroupId(String groupId) {
HashMap options = new HashMap();
options.put("start", "0");
options.put("length", "50");
// 获取用户列表
JSonObject res = FaceUtil.getClient().getGroupUsers(groupId, options);
return FaceResultUtil.isSuccess(res);
}
public static void deleteUser(String userId, String groupId) {
HashMap options = new HashMap();
// 删除用户
JSonObject res = FaceUtil.getClient().deleteUser(groupId, userId, options);
FaceResultUtil.isSuccess(res);
logger.info("用户删除成功 {}", res.toString(2));
}
public static void addGroup(String groupId) {
HashMap options = new HashMap();
// 创建用户组
JSonObject res = FaceUtil.getClient().groupAdd(groupId, options);
FaceResultUtil.isSuccess(res);
logger.info("创建用户组 {}", res.toString(2));
}
public static void deleteGroup(String groupId){
HashMap options = new HashMap();
// 删除用户组
JSonObject res = FaceUtil.getClient().groupDelete(groupId, options);
FaceResultUtil.isSuccess(res);
logger.info("删除用户组 {}", res.toString(2));
}
public static FaceResult listGroup() {
HashMap options = new HashMap();
options.put("start", "0");
options.put("length", "50");
// 组列表查询
JSonObject res = FaceUtil.getClient().getGroupList(options);
return FaceResultUtil.isSuccess(res);
}
public static FaceResult personVerify(String idCardNumber, String realName, ImageU imageU){
HashMap options = new HashMap();
options.put("quality_control", QualityControlEnum.LOW.name());
options.put("liveness_control", LivenessControlEnum.NONE.name());
// 身份验证
JSonObject res = FaceUtil.getClient().personVerify(imageU.getData(), imageU.getImageTypeEnum().name(), idCardNumber, realName, options);
return FaceResultUtil.isSuccess(res);
}
public static int faceMatchScore(ImageU imageU1, ImageU imageU2){
MatchRequest req1 = new MatchRequest(imageU1.getData(), imageU1.getImageTypeEnum().name());
MatchRequest req2 = new MatchRequest(imageU2.getData(), imageU2.getImageTypeEnum().name());
ArrayList requests = new ArrayList();
requests.add(req1);
requests.add(req2);
JSonObject res = FaceUtil.getClient().match(requests);
FaceResult result = FaceResultUtil.isSuccess(res);
// 对结果进行特殊处理
Integer score = result.getData().getInteger(FaceConstant.SCORE);
return score == null ? 0 : score;
}
public static boolean isfaceMatch(ImageU imageU1, ImageU imageU2, Integer score){
int defaultScore = FaceConstant.MATCH_SCORE;
if (Objects.nonNull(score)){
defaultScore = score;
}
return faceMatchScore(imageU1, imageU2) > defaultScore ? true : false;
}
public static FaceResult faceDetect(ImageU imageU) {
HashMap options = new HashMap();
options.put("face_field", "age");
options.put("max_face_num", "2");
options.put("face_type", "LIVE");
// 人脸检测
JSonObject res = FaceUtil.getClient().detect(imageU.getData(), imageU.getImageTypeEnum().name(), options);
return FaceResultUtil.isSuccess(res);
}
public static FaceResult faceSearch(String groupIds, ImageU imageU) {
HashMap options = new HashMap();
options.put("max_face_num", "1");
options.put("max_user_num", "1");
options.put("quality_control", QualityControlEnum.LOW.name());
options.put("liveness_control", LivenessControlEnum.NONE.name());
// 人脸搜索
JSonObject res = FaceUtil.getClient().search(imageU.getData(), imageU.getImageTypeEnum().name(), groupIds, options);
return FaceResultUtil.isSuccess(res);
}
public static FaceResult faceverify(ImageU imageU) {
FaceVerifyRequest req = new FaceVerifyRequest(imageU.getData(), imageU.getImageTypeEnum().name());
ArrayList list = new ArrayList();
list.add(req);
JSonObject res = FaceUtil.getClient().faceverify(list);
return FaceResultUtil.isSuccess(res);
}
}
3.8、测试
package com.ruoyi.common.utils.face;
import com.alibaba.fastjson.JSON;
import com.example.common.face.FaceManage;
import com.example.common.face.constant.FaceConstant;
import com.example.common.face.constant.ImageTypeEnum;
import com.example.common.face.dto.FaceResult;
import com.example.common.face.dto.FaceUserDTO;
import com.example.common.face.dto.ImageU;
import com.example.common.face.utils.FaceUtil;
import com.example.common.utils.FilesUtil;
import org.apache.commons.io.IOUtils;
import org.junit.Test;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.HashMap;
public class FaceIdentificationTest {
@Test
public void test00() throws Exception{
FaceUserDTO userDTO = new FaceUserDTO<>();
userDTO.setGroupId("group2");
String filePath = "/Users/cxx/Downloads/entryPhoto/";
File[] files = FilesUtil.listFile(filePath);
int j = 0;
for (File file : files) {
int id = 7000 + j;
j++;
userDTO.setUserId(String.valueOf(id));
InputStream is = new FileInputStream(new File(filePath + file.getName()));
byte[] bytes = IOUtils.toByteArray(is);
String data = FaceUtil.encodebase64(bytes);
ImageU imageU = ImageU.builder().data(data).imageTypeEnum(ImageTypeEnum.base64).build();
userDTO.setUser("用户信息 group1 - " + id);
try {
FaceManage.faceRegister(userDTO, imageU);
}catch (Exception e){
System.out.println("注册失败 msg:" + e.getMessage());
continue;
}
}
}
@Test
public void test01() {
FaceUserDTO userDTO = new FaceUserDTO<>();
userDTO.setGroupId("group1");
userDTO.setUserId("6031");
String image = "https://download.2dfire.com/mis/permanent/img2.jpg";
ImageU imageU = ImageU.builder().data(image).imageTypeEnum(ImageTypeEnum.URL).build();
userDTO.setUser("用户信息1");
FaceManage.faceRegister(userDTO, imageU);
}
@Test
public void test02() {
FaceUserDTO userDTO = new FaceUserDTO();
userDTO.setGroupId("group1");
userDTO.setUserId("6031");
String image = "https://download.2dfire.com/mis/permanent/img2.jpg";
ImageU imageU = ImageU.builder().data(image).imageTypeEnum(ImageTypeEnum.URL).build();
userDTO.setUser("用户信息1");
// 人脸更新
FaceManage.faceUpdate(userDTO, imageU);
}
@Test
public void test03() {
String userId = "6030";
String groupId = "group1";
String faceToken = "5a1a8c17c40ea41264e8830017134972";
FaceManage.faceDelete(userId, groupId, faceToken);
}
@Test
public void test04() {
HashMap options = new HashMap<>();
String userId = "6030";
String groupId = "group1";
// 用户信息查询
FaceUserDTO userDTO = FaceManage.findUser(userId, groupId);
System.out.println("用户信息:" + JSON.toJSonString(userDTO));
}
@Test
public void test05() {
String userId = "6030";
String groupId = "group1";
// 获取用户人脸列表
FaceResult result = FaceManage.faceGetList(userId, groupId);
String data = result.getData().getString(FaceConstant.FACE_LIST);
System.out.println("人脸列表"+data);
}
@Test
public void test06() {
String groupId = "group1";
FaceResult result = FaceManage.listUserByGroupId(groupId);
// 获取用户列表
String userIds = result.getData().getString(FaceConstant.USER_ID_LIST);
System.out.println("userIds" + userIds);
}
@Test
public void test07() {
HashMap options = new HashMap();
String groupId = "group1";
String userId = "6031";
// 删除用户
FaceManage.deleteUser(userId, groupId);
}
@Test
public void test08() {
String groupId = "group2";
FaceManage.addGroup(groupId);
}
@Test
public void test09() {
String groupId = "group2";
FaceManage.deleteGroup(groupId);
}
@Test
public void test10() {
FaceResult result = FaceManage.listGroup();
String groupIds = result.getData().getString(FaceConstant.GROUP_ID_LIST);
System.out.println(groupIds);
}
@Test
public void test11() {
String image = "https://download.2dfire.com/mis/permanent/img1.jpg";
ImageU imageU = ImageU.builder().data(image).imageTypeEnum(ImageTypeEnum.URL).build();
String idCardNumber = "235151251";
String name = "陈星星";
FaceManage.personVerify(idCardNumber, name, imageU);
}
@Test
public void test12() {
String image1 = "https://download.2dfire.com/mis/permanent/img1.jpg";
String image2 = "https://download.2dfire.com/mis/permanent/img2.jpg";
ImageU imageU1 = ImageU.builder().data(image1).imageTypeEnum(ImageTypeEnum.URL).build();
ImageU imageU2 = ImageU.builder().data(image2).imageTypeEnum(ImageTypeEnum.URL).build();
boolean match = FaceManage.isfaceMatch(imageU2, imageU1, 80);
int matchScore = FaceManage.faceMatchScore(imageU2, imageU1);
System.out.println("是否匹配:" + match);
System.out.println("匹配等分:" + matchScore);
}
@Test
public void test13() {
String image = "https://download.2dfire.com/mis/permanent/img1.jpg";
ImageU imageU = ImageU.builder().data(image).imageTypeEnum(ImageTypeEnum.URL).build();
FaceResult result = FaceManage.faceDetect(imageU);
String data = result.getData().getString(FaceConstant.FACE_LIST);
System.out.println(data);
}
@Test
public void test14() {
String image = "https://download.2dfire.com/mis/permanent/img1.jpg";
ImageU imageU = ImageU.builder().data(image).imageTypeEnum(ImageTypeEnum.URL).build();
String groupIds = "group1,group2";
FaceResult result = FaceManage.faceSearch(groupIds, imageU);
String users = result.getData().getString(FaceConstant.USER_LIST);
System.out.println(users);
}
@Test
public void test15() {
String image = "https://download.2dfire.com/mis/permanent/img1.jpg";
ImageU imageU = ImageU.builder().data(image).imageTypeEnum(ImageTypeEnum.URL).build();
FaceResult result = FaceManage.faceverify(imageU);
String users = result.getData().toJSonString();
System.out.println(users);
}
}
3.9人脸识别登陆Controller
@PostMapping( "/facelogin")
@ResponseBody
public AjaxResult facelogin(@RequestParam("file") String file,@RequestParam("groupId") String groupId) throws Exception {
MultipartFile multipartFile = base64DecodeMultipartFile.base64Convert(file);//很长
if (multipartFile.isEmpty()) {
throw new BizException("上传文件不能为空");
}
String groupIds = "group1";
String data = FaceUtil.encodebase64(multipartFile.getBytes());
ImageU imageU = ImageU.builder().data(data).imageTypeEnum(ImageTypeEnum.base64).build();
FaceResult result = FaceManage.faceSearch(groupIds, imageU);
String users = result.getData().getString(FaceConstant.USER_LIST);
if (StringUtils.isEmpty(users)){
return AjaxResult.error("用户不存在");
}
JSonArray array = JSONObject.parseArray(users);
JSonObject object = JSONObject.parseObject(array.get(0).toString());
Integer score = object.getInteger(FaceConstant.SCORE);
if (score == null){
return AjaxResult.error("登录失败");
}
if (score >= FaceConstant.MATCH_SCORE){
System.out.println(result.getData().toString());
Long user_id = object.getLong("user_id");
SysUser sysUser = sysUserService.selectUserById(user_id);
AjaxResult ajax = loginService.login(0,sysUser.getUserName());
return ajax;
}
return AjaxResult.error("用户不存在");
}
3.10 枚举,用到的一些辅助类
package com.ruoyi.common.utils.face;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.base64Decoder;
import java.io.*;
import java.util.UUID;
public class base64DecodeMultipartFile implements MultipartFile {
private final byte[] imgContent;
private final String header;
public base64DecodeMultipartFile(byte[] imgContent, String header) {
this.imgContent = imgContent;
this.header = header.split(";")[0];
}
@Override
public String getName() {
return System.currentTimeMillis() + Math.random() + "." + header.split("/")[1];
}
@Override
public String getOriginalFilename() {
return System.currentTimeMillis() + (int) Math.random() * 10000 + "." + header.split("/")[1];
}
@Override
public String getContentType() {
return header.split(":")[1];
}
@Override
public boolean isEmpty() {
return imgContent == null || imgContent.length == 0;
}
@Override
public long getSize() {
return imgContent.length;
}
@Override
public byte[] getBytes() throws IOException {
return imgContent;
}
@Override
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(imgContent);
}
@Override
public void transferTo(File dest) throws IOException, IllegalStateException {
new FileOutputStream(dest).write(imgContent);
}
public static MultipartFile base64Convert(String base64) {
String[] baseStrs = base64.split(",");
base64Decoder decoder = new base64Decoder();
byte[] b = new byte[0];
try {
b = decoder.decodeBuffer(baseStrs[1]);
} catch (IOException e) {
e.printStackTrace();
}
for (int i = 0; i < b.length; ++i) {
if (b[i] < 0) {
b[i] += 256;
}
}
return new base64DecodeMultipartFile(b, baseStrs[0]);
}
}
package com.ruoyi.common.utils.face;
public class BizException extends RuntimeException {
private static final long serialVersionUID = 1L;
private String msg;
private int code = 500;
public BizException(String msg) {
super(msg);
this.msg = msg;
}
public BizException(String msg, Throwable e) {
super(msg, e);
this.msg = msg;
}
public BizException(String msg, int code) {
super(msg);
this.msg = msg;
this.code = code;
}
public BizException(String msg, int code, Throwable e) {
super(msg, e);
this.msg = msg;
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
}
package com.ruoyi.common.utils.face.constant;
public enum ActionTypeEnum {
APPEND("重复注册"),
REPLACE("会用新图替换");
ActionTypeEnum(String desc){
this.desc = desc;
}
private String desc;
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
package com.ruoyi.common.utils.face.constant;
public enum ErrorEnum {
ERROR_ENUM_1(1, "Unknown error", "服务器内部错误,请再次请求"),
ERROR_ENUM_13(13, "Get service token failed", "获取token失败"),
ERROR_ENUM_222202(222202, "pic not has face", "图片中没有人脸"),
ERROR_ENUM_222203(222203, "image check fail", "无法解析人脸"),
ERROR_ENUM_222207(222207, "match user is not found", "未找到匹配的用户"),
ERROR_ENUM_222209(222209, "face token not exist", "face token不存在"),
ERROR_ENUM_222301(222301, "get face fail", "获取人脸图片失败"),
ERROR_ENUM_223102(223102, "user is already exist", "该用户已存在"),
ERROR_ENUM_223106(223106, "face is not exist", "该人脸不存在"),
ERROR_ENUM_223113(223113, "face is covered", "人脸模糊"),
ERROR_ENUM_223114(223114, "face is fuzzy", "人脸模糊"),
ERROR_ENUM_223115(223115, "face light is not good", "人脸光照不好"),
ERROR_ENUM_223116(223116, "incomplete face", "人脸不完整");
ErrorEnum(int errorCode, String desc, String cnDesc){
this.errorCode = errorCode;
this.desc = desc;
this.cnDesc = cnDesc;
}
private int errorCode;
private String desc;
private String cnDesc;
public static ErrorEnum getInstance(int errorCode){
for (ErrorEnum value : ErrorEnum.values()) {
if (value.errorCode == errorCode){
return value;
}
}
return null;
}
public int getErrorCode() {
return errorCode;
}
public void setErrorCode(int errorCode) {
this.errorCode = errorCode;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public String getCnDesc() {
return cnDesc;
}
public void setCnDesc(String cnDesc) {
this.cnDesc = cnDesc;
}
}
package com.ruoyi.common.utils.face.constant;
public class FaceConstant {
public static final String DEFAULT_GROUP_ID = "60030";
public static final int MATCH_SCORE = 80;
public static final String RESULT = "result";
public static final String LOG_ID = "log_id";
public static final String ERROR_MSG = "error_msg";
public static final String CACHED = "cached";
public static final String ERROR_CODE = "error_code";
public static final String TIMESTAMP = "timestamp";
public static final String SCORE = "score";
public static final String FACE_LIST = "face_list";
public static final String FACE_TOKEN = "face_token";
public static final String USER_ID_LIST = "user_id_list";
public static final String GROUP_ID_LIST = "group_id_list";
public static final String USER_LIST = "user_list";
}
package com.ruoyi.common.utils.face.constant;
public enum ImageTypeEnum {
base64("base64", 2),
URL("URL", 0),
FACE_TOKEN("FACE_TOKEN", 0);
ImageTypeEnum(String key, int size){
this.key = key;
this.size = size;
}
private String key;
private int size;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
}
package com.ruoyi.common.utils.face.constant;
public enum LivenessControlEnum {
NONE("不进行控制"),
LOW("较低的活体要求(高通过率 低攻击拒绝率)"),
NORMAL("一般的活体要求(平衡的攻击拒绝率, 通过率)"),
HIGH("较高的活体要求");
LivenessControlEnum(String desc){
this.desc = desc;
}
private String desc;
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
package com.ruoyi.common.utils.face.constant;
public enum QualityControlEnum {
NONE("不进行控制"),
LOW("较低的质量要求"),
NORMAL("一般的质量要求"),
HIGH("较高的质量要求");
QualityControlEnum(String desc){
this.desc = desc;
}
private String desc;
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
4、前端实现
管理系统
记住密码
登 录
登 录 中...
立即注册
Copyright © 2018-2021 nexauto All Rights Reserved.
.login {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
background-image: url("../assets/images/login-background.jpg");
background-size: cover;
}
.title {
margin: 0px auto 30px auto;
text-align: center;
color: #707070;
}
.login-form {
border-radius: 6px;
background: #ffffff;
width: 400px;
padding: 25px 25px 5px 25px;
.el-input {
height: 38px;
input {
height: 38px;
}
}
.input-icon {
height: 39px;
width: 14px;
margin-left: 2px;
}
}
.login-tip {
font-size: 13px;
text-align: center;
color: #bfbfbf;
}
.login-code {
width: 33%;
height: 38px;
float: right;
img {
cursor: pointer;
vertical-align: middle;
}
}
.el-login-footer {
height: 40px;
line-height: 40px;
position: fixed;
bottom: 0;
width: 100%;
text-align: center;
color: #fff;
font-family: Arial;
font-size: 12px;
letter-spacing: 1px;
}
.login-code-img {
height: 38px;
}
.testTrackingWrapper {
height: 300px;
width: 200px;
position: relative;
}
video,
canvas {
position: absolute;
left: 0;
right: 0;
top: 0;
}
.buttonWrapper {
position: absolute;
left: 0;
right: 0;
bottom: 7%;
}
写的不好的地方,可以纠正,如出问题,鄙人可以交流学习:
package com.ruoyi.common.utils.face.dto; import com.ruoyi.common.utils.face.constant.FaceConstant; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; @Data @Builder @AllArgsConstructor @NoArgsConstructor public class FaceUserDTOimplements Serializable { private String userId; private String groupId = FaceConstant.DEFAULT_GROUP_ID; private String faceToken; private T user; }
3.7 创建FaceManage[关键类](重点)
package com.ruoyi.common.utils.face;
import com.alibaba.fastjson.JSON;
import com.baidu.aip.face.FaceVerifyRequest;
import com.baidu.aip.face.MatchRequest;
import com.ruoyi.common.utils.face.constant.ActionTypeEnum;
import com.ruoyi.common.utils.face.constant.FaceConstant;
import com.ruoyi.common.utils.face.constant.LivenessControlEnum;
import com.ruoyi.common.utils.face.constant.QualityControlEnum;
import com.ruoyi.common.utils.face.dto.FaceResult;
import com.ruoyi.common.utils.face.dto.FaceUserDTO;
import com.ruoyi.common.utils.face.dto.ImageU;
import com.ruoyi.common.utils.face.utils.FaceResultUtil;
import com.ruoyi.common.utils.face.utils.FaceUtil;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Objects;
public class FaceManage {
private static final Logger logger = LoggerFactory.getLogger(FaceManage.class);
public static void faceRegister(FaceUserDTO userDTO, ImageU imageU){
// 传入可选参数调用接口
HashMap options = new HashMap();
// 用户资料
options.put("user_info", JSON.toJSonString(userDTO));
// 图片质量
options.put("quality_control", QualityControlEnum.LOW.name());
// 活体检测控制
options.put("liveness_control", LivenessControlEnum.NONE.name());
// 操作方式
options.put("action_type", ActionTypeEnum.REPLACe.name());
String image = imageU.getData();
String imageType = imageU.getImageTypeEnum().name();
String groupId = userDTO.getGroupId();
String userId = userDTO.getUserId();
// 人脸注册
JSonObject res = FaceUtil.getClient().addUser(image, imageType, groupId, userId, options);
FaceResultUtil.isSuccess(res);
logger.info("人脸注册成功");
}
public static void faceUpdate(FaceUserDTO userDTO, ImageU imageU) {
HashMap options = new HashMap();
// 用户资料
options.put("user_info", JSON.toJSonString(userDTO));
// 图片质量
options.put("quality_control", QualityControlEnum.LOW.name());
// 活体检测控制
options.put("liveness_control", LivenessControlEnum.NONE.name());
// 操作方式
options.put("action_type", ActionTypeEnum.REPLACE.name());
String image = imageU.getData();
String imageType = imageU.getImageTypeEnum().name();
String groupId = userDTO.getGroupId();
String userId = userDTO.getUserId();
// 人脸更新
JSonObject res = FaceUtil.getClient().updateUser(image, imageType, groupId, userId, options);
FaceResultUtil.isSuccess(res);
logger.info("人脸更新成功 {}", res.toString(2));
}
public static void faceDelete(String userId, String groupId, String faceToken) {
// 传入可选参数调用接口
HashMap options = new HashMap();
// 人脸删除
JSonObject res = FaceUtil.getClient().faceDelete(userId, groupId, faceToken, options);
FaceResultUtil.isSuccess(res);
logger.info("人脸删除成功 {}", res.toString(2));
}
public static FaceUserDTO findUser(String userId, String groupId) {
HashMap options = new HashMap<>();
// 用户信息查询
JSonObject res = FaceUtil.getClient().getUser(userId, groupId, options);
FaceResult result = FaceResultUtil.isSuccess(res);
return JSON.parseObject(result.getData().toJSonString(), FaceUserDTO.class);
}
public static FaceResult faceGetList(String userId, String groupId){
HashMap options = new HashMap();
// 获取用户人脸列表
JSonObject res = FaceUtil.getClient().faceGetlist(userId, groupId, options);
return FaceResultUtil.isSuccess(res);
}
public static FaceResult listUserByGroupId(String groupId) {
HashMap options = new HashMap();
options.put("start", "0");
options.put("length", "50");
// 获取用户列表
JSonObject res = FaceUtil.getClient().getGroupUsers(groupId, options);
return FaceResultUtil.isSuccess(res);
}
public static void deleteUser(String userId, String groupId) {
HashMap options = new HashMap();
// 删除用户
JSonObject res = FaceUtil.getClient().deleteUser(groupId, userId, options);
FaceResultUtil.isSuccess(res);
logger.info("用户删除成功 {}", res.toString(2));
}
public static void addGroup(String groupId) {
HashMap options = new HashMap();
// 创建用户组
JSonObject res = FaceUtil.getClient().groupAdd(groupId, options);
FaceResultUtil.isSuccess(res);
logger.info("创建用户组 {}", res.toString(2));
}
public static void deleteGroup(String groupId){
HashMap options = new HashMap();
// 删除用户组
JSonObject res = FaceUtil.getClient().groupDelete(groupId, options);
FaceResultUtil.isSuccess(res);
logger.info("删除用户组 {}", res.toString(2));
}
public static FaceResult listGroup() {
HashMap options = new HashMap();
options.put("start", "0");
options.put("length", "50");
// 组列表查询
JSonObject res = FaceUtil.getClient().getGroupList(options);
return FaceResultUtil.isSuccess(res);
}
public static FaceResult personVerify(String idCardNumber, String realName, ImageU imageU){
HashMap options = new HashMap();
options.put("quality_control", QualityControlEnum.LOW.name());
options.put("liveness_control", LivenessControlEnum.NONE.name());
// 身份验证
JSonObject res = FaceUtil.getClient().personVerify(imageU.getData(), imageU.getImageTypeEnum().name(), idCardNumber, realName, options);
return FaceResultUtil.isSuccess(res);
}
public static int faceMatchScore(ImageU imageU1, ImageU imageU2){
MatchRequest req1 = new MatchRequest(imageU1.getData(), imageU1.getImageTypeEnum().name());
MatchRequest req2 = new MatchRequest(imageU2.getData(), imageU2.getImageTypeEnum().name());
ArrayList requests = new ArrayList();
requests.add(req1);
requests.add(req2);
JSonObject res = FaceUtil.getClient().match(requests);
FaceResult result = FaceResultUtil.isSuccess(res);
// 对结果进行特殊处理
Integer score = result.getData().getInteger(FaceConstant.SCORE);
return score == null ? 0 : score;
}
public static boolean isfaceMatch(ImageU imageU1, ImageU imageU2, Integer score){
int defaultScore = FaceConstant.MATCH_SCORE;
if (Objects.nonNull(score)){
defaultScore = score;
}
return faceMatchScore(imageU1, imageU2) > defaultScore ? true : false;
}
public static FaceResult faceDetect(ImageU imageU) {
HashMap options = new HashMap();
options.put("face_field", "age");
options.put("max_face_num", "2");
options.put("face_type", "LIVE");
// 人脸检测
JSonObject res = FaceUtil.getClient().detect(imageU.getData(), imageU.getImageTypeEnum().name(), options);
return FaceResultUtil.isSuccess(res);
}
public static FaceResult faceSearch(String groupIds, ImageU imageU) {
HashMap options = new HashMap();
options.put("max_face_num", "1");
options.put("max_user_num", "1");
options.put("quality_control", QualityControlEnum.LOW.name());
options.put("liveness_control", LivenessControlEnum.NONE.name());
// 人脸搜索
JSonObject res = FaceUtil.getClient().search(imageU.getData(), imageU.getImageTypeEnum().name(), groupIds, options);
return FaceResultUtil.isSuccess(res);
}
public static FaceResult faceverify(ImageU imageU) {
FaceVerifyRequest req = new FaceVerifyRequest(imageU.getData(), imageU.getImageTypeEnum().name());
ArrayList list = new ArrayList();
list.add(req);
JSonObject res = FaceUtil.getClient().faceverify(list);
return FaceResultUtil.isSuccess(res);
}
}
3.8、测试
package com.ruoyi.common.utils.face;
import com.alibaba.fastjson.JSON;
import com.example.common.face.FaceManage;
import com.example.common.face.constant.FaceConstant;
import com.example.common.face.constant.ImageTypeEnum;
import com.example.common.face.dto.FaceResult;
import com.example.common.face.dto.FaceUserDTO;
import com.example.common.face.dto.ImageU;
import com.example.common.face.utils.FaceUtil;
import com.example.common.utils.FilesUtil;
import org.apache.commons.io.IOUtils;
import org.junit.Test;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.HashMap;
public class FaceIdentificationTest {
@Test
public void test00() throws Exception{
FaceUserDTO userDTO = new FaceUserDTO<>();
userDTO.setGroupId("group2");
String filePath = "/Users/cxx/Downloads/entryPhoto/";
File[] files = FilesUtil.listFile(filePath);
int j = 0;
for (File file : files) {
int id = 7000 + j;
j++;
userDTO.setUserId(String.valueOf(id));
InputStream is = new FileInputStream(new File(filePath + file.getName()));
byte[] bytes = IOUtils.toByteArray(is);
String data = FaceUtil.encodebase64(bytes);
ImageU imageU = ImageU.builder().data(data).imageTypeEnum(ImageTypeEnum.base64).build();
userDTO.setUser("用户信息 group1 - " + id);
try {
FaceManage.faceRegister(userDTO, imageU);
}catch (Exception e){
System.out.println("注册失败 msg:" + e.getMessage());
continue;
}
}
}
@Test
public void test01() {
FaceUserDTO userDTO = new FaceUserDTO<>();
userDTO.setGroupId("group1");
userDTO.setUserId("6031");
String image = "https://download.2dfire.com/mis/permanent/img2.jpg";
ImageU imageU = ImageU.builder().data(image).imageTypeEnum(ImageTypeEnum.URL).build();
userDTO.setUser("用户信息1");
FaceManage.faceRegister(userDTO, imageU);
}
@Test
public void test02() {
FaceUserDTO userDTO = new FaceUserDTO();
userDTO.setGroupId("group1");
userDTO.setUserId("6031");
String image = "https://download.2dfire.com/mis/permanent/img2.jpg";
ImageU imageU = ImageU.builder().data(image).imageTypeEnum(ImageTypeEnum.URL).build();
userDTO.setUser("用户信息1");
// 人脸更新
FaceManage.faceUpdate(userDTO, imageU);
}
@Test
public void test03() {
String userId = "6030";
String groupId = "group1";
String faceToken = "5a1a8c17c40ea41264e8830017134972";
FaceManage.faceDelete(userId, groupId, faceToken);
}
@Test
public void test04() {
HashMap options = new HashMap<>();
String userId = "6030";
String groupId = "group1";
// 用户信息查询
FaceUserDTO userDTO = FaceManage.findUser(userId, groupId);
System.out.println("用户信息:" + JSON.toJSonString(userDTO));
}
@Test
public void test05() {
String userId = "6030";
String groupId = "group1";
// 获取用户人脸列表
FaceResult result = FaceManage.faceGetList(userId, groupId);
String data = result.getData().getString(FaceConstant.FACE_LIST);
System.out.println("人脸列表"+data);
}
@Test
public void test06() {
String groupId = "group1";
FaceResult result = FaceManage.listUserByGroupId(groupId);
// 获取用户列表
String userIds = result.getData().getString(FaceConstant.USER_ID_LIST);
System.out.println("userIds" + userIds);
}
@Test
public void test07() {
HashMap options = new HashMap();
String groupId = "group1";
String userId = "6031";
// 删除用户
FaceManage.deleteUser(userId, groupId);
}
@Test
public void test08() {
String groupId = "group2";
FaceManage.addGroup(groupId);
}
@Test
public void test09() {
String groupId = "group2";
FaceManage.deleteGroup(groupId);
}
@Test
public void test10() {
FaceResult result = FaceManage.listGroup();
String groupIds = result.getData().getString(FaceConstant.GROUP_ID_LIST);
System.out.println(groupIds);
}
@Test
public void test11() {
String image = "https://download.2dfire.com/mis/permanent/img1.jpg";
ImageU imageU = ImageU.builder().data(image).imageTypeEnum(ImageTypeEnum.URL).build();
String idCardNumber = "235151251";
String name = "陈星星";
FaceManage.personVerify(idCardNumber, name, imageU);
}
@Test
public void test12() {
String image1 = "https://download.2dfire.com/mis/permanent/img1.jpg";
String image2 = "https://download.2dfire.com/mis/permanent/img2.jpg";
ImageU imageU1 = ImageU.builder().data(image1).imageTypeEnum(ImageTypeEnum.URL).build();
ImageU imageU2 = ImageU.builder().data(image2).imageTypeEnum(ImageTypeEnum.URL).build();
boolean match = FaceManage.isfaceMatch(imageU2, imageU1, 80);
int matchScore = FaceManage.faceMatchScore(imageU2, imageU1);
System.out.println("是否匹配:" + match);
System.out.println("匹配等分:" + matchScore);
}
@Test
public void test13() {
String image = "https://download.2dfire.com/mis/permanent/img1.jpg";
ImageU imageU = ImageU.builder().data(image).imageTypeEnum(ImageTypeEnum.URL).build();
FaceResult result = FaceManage.faceDetect(imageU);
String data = result.getData().getString(FaceConstant.FACE_LIST);
System.out.println(data);
}
@Test
public void test14() {
String image = "https://download.2dfire.com/mis/permanent/img1.jpg";
ImageU imageU = ImageU.builder().data(image).imageTypeEnum(ImageTypeEnum.URL).build();
String groupIds = "group1,group2";
FaceResult result = FaceManage.faceSearch(groupIds, imageU);
String users = result.getData().getString(FaceConstant.USER_LIST);
System.out.println(users);
}
@Test
public void test15() {
String image = "https://download.2dfire.com/mis/permanent/img1.jpg";
ImageU imageU = ImageU.builder().data(image).imageTypeEnum(ImageTypeEnum.URL).build();
FaceResult result = FaceManage.faceverify(imageU);
String users = result.getData().toJSonString();
System.out.println(users);
}
}
3.9人脸识别登陆Controller
@PostMapping( "/facelogin")
@ResponseBody
public AjaxResult facelogin(@RequestParam("file") String file,@RequestParam("groupId") String groupId) throws Exception {
MultipartFile multipartFile = base64DecodeMultipartFile.base64Convert(file);//很长
if (multipartFile.isEmpty()) {
throw new BizException("上传文件不能为空");
}
String groupIds = "group1";
String data = FaceUtil.encodebase64(multipartFile.getBytes());
ImageU imageU = ImageU.builder().data(data).imageTypeEnum(ImageTypeEnum.base64).build();
FaceResult result = FaceManage.faceSearch(groupIds, imageU);
String users = result.getData().getString(FaceConstant.USER_LIST);
if (StringUtils.isEmpty(users)){
return AjaxResult.error("用户不存在");
}
JSonArray array = JSONObject.parseArray(users);
JSonObject object = JSONObject.parseObject(array.get(0).toString());
Integer score = object.getInteger(FaceConstant.SCORE);
if (score == null){
return AjaxResult.error("登录失败");
}
if (score >= FaceConstant.MATCH_SCORE){
System.out.println(result.getData().toString());
Long user_id = object.getLong("user_id");
SysUser sysUser = sysUserService.selectUserById(user_id);
AjaxResult ajax = loginService.login(0,sysUser.getUserName());
return ajax;
}
return AjaxResult.error("用户不存在");
}
3.10 枚举,用到的一些辅助类
package com.ruoyi.common.utils.face;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.base64Decoder;
import java.io.*;
import java.util.UUID;
public class base64DecodeMultipartFile implements MultipartFile {
private final byte[] imgContent;
private final String header;
public base64DecodeMultipartFile(byte[] imgContent, String header) {
this.imgContent = imgContent;
this.header = header.split(";")[0];
}
@Override
public String getName() {
return System.currentTimeMillis() + Math.random() + "." + header.split("/")[1];
}
@Override
public String getOriginalFilename() {
return System.currentTimeMillis() + (int) Math.random() * 10000 + "." + header.split("/")[1];
}
@Override
public String getContentType() {
return header.split(":")[1];
}
@Override
public boolean isEmpty() {
return imgContent == null || imgContent.length == 0;
}
@Override
public long getSize() {
return imgContent.length;
}
@Override
public byte[] getBytes() throws IOException {
return imgContent;
}
@Override
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(imgContent);
}
@Override
public void transferTo(File dest) throws IOException, IllegalStateException {
new FileOutputStream(dest).write(imgContent);
}
public static MultipartFile base64Convert(String base64) {
String[] baseStrs = base64.split(",");
base64Decoder decoder = new base64Decoder();
byte[] b = new byte[0];
try {
b = decoder.decodeBuffer(baseStrs[1]);
} catch (IOException e) {
e.printStackTrace();
}
for (int i = 0; i < b.length; ++i) {
if (b[i] < 0) {
b[i] += 256;
}
}
return new base64DecodeMultipartFile(b, baseStrs[0]);
}
}
package com.ruoyi.common.utils.face;
public class BizException extends RuntimeException {
private static final long serialVersionUID = 1L;
private String msg;
private int code = 500;
public BizException(String msg) {
super(msg);
this.msg = msg;
}
public BizException(String msg, Throwable e) {
super(msg, e);
this.msg = msg;
}
public BizException(String msg, int code) {
super(msg);
this.msg = msg;
this.code = code;
}
public BizException(String msg, int code, Throwable e) {
super(msg, e);
this.msg = msg;
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
}
package com.ruoyi.common.utils.face.constant;
public enum ActionTypeEnum {
APPEND("重复注册"),
REPLACE("会用新图替换");
ActionTypeEnum(String desc){
this.desc = desc;
}
private String desc;
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
package com.ruoyi.common.utils.face.constant;
public enum ErrorEnum {
ERROR_ENUM_1(1, "Unknown error", "服务器内部错误,请再次请求"),
ERROR_ENUM_13(13, "Get service token failed", "获取token失败"),
ERROR_ENUM_222202(222202, "pic not has face", "图片中没有人脸"),
ERROR_ENUM_222203(222203, "image check fail", "无法解析人脸"),
ERROR_ENUM_222207(222207, "match user is not found", "未找到匹配的用户"),
ERROR_ENUM_222209(222209, "face token not exist", "face token不存在"),
ERROR_ENUM_222301(222301, "get face fail", "获取人脸图片失败"),
ERROR_ENUM_223102(223102, "user is already exist", "该用户已存在"),
ERROR_ENUM_223106(223106, "face is not exist", "该人脸不存在"),
ERROR_ENUM_223113(223113, "face is covered", "人脸模糊"),
ERROR_ENUM_223114(223114, "face is fuzzy", "人脸模糊"),
ERROR_ENUM_223115(223115, "face light is not good", "人脸光照不好"),
ERROR_ENUM_223116(223116, "incomplete face", "人脸不完整");
ErrorEnum(int errorCode, String desc, String cnDesc){
this.errorCode = errorCode;
this.desc = desc;
this.cnDesc = cnDesc;
}
private int errorCode;
private String desc;
private String cnDesc;
public static ErrorEnum getInstance(int errorCode){
for (ErrorEnum value : ErrorEnum.values()) {
if (value.errorCode == errorCode){
return value;
}
}
return null;
}
public int getErrorCode() {
return errorCode;
}
public void setErrorCode(int errorCode) {
this.errorCode = errorCode;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public String getCnDesc() {
return cnDesc;
}
public void setCnDesc(String cnDesc) {
this.cnDesc = cnDesc;
}
}
package com.ruoyi.common.utils.face.constant;
public class FaceConstant {
public static final String DEFAULT_GROUP_ID = "60030";
public static final int MATCH_SCORE = 80;
public static final String RESULT = "result";
public static final String LOG_ID = "log_id";
public static final String ERROR_MSG = "error_msg";
public static final String CACHED = "cached";
public static final String ERROR_CODE = "error_code";
public static final String TIMESTAMP = "timestamp";
public static final String SCORE = "score";
public static final String FACE_LIST = "face_list";
public static final String FACE_TOKEN = "face_token";
public static final String USER_ID_LIST = "user_id_list";
public static final String GROUP_ID_LIST = "group_id_list";
public static final String USER_LIST = "user_list";
}
package com.ruoyi.common.utils.face.constant;
public enum ImageTypeEnum {
base64("base64", 2),
URL("URL", 0),
FACE_TOKEN("FACE_TOKEN", 0);
ImageTypeEnum(String key, int size){
this.key = key;
this.size = size;
}
private String key;
private int size;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
}
package com.ruoyi.common.utils.face.constant;
public enum LivenessControlEnum {
NONE("不进行控制"),
LOW("较低的活体要求(高通过率 低攻击拒绝率)"),
NORMAL("一般的活体要求(平衡的攻击拒绝率, 通过率)"),
HIGH("较高的活体要求");
LivenessControlEnum(String desc){
this.desc = desc;
}
private String desc;
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
package com.ruoyi.common.utils.face.constant;
public enum QualityControlEnum {
NONE("不进行控制"),
LOW("较低的质量要求"),
NORMAL("一般的质量要求"),
HIGH("较高的质量要求");
QualityControlEnum(String desc){
this.desc = desc;
}
private String desc;
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
4、前端实现
管理系统
记住密码
登 录
登 录 中...
立即注册
Copyright © 2018-2021 nexauto All Rights Reserved.
.login {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
background-image: url("../assets/images/login-background.jpg");
background-size: cover;
}
.title {
margin: 0px auto 30px auto;
text-align: center;
color: #707070;
}
.login-form {
border-radius: 6px;
background: #ffffff;
width: 400px;
padding: 25px 25px 5px 25px;
.el-input {
height: 38px;
input {
height: 38px;
}
}
.input-icon {
height: 39px;
width: 14px;
margin-left: 2px;
}
}
.login-tip {
font-size: 13px;
text-align: center;
color: #bfbfbf;
}
.login-code {
width: 33%;
height: 38px;
float: right;
img {
cursor: pointer;
vertical-align: middle;
}
}
.el-login-footer {
height: 40px;
line-height: 40px;
position: fixed;
bottom: 0;
width: 100%;
text-align: center;
color: #fff;
font-family: Arial;
font-size: 12px;
letter-spacing: 1px;
}
.login-code-img {
height: 38px;
}
.testTrackingWrapper {
height: 300px;
width: 200px;
position: relative;
}
video,
canvas {
position: absolute;
left: 0;
right: 0;
top: 0;
}
.buttonWrapper {
position: absolute;
left: 0;
right: 0;
bottom: 7%;
}
写的不好的地方,可以纠正,如出问题,鄙人可以交流学习:
package com.ruoyi.common.utils.face;
import com.alibaba.fastjson.JSON;
import com.example.common.face.FaceManage;
import com.example.common.face.constant.FaceConstant;
import com.example.common.face.constant.ImageTypeEnum;
import com.example.common.face.dto.FaceResult;
import com.example.common.face.dto.FaceUserDTO;
import com.example.common.face.dto.ImageU;
import com.example.common.face.utils.FaceUtil;
import com.example.common.utils.FilesUtil;
import org.apache.commons.io.IOUtils;
import org.junit.Test;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.HashMap;
public class FaceIdentificationTest {
@Test
public void test00() throws Exception{
FaceUserDTO userDTO = new FaceUserDTO<>();
userDTO.setGroupId("group2");
String filePath = "/Users/cxx/Downloads/entryPhoto/";
File[] files = FilesUtil.listFile(filePath);
int j = 0;
for (File file : files) {
int id = 7000 + j;
j++;
userDTO.setUserId(String.valueOf(id));
InputStream is = new FileInputStream(new File(filePath + file.getName()));
byte[] bytes = IOUtils.toByteArray(is);
String data = FaceUtil.encodebase64(bytes);
ImageU imageU = ImageU.builder().data(data).imageTypeEnum(ImageTypeEnum.base64).build();
userDTO.setUser("用户信息 group1 - " + id);
try {
FaceManage.faceRegister(userDTO, imageU);
}catch (Exception e){
System.out.println("注册失败 msg:" + e.getMessage());
continue;
}
}
}
@Test
public void test01() {
FaceUserDTO userDTO = new FaceUserDTO<>();
userDTO.setGroupId("group1");
userDTO.setUserId("6031");
String image = "https://download.2dfire.com/mis/permanent/img2.jpg";
ImageU imageU = ImageU.builder().data(image).imageTypeEnum(ImageTypeEnum.URL).build();
userDTO.setUser("用户信息1");
FaceManage.faceRegister(userDTO, imageU);
}
@Test
public void test02() {
FaceUserDTO userDTO = new FaceUserDTO();
userDTO.setGroupId("group1");
userDTO.setUserId("6031");
String image = "https://download.2dfire.com/mis/permanent/img2.jpg";
ImageU imageU = ImageU.builder().data(image).imageTypeEnum(ImageTypeEnum.URL).build();
userDTO.setUser("用户信息1");
// 人脸更新
FaceManage.faceUpdate(userDTO, imageU);
}
@Test
public void test03() {
String userId = "6030";
String groupId = "group1";
String faceToken = "5a1a8c17c40ea41264e8830017134972";
FaceManage.faceDelete(userId, groupId, faceToken);
}
@Test
public void test04() {
HashMap options = new HashMap<>();
String userId = "6030";
String groupId = "group1";
// 用户信息查询
FaceUserDTO userDTO = FaceManage.findUser(userId, groupId);
System.out.println("用户信息:" + JSON.toJSonString(userDTO));
}
@Test
public void test05() {
String userId = "6030";
String groupId = "group1";
// 获取用户人脸列表
FaceResult result = FaceManage.faceGetList(userId, groupId);
String data = result.getData().getString(FaceConstant.FACE_LIST);
System.out.println("人脸列表"+data);
}
@Test
public void test06() {
String groupId = "group1";
FaceResult result = FaceManage.listUserByGroupId(groupId);
// 获取用户列表
String userIds = result.getData().getString(FaceConstant.USER_ID_LIST);
System.out.println("userIds" + userIds);
}
@Test
public void test07() {
HashMap options = new HashMap();
String groupId = "group1";
String userId = "6031";
// 删除用户
FaceManage.deleteUser(userId, groupId);
}
@Test
public void test08() {
String groupId = "group2";
FaceManage.addGroup(groupId);
}
@Test
public void test09() {
String groupId = "group2";
FaceManage.deleteGroup(groupId);
}
@Test
public void test10() {
FaceResult result = FaceManage.listGroup();
String groupIds = result.getData().getString(FaceConstant.GROUP_ID_LIST);
System.out.println(groupIds);
}
@Test
public void test11() {
String image = "https://download.2dfire.com/mis/permanent/img1.jpg";
ImageU imageU = ImageU.builder().data(image).imageTypeEnum(ImageTypeEnum.URL).build();
String idCardNumber = "235151251";
String name = "陈星星";
FaceManage.personVerify(idCardNumber, name, imageU);
}
@Test
public void test12() {
String image1 = "https://download.2dfire.com/mis/permanent/img1.jpg";
String image2 = "https://download.2dfire.com/mis/permanent/img2.jpg";
ImageU imageU1 = ImageU.builder().data(image1).imageTypeEnum(ImageTypeEnum.URL).build();
ImageU imageU2 = ImageU.builder().data(image2).imageTypeEnum(ImageTypeEnum.URL).build();
boolean match = FaceManage.isfaceMatch(imageU2, imageU1, 80);
int matchScore = FaceManage.faceMatchScore(imageU2, imageU1);
System.out.println("是否匹配:" + match);
System.out.println("匹配等分:" + matchScore);
}
@Test
public void test13() {
String image = "https://download.2dfire.com/mis/permanent/img1.jpg";
ImageU imageU = ImageU.builder().data(image).imageTypeEnum(ImageTypeEnum.URL).build();
FaceResult result = FaceManage.faceDetect(imageU);
String data = result.getData().getString(FaceConstant.FACE_LIST);
System.out.println(data);
}
@Test
public void test14() {
String image = "https://download.2dfire.com/mis/permanent/img1.jpg";
ImageU imageU = ImageU.builder().data(image).imageTypeEnum(ImageTypeEnum.URL).build();
String groupIds = "group1,group2";
FaceResult result = FaceManage.faceSearch(groupIds, imageU);
String users = result.getData().getString(FaceConstant.USER_LIST);
System.out.println(users);
}
@Test
public void test15() {
String image = "https://download.2dfire.com/mis/permanent/img1.jpg";
ImageU imageU = ImageU.builder().data(image).imageTypeEnum(ImageTypeEnum.URL).build();
FaceResult result = FaceManage.faceverify(imageU);
String users = result.getData().toJSonString();
System.out.println(users);
}
}



