diff --git a/login/pom.xml b/login/pom.xml
index 57cc949..18bd519 100644
--- a/login/pom.xml
+++ b/login/pom.xml
@@ -60,6 +60,32 @@
7.0.2
+
+ com.arcsoft.face
+ arcsoft-sdk-face
+ 4.1.1.0
+
+
+
+
+ org.apache.commons
+ commons-pool2
+ 2.12.0
+
+
+
+
+ org.bytedeco
+ javacv-platform
+ 1.4.4
+
+
+
+ com.alibaba
+ druid-spring-boot-starter
+ 1.1.10
+
+
diff --git a/login/src/main/java/com/guwan/config/GlobalValue.java b/login/src/main/java/com/guwan/config/GlobalValue.java
index 7f7fab2..ffbe08c 100644
--- a/login/src/main/java/com/guwan/config/GlobalValue.java
+++ b/login/src/main/java/com/guwan/config/GlobalValue.java
@@ -58,4 +58,7 @@ public class GlobalValue {
private String minioBucketName;
+ @Value("${global.file_path.static-locations}")
+ private String staticLocations;
+
}
diff --git a/login/src/main/java/com/guwan/config/MinioConfig.java b/login/src/main/java/com/guwan/config/MinioConfig.java
index 472b61e..fcb3de2 100644
--- a/login/src/main/java/com/guwan/config/MinioConfig.java
+++ b/login/src/main/java/com/guwan/config/MinioConfig.java
@@ -23,7 +23,7 @@ public class MinioConfig {
}
@Bean("minioClient")
public MinioClient minioClient(){
- MinioClient minioClient=null;
+ MinioClient minioClient = null;
try {
minioClient = new MinioClient(globalValue.getMinioEndpoint(),
// globalValue.getMinioPort(),
diff --git a/login/src/main/java/com/guwan/controller/login/FaceController.java b/login/src/main/java/com/guwan/controller/login/FaceController.java
index a35dd9c..a905ab6 100644
--- a/login/src/main/java/com/guwan/controller/login/FaceController.java
+++ b/login/src/main/java/com/guwan/controller/login/FaceController.java
@@ -1,81 +1,89 @@
package com.guwan.controller.login;
+import cn.hutool.core.collection.CollectionUtil;
+import com.arcsoft.face.FaceInfo;
+import com.arcsoft.face.enums.ExtractType;
+import com.arcsoft.face.toolkit.ImageFactory;
+import com.arcsoft.face.toolkit.ImageInfo;
+import com.guwan.config.GlobalValue;
import com.guwan.config.MinioConfig;
+import com.guwan.face.dto.FaceRecognitionResDTO;
+import com.guwan.face.service.FaceEngineService;
import com.guwan.util.UUIDUtil;
import io.minio.MinioClient;
-import io.minio.PutObjectOptions;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
+import java.io.ByteArrayOutputStream;
import java.io.InputStream;
-import java.util.regex.Pattern;
+import java.util.Base64;
+import java.util.List;
@RestController
+@Slf4j
public class FaceController {
@Autowired
private MinioConfig minioConfig;
@Autowired
private MinioClient minioClient;
+ @Autowired
+ private GlobalValue globalValue;
+ @Autowired
+ private FaceEngineService faceEngineService;
@GetMapping("/11")
- public String test() {
+ public Integer test() {
try {
- // 调用statObject()来判断对象是否存在。
- // 如果不存在, statObject()抛出异常,
- // 否则则代表对象存在。
- minioClient.statObject(minioConfig.getBucketName(), "tempOrgImageFile");
+ String tempOrgImageFile = "photo/t_1f952219ae6848a48fbf282d7d464623.jpg";
+ // 调用statObject()来判断对象是否存在。如果不存在, statObject()抛出异常, 否则则代表对象存在。
+ minioClient.statObject(minioConfig.getBucketName(), tempOrgImageFile);
//判断人脸照片是否合格
- //1.保存到本地
- InputStream tempInputStream = minioClient.getObject(minioConfig.getBucketName(), tempOrgImageFile);
- String tempPath = globalValue.getStaticLocations() + "/";//+globalValue.getTempDir()+"/";
- String tempOrgFilePath = tempPath + tempOrgImageFile;
- int index;
- byte[] bytes = new byte[1024];
- File outFile = new File(tempOrgFilePath);
- FileOutputStream downloadFile = new FileOutputStream(outFile);
- while ((index = tempInputStream.read(bytes)) != -1) {
- downloadFile.write(bytes, 0, index);
- downloadFile.flush();
+ //1
+ InputStream tempInputStream = minioClient.getObject(minioConfig.getBucketName(),
+ tempOrgImageFile);
+ //----------------算法检测----------------------------------------------
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ byte[] buffer = new byte[1024];
+ int length;
+ while ((length = tempInputStream.read(buffer)) != -1) {
+ outputStream.write(buffer, 0, length);
}
- downloadFile.close();
+ byte[] bytes = outputStream.toByteArray();
+ outputStream.close();
tempInputStream.close();
- //2.测试上传的文件
- String tempFaceFileName = UUIDUtil.uuid() + ".jpg";
- String tempFaceFilePath = tempPath + tempFaceFileName;
-
- String osName = System.getProperty("os.name");//获取指定键(即os.name)的系统属性,如:Windows 7。
-// if (Pattern.matches("Windows.*", osName)) {
- if (!Pattern.matches("Windows.*", osName)) {
- int res = PicSDK.getFace(tempOrgFilePath, tempFaceFilePath);
- if (res != 0) {
+ //-------------------------------------------------------------------------
+ ImageInfo rgbData = ImageFactory.getRGBData(bytes);
+ List faceInfoList = faceEngineService.detectFaces(rgbData);
+ if (CollectionUtil.isNotEmpty(faceInfoList)) {
+ FaceInfo faceInfo = faceInfoList.get(0);
+ FaceRecognitionResDTO faceRecognitionResDTO = new FaceRecognitionResDTO();
+ faceRecognitionResDTO.setRect(faceInfo.getRect());
+ byte[] featureBytes = faceEngineService.extractFaceFeature(rgbData, faceInfo, ExtractType.REGISTER);
+ if (featureBytes != null) {
+// UserRamCache.UserInfo userInfo = new UserCompareInfo();
+// userInfo.setFaceId(faceAddReqDTO.getName());
+// userInfo.setName(faceAddReqDTO.getName());
+// userInfo.setFaceFeature(feature);
+// //这边注册到内存缓存中,也可以根据业务,注册到数据库中
+// UserRamCache.addUser(userInfo);
+ //entity.setFeature(Base64.getEncoder().encodeToString(featureBytes));
+ System.out.println(Base64.getEncoder().encodeToString(featureBytes));
+ }else{
log.error("图片不合格,未检测到人脸");
-// return 2;
+ return 2;
}
- //保存底片文件到oss
- InputStream inputStream = new FileInputStream(tempFaceFilePath);
- PutObjectOptions putObjectOptions = new PutObjectOptions(inputStream.available(), -1);
- putObjectOptions.setContentType("image/jpeg");
- minioClient.putObject(
- minioConfig.getBucketName(), faceImageFileName, inputStream, putObjectOptions);
- inputStream.close();
- } else {
- minioClient.copyObject(
- minioConfig.getBucketName(),
- faceImageFileName,
- null,
- null,
- minioConfig.getBucketName(),
- tempOrgImageFile,
- null,
- null);
+ }else{
+ log.error("图片不合格,未检测到人脸");
+ return 2;
}
+
+
+ String orgImageFileName = "face/"+ "o_" + UUIDUtil.uuid() + ".jpg";
//拷贝临时文件正式文件
minioClient.copyObject(
minioConfig.getBucketName(),
@@ -87,17 +95,18 @@ public class FaceController {
null,
null);
- entity.setOrgImage(orgImageFileName);
- entity.setFaceImage(faceImageFileName);
+
+
//删除临时文件oss
minioClient.removeObject(minioConfig.getBucketName(), tempOrgImageFile);
//删除本地临时文件
- new File(tempFaceFilePath).delete();
+// new File(tempFaceFilePath).delete();
} catch (Exception e) {
- entity.setOrgImage("");
- entity.setFaceImage("");
+
e.printStackTrace();
+ return 10;
}
+ return 1;
}
}
diff --git a/login/src/main/java/com/guwan/controller/login/UploadController.java b/login/src/main/java/com/guwan/controller/login/UploadController.java
index 6105ff8..dfa9f4c 100644
--- a/login/src/main/java/com/guwan/controller/login/UploadController.java
+++ b/login/src/main/java/com/guwan/controller/login/UploadController.java
@@ -1,7 +1,10 @@
package com.guwan.controller.login;
import com.guwan.common.R;
+import com.guwan.config.GlobalValue;
import com.guwan.config.MinioConfig;
+import com.guwan.util.IPUtils;
+import com.guwan.util.PathUtil;
import io.minio.MinioClient;
import io.minio.PutObjectOptions;
import lombok.RequiredArgsConstructor;
@@ -11,6 +14,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
+import java.io.File;
+import java.io.IOException;
import java.io.InputStream;
import java.util.UUID;
@@ -23,6 +28,7 @@ public class UploadController {
private final MinioConfig minioConfig;
private final MinioClient minioClient;
+ private final GlobalValue globalValue;
@PostMapping("/GBUpload")
public R gbUpload(MultipartFile file) {
@@ -75,4 +81,33 @@ public class UploadController {
}
+
+
+ @PostMapping("/demo111")
+ public void uploadFile(MultipartFile file) {
+
+
+ String path = PathUtil.path("");
+
+ try {
+ // 确保临时路径存在
+ File tempDir = new File(path);
+ if (!tempDir.exists()) {
+ tempDir.mkdirs(); // 创建目录
+ }
+
+ // 构建文件的完整路径
+ File serverFile = new File(path + File.separator + file.getOriginalFilename());
+
+ // 将上传的文件保存到服务器
+ file.transferTo(serverFile);
+
+ System.out.println("文件上传成功,保存路径为:" + serverFile.getAbsolutePath());
+ } catch (IOException e) {
+ e.printStackTrace();
+ System.out.println("文件上传失败:" + e.getMessage());
+ }
+ }
+
+
}
diff --git a/login/src/main/java/com/guwan/controller/login/UserController.java b/login/src/main/java/com/guwan/controller/login/UserController.java
index 28a8fb6..f43af0c 100644
--- a/login/src/main/java/com/guwan/controller/login/UserController.java
+++ b/login/src/main/java/com/guwan/controller/login/UserController.java
@@ -1,14 +1,22 @@
package com.guwan.controller.login;
+import com.guwan.config.GlobalValue;
import com.guwan.service.TokenService;
import com.guwan.util.IPUtils;
+import com.guwan.util.PathUtil;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.annotation.security.PermitAll;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
@RestController
@RequestMapping("/user")
@@ -16,11 +24,20 @@ public class UserController {
@Autowired
private TokenService tokenService;
+ @Autowired
+ private GlobalValue globalValue;
@GetMapping("/login")
@PermitAll
@Operation(summary = "使用账号密码登录")
public String login(String userId, HttpServletRequest request) {
+
+
+ String test = PathUtil.path();
+
+
+ System.out.println("tempPath = " + test);
+
String ip = IPUtils.getIpAddr(request);
System.out.println("ip111 = " + ip);
return tokenService.createToken(userId, ip);
@@ -46,4 +63,33 @@ public class UserController {
}
return "getInfo";
}
+
+
+ @PostMapping("/demo111")
+ public void uploadFile(MultipartFile file) {
+
+
+ String tempPath = System.getProperty("user.dir") + globalValue.getStaticLocations();
+
+ try {
+ // 确保临时路径存在
+ File tempDir = new File(tempPath);
+ if (!tempDir.exists()) {
+ tempDir.mkdirs(); // 创建目录
+ }
+
+ // 构建文件的完整路径
+ File serverFile = new File(tempPath + File.separator + file.getOriginalFilename());
+
+ // 将上传的文件保存到服务器
+ file.transferTo(serverFile);
+
+ System.out.println("文件上传成功,保存路径为:" + serverFile.getAbsolutePath());
+ } catch (IOException e) {
+ e.printStackTrace();
+ System.out.println("文件上传失败:" + e.getMessage());
+ }
+ }
+
+
}
diff --git a/login/src/main/java/com/guwan/face/FaceEngineAutoRun.java b/login/src/main/java/com/guwan/face/FaceEngineAutoRun.java
new file mode 100644
index 0000000..cf62c1f
--- /dev/null
+++ b/login/src/main/java/com/guwan/face/FaceEngineAutoRun.java
@@ -0,0 +1,120 @@
+/*
+package com.guwan.face;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.guwan.config.GlobalValue;
+import com.guwan.face.entity.UserCompareInfo;
+import com.guwan.face.service.FaceEngineService;
+import com.guwan.face.util.Base64Util;
+import com.guwan.face.util.UserInfo;
+import com.guwan.face.util.UserRamGroup;
+import lombok.extern.slf4j.Slf4j;
+
+import net.shapelight.modules.ten.entity.TenCellEntity;
+import net.shapelight.modules.ten.entity.TenPersonEntity;
+import net.shapelight.modules.ten.service.TenCellService;
+import net.shapelight.modules.ten.service.TenPersonService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+@Component
+@Order(1)
+@Slf4j
+public class FaceEngineAutoRun implements ApplicationRunner {
+ @Autowired
+ private FaceEngineService faceEngineService;
+ @Autowired
+ private TenPersonService tenPersonService;
+ @Autowired
+ private TenCellService tenCellService;
+ @Autowired
+ private GlobalValue globalValue;
+
+ @Override
+ public void run(ApplicationArguments args) throws Exception {
+ // 任务初始化
+ log.debug("服务启动。。。。。初始化人脸库");
+// Map fileMap = Maps.newHashMap();
+// fileMap.put("zhao1", "赵丽颖");
+// fileMap.put("yang1", "杨紫");
+// fileMap.put("baixue", "白雪");
+// fileMap.put("chenchuang", "陈创");
+// for (String f : fileMap.keySet()) {
+// ClassPathResource resource = new ClassPathResource("static/images/" + f + ".jpg");
+// InputStream inputStream = resource.getInputStream();
+// ImageInfo rgbData = ImageFactory.getRGBData(inputStream);
+// List faceInfoList = faceEngineService.detectFaces(rgbData);
+// if (CollectionUtil.isNotEmpty(faceInfoList)) {
+// byte[] feature = faceEngineService.extractFaceFeature(rgbData, faceInfoList.get(0), ExtractType.REGISTER);
+// UserRamCache.UserInfo userInfo = new UserCompareInfo();
+// userInfo.setFaceId(f);
+// userInfo.setName(fileMap.get(f));
+// userInfo.setFaceFeature(feature);
+// //这边注册到内存缓存中,也可以根据业务,注册到数据库中
+// UserRamCache.addUser(userInfo);
+// }
+// }
+
+// int count = tenPersonService.findCount();
+// int pageSize = 1000;
+// int page = count/pageSize;
+// if(count%1000!=0){
+// page = page+1;
+// }
+// int faceCount = 0;
+// for (int i = 0; i < page; i++) {
+// int start = i*1000;
+// List listPage = tenPersonService.listPage(start,1000);
+// for(TenPersonEntity personEntity: listPage){
+// if(personEntity.getFeature()!=null && personEntity.getFeature().length()>0){
+// UserRamCache.UserInfo userInfo = new UserCompareInfo();
+// userInfo.setFaceId(personEntity.getPersonId()+"");
+// userInfo.setName(personEntity.getName());
+// userInfo.setFaceFeature(Base64Util.base64ToBytes(personEntity.getFeature()));
+// //这边注册到内存缓存中
+// UserRamCache.addUser(userInfo);
+// faceCount++;
+// }
+// }
+// }
+
+
+ List cellList = tenCellService.list(new QueryWrapper()
+ .eq("tenant_id",globalValue.getTenantId())
+ .eq("delete_flag",0));
+ for(TenCellEntity cellEntity: cellList){
+ String cellId = cellEntity.getCellId()+"";
+ UserRamGroup.addCell(cellId);
+ UserRamGroup.addOrgId(cellEntity.getOrgId(),cellId);
+ int count = tenPersonService.findCount(cellId);
+ int pageSize = 1000;
+ int page = count/pageSize;
+ if(count%1000!=0){
+ page = page+1;
+ }
+ int faceCount = 0;
+ for (int i = 0; i < page; i++) {
+ int start = i*1000;
+ List listPage = tenPersonService.listPage(start,1000, cellId);
+ for(TenPersonEntity personEntity: listPage){
+ if(personEntity.getFeature()!=null && personEntity.getFeature().length()>0){
+ UserInfo userInfo = new UserCompareInfo();
+ userInfo.setFaceId(personEntity.getPersonId()+"");
+ userInfo.setName(personEntity.getName());
+ userInfo.setFaceFeature(Base64Util.base64ToBytes(personEntity.getFeature()));
+ //这边注册到内存缓存中
+ UserRamGroup.addUser(userInfo,cellId);
+ faceCount++;
+ }
+ }
+ }
+ log.debug(cellEntity.getName()+":初始化人脸库完成,共 "+faceCount+" 人");
+ }
+ }
+}
+*/
diff --git a/login/src/main/java/com/guwan/face/config/ArcFaceAutoConfiguration.java b/login/src/main/java/com/guwan/face/config/ArcFaceAutoConfiguration.java
new file mode 100644
index 0000000..6f4699b
--- /dev/null
+++ b/login/src/main/java/com/guwan/face/config/ArcFaceAutoConfiguration.java
@@ -0,0 +1,133 @@
+package com.guwan.face.config;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.io.ClassPathResource;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.LinkedList;
+import java.util.List;
+
+@Slf4j
+@Configuration
+public class ArcFaceAutoConfiguration implements InitializingBean, DisposableBean {
+
+
+ private static final String PLATFORM;
+
+ private static final String USER_HOME;
+
+ public static String CACHE_LIB_FOLDER;
+
+ @Value("${config.arcface-sdk.version}")
+ public String ARC_FACE_VERSION;
+
+ static {
+ String jvmName = System.getProperty("java.vm.name", "").toLowerCase();
+ String osName = System.getProperty("os.name", "").toLowerCase();
+ String osArch = System.getProperty("os.arch", "").toLowerCase();
+ String abiType = System.getProperty("sun.arch.abi", "").toLowerCase();
+ String libPath = System.getProperty("sun.boot.library.path", "").toLowerCase();
+ USER_HOME = System.getProperty("user.home");
+ if (jvmName.startsWith("dalvik") && osName.startsWith("linux")) {
+ osName = "android";
+ } else if (jvmName.startsWith("robovm") && osName.startsWith("darwin")) {
+ osName = "ios";
+ osArch = "arm";
+ } else if (osName.startsWith("mac os x") || osName.startsWith("darwin")) {
+ osName = "macosx";
+ } else {
+ int spaceIndex = osName.indexOf(' ');
+ if (spaceIndex > 0) {
+ osName = osName.substring(0, spaceIndex);
+ }
+ }
+ if (osArch.equals("i386") || osArch.equals("i486") || osArch.equals("i586") || osArch.equals("i686")) {
+ osArch = "x86";
+ } else if (osArch.equals("amd64") || osArch.equals("x86-64") || osArch.equals("x64")) {
+ osArch = "x86_64";
+ } else if (osArch.startsWith("aarch64") || osArch.startsWith("armv8") || osArch.startsWith("arm64")) {
+ osArch = "arm64";
+ } else if ((osArch.startsWith("arm")) && ((abiType.equals("gnueabihf")) || (libPath.contains("openjdk-armhf")))) {
+ osArch = "armhf";
+ } else if (osArch.startsWith("arm")) {
+ osArch = "arm";
+ }
+ PLATFORM = osName + "-" + osArch;
+
+ }
+
+
+ @Override
+ public void afterPropertiesSet() throws IOException {
+ CACHE_LIB_FOLDER = USER_HOME + "/.arcface/cache/" + ARC_FACE_VERSION + "/" + PLATFORM + "/";
+ loadLibrary();
+ }
+
+ public void loadLibrary() throws IOException {
+ String baseFolder = "";
+ String suffix = ".dll";
+ if ("windows-x86_64".equals(PLATFORM)) {
+ baseFolder = "WIN64";
+ } else if ("windows-x86".equals(PLATFORM)) {
+ baseFolder = "WIN32";
+ } else if ("linux-x86_64".equals(PLATFORM)) {
+ baseFolder = "LINUX64";
+ suffix = ".so";
+ }
+
+ if ("".equals(baseFolder)) {
+ throw new RuntimeException("ArcFace不支持该操作系统");
+ }
+
+
+ File file = new File(CACHE_LIB_FOLDER);
+ if (!file.exists()) {
+ file.mkdirs();
+ }
+
+ List libList = new LinkedList<>();
+ libList.add("libarcsoft_face");
+ libList.add("libarcsoft_face_engine");
+ libList.add("libarcsoft_face_engine_jni");
+
+ for (String lib : libList) {
+ ClassPathResource resource = new ClassPathResource("libs/" + ARC_FACE_VERSION + "/" + baseFolder + "/" + lib + suffix);
+ InputStream inputStream = resource.getInputStream();
+ int faceLength = inputStream.available();
+ File facePath = new File(CACHE_LIB_FOLDER + lib + suffix);
+ if (facePath.exists()) {
+ if (facePath.length() == faceLength) {
+ continue;
+ }
+ facePath.delete();
+ }
+ writeToLocal(CACHE_LIB_FOLDER + lib + suffix, inputStream);
+ }
+ }
+
+ private void writeToLocal(String destination, InputStream input)
+ throws IOException {
+ int index;
+ byte[] bytes = new byte[1024 * 100];
+ FileOutputStream fileOutputStream = new FileOutputStream(destination);
+ while ((index = input.read(bytes)) != -1) {
+ fileOutputStream.write(bytes, 0, index);
+ }
+ fileOutputStream.flush();
+ fileOutputStream.close();
+ input.close();
+ }
+
+
+ @Override
+ public void destroy() throws Exception {
+ }
+
+}
diff --git a/login/src/main/java/com/guwan/face/dto/CompareFacesReqDTO.java b/login/src/main/java/com/guwan/face/dto/CompareFacesReqDTO.java
new file mode 100644
index 0000000..0fc1500
--- /dev/null
+++ b/login/src/main/java/com/guwan/face/dto/CompareFacesReqDTO.java
@@ -0,0 +1,14 @@
+package com.guwan.face.dto;
+
+import lombok.Data;
+
+/**
+ * @author shentao
+ * @desc
+ * @date 2022/3/30
+ */
+@Data
+public class CompareFacesReqDTO {
+ private String image1;
+ private String image2;
+}
diff --git a/login/src/main/java/com/guwan/face/dto/FaceAddReqDTO.java b/login/src/main/java/com/guwan/face/dto/FaceAddReqDTO.java
new file mode 100644
index 0000000..fcadf6c
--- /dev/null
+++ b/login/src/main/java/com/guwan/face/dto/FaceAddReqDTO.java
@@ -0,0 +1,12 @@
+package com.guwan.face.dto;
+
+import lombok.Data;
+
+@Data
+public class FaceAddReqDTO {
+
+ private String name;
+
+ private String image;
+
+}
diff --git a/login/src/main/java/com/guwan/face/dto/FaceDetectReqDTO.java b/login/src/main/java/com/guwan/face/dto/FaceDetectReqDTO.java
new file mode 100644
index 0000000..c542929
--- /dev/null
+++ b/login/src/main/java/com/guwan/face/dto/FaceDetectReqDTO.java
@@ -0,0 +1,10 @@
+package com.guwan.face.dto;
+
+import lombok.Data;
+
+@Data
+public class FaceDetectReqDTO {
+
+ private String image;
+
+}
diff --git a/login/src/main/java/com/guwan/face/dto/FaceDetectResDTO.java b/login/src/main/java/com/guwan/face/dto/FaceDetectResDTO.java
new file mode 100644
index 0000000..1ad0583
--- /dev/null
+++ b/login/src/main/java/com/guwan/face/dto/FaceDetectResDTO.java
@@ -0,0 +1,14 @@
+package com.guwan.face.dto;
+
+import com.arcsoft.face.Rect;
+import lombok.Data;
+
+@Data
+public class FaceDetectResDTO {
+ private Rect rect;
+ private int orient;
+ private int faceId = -1;
+ private int age = -1;
+ private int gender = -1;
+ private int liveness = -1;
+}
diff --git a/login/src/main/java/com/guwan/face/dto/FaceRecognitionReqDTO.java b/login/src/main/java/com/guwan/face/dto/FaceRecognitionReqDTO.java
new file mode 100644
index 0000000..342076c
--- /dev/null
+++ b/login/src/main/java/com/guwan/face/dto/FaceRecognitionReqDTO.java
@@ -0,0 +1,10 @@
+package com.guwan.face.dto;
+
+import lombok.Data;
+
+@Data
+public class FaceRecognitionReqDTO {
+
+ private String image;
+
+}
diff --git a/login/src/main/java/com/guwan/face/dto/FaceRecognitionResDTO.java b/login/src/main/java/com/guwan/face/dto/FaceRecognitionResDTO.java
new file mode 100644
index 0000000..0cea030
--- /dev/null
+++ b/login/src/main/java/com/guwan/face/dto/FaceRecognitionResDTO.java
@@ -0,0 +1,15 @@
+package com.guwan.face.dto;
+
+
+import com.arcsoft.face.Rect;
+import lombok.Data;
+
+@Data
+public class FaceRecognitionResDTO {
+
+ private Rect rect;
+ private String personId;
+ private String name;
+ private float similar;
+
+}
diff --git a/login/src/main/java/com/guwan/face/dto/FaceVideoVo.java b/login/src/main/java/com/guwan/face/dto/FaceVideoVo.java
new file mode 100644
index 0000000..e1930de
--- /dev/null
+++ b/login/src/main/java/com/guwan/face/dto/FaceVideoVo.java
@@ -0,0 +1,35 @@
+package com.guwan.face.dto;
+
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Accessors(chain = true)
+public class FaceVideoVo {
+ /**
+ * 人员id
+ */
+ private String personId;
+ /**
+ * 人员name
+ */
+ private String name;
+ /**
+ * 是否正脸
+ */
+
+ private Integer isHeadOnView; //0否1是
+
+ /**
+ * 图片url
+ */
+ private String imageUrl;
+
+
+
+}
diff --git a/login/src/main/java/com/guwan/face/dto/GetFaceListResDTO.java b/login/src/main/java/com/guwan/face/dto/GetFaceListResDTO.java
new file mode 100644
index 0000000..9bd9a18
--- /dev/null
+++ b/login/src/main/java/com/guwan/face/dto/GetFaceListResDTO.java
@@ -0,0 +1,14 @@
+package com.guwan.face.dto;
+
+import lombok.Data;
+
+@Data
+public class GetFaceListResDTO {
+
+ private String id;
+
+ private String name;
+
+ private String url;
+
+}
diff --git a/login/src/main/java/com/guwan/face/entity/ProcessInfo.java b/login/src/main/java/com/guwan/face/entity/ProcessInfo.java
new file mode 100644
index 0000000..516f558
--- /dev/null
+++ b/login/src/main/java/com/guwan/face/entity/ProcessInfo.java
@@ -0,0 +1,12 @@
+package com.guwan.face.entity;
+
+
+import lombok.Data;
+
+@Data
+public class ProcessInfo {
+ private int age;
+ private int gender;
+ private int liveness;
+
+}
diff --git a/login/src/main/java/com/guwan/face/entity/UserCompareInfo.java b/login/src/main/java/com/guwan/face/entity/UserCompareInfo.java
new file mode 100644
index 0000000..b21fd9e
--- /dev/null
+++ b/login/src/main/java/com/guwan/face/entity/UserCompareInfo.java
@@ -0,0 +1,12 @@
+package com.guwan.face.entity;
+
+
+import com.guwan.face.util.UserInfo;
+import lombok.Data;
+
+
+@Data
+public class UserCompareInfo extends UserInfo {
+ private Float similar;
+ private Integer isHeadOnView; //0否1是
+}
diff --git a/login/src/main/java/com/guwan/face/enums/ErrorCodeEnum.java b/login/src/main/java/com/guwan/face/enums/ErrorCodeEnum.java
new file mode 100644
index 0000000..ec6859a
--- /dev/null
+++ b/login/src/main/java/com/guwan/face/enums/ErrorCodeEnum.java
@@ -0,0 +1,50 @@
+package com.guwan.face.enums;
+
+
+import com.guwan.face.rpc.ErrorCode;
+import lombok.Getter;
+
+
+@Getter
+public enum ErrorCodeEnum implements ErrorCode {
+
+ /**
+ * 成功
+ */
+ SUCCESS(0, "success", "成功"),
+ FAIL(1, "fail", "失败"),
+ PARAM_ERROR(2, "param error", "参数错误"),
+ SYSTEM_ERROR(999, "system error", "系统错误"),
+
+ ;
+ private Integer code;
+ private String desc;
+ private String descCN;
+
+ ErrorCodeEnum(Integer code, String desc) {
+ this.code = code;
+ this.desc = desc;
+ }
+
+ ErrorCodeEnum(Integer code, String desc, String descCN) {
+ this.code = code;
+ this.desc = desc;
+ this.descCN = descCN;
+ }
+
+ @Override
+ public Integer getCode() {
+ return code;
+ }
+
+ @Override
+ public String getDesc() {
+ return desc;
+ }
+
+ @Override
+ public String getDescCN() {
+ return descCN;
+ }
+
+}
diff --git a/login/src/main/java/com/guwan/face/face/FacePreviewInfo.java b/login/src/main/java/com/guwan/face/face/FacePreviewInfo.java
new file mode 100644
index 0000000..801270f
--- /dev/null
+++ b/login/src/main/java/com/guwan/face/face/FacePreviewInfo.java
@@ -0,0 +1,46 @@
+package com.guwan.face.face;
+
+import com.arcsoft.face.FaceInfo;
+
+public class FacePreviewInfo {
+ private FaceInfo faceInfo;
+ private int trackId;
+ private int gender = -1;
+
+ public FacePreviewInfo(FaceInfo faceInfo, int trackId) {
+ this.faceInfo = faceInfo;
+ this.trackId = trackId;
+ }
+
+ public FacePreviewInfo(FaceInfo faceInfo, int trackId, int gender) {
+ this.faceInfo = faceInfo;
+ this.trackId = trackId;
+ this.gender = gender;
+ }
+
+ public int getGender() {
+ return gender;
+ }
+
+ public void setGender(int gender) {
+ this.gender = gender;
+ }
+
+ public FaceInfo getFaceInfo() {
+ return faceInfo;
+ }
+
+ public void setFaceInfo(FaceInfo faceInfo) {
+ this.faceInfo = faceInfo;
+ }
+
+
+ public int getTrackId() {
+ return trackId;
+ }
+
+ public void setTrackId(int trackId) {
+ this.trackId = trackId;
+ }
+
+}
diff --git a/login/src/main/java/com/guwan/face/face/FaceRecognize.java b/login/src/main/java/com/guwan/face/face/FaceRecognize.java
new file mode 100644
index 0000000..de444ff
--- /dev/null
+++ b/login/src/main/java/com/guwan/face/face/FaceRecognize.java
@@ -0,0 +1,293 @@
+package com.guwan.face.face;
+
+import com.arcsoft.face.*;
+import com.arcsoft.face.enums.DetectMode;
+import com.arcsoft.face.enums.ErrorInfo;
+import com.arcsoft.face.enums.ExtractType;
+import com.arcsoft.face.toolkit.ImageFactory;
+import com.arcsoft.face.toolkit.ImageInfo;
+import com.guwan.face.config.ArcFaceAutoConfiguration;
+import com.guwan.face.factory.FaceEngineFactory;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.pool2.impl.GenericObjectPool;
+import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
+
+import java.io.File;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+@Slf4j
+public final class FaceRecognize {
+
+ /**
+ * VIDEO模式人脸检测引擎,用于预览帧人脸追踪
+ */
+ private static FaceEngine ftEngine;
+
+ /**
+ * 人脸注册引擎
+ */
+ private static FaceEngine regEngine;
+
+ /**
+ * 用于人脸识别的引擎池
+ */
+ private static GenericObjectPool frEnginePool;
+
+
+ private static volatile ConcurrentHashMap faceResultRegistry = new ConcurrentHashMap<>();
+
+ private static ExecutorService frService = Executors.newFixedThreadPool(20);
+
+ public static ConcurrentHashMap faceFeatureRegistry = new ConcurrentHashMap<>();
+
+ /**
+ * 初始化引擎
+ */
+ public void initEngine(String appId, String sdkKey, String activeKey, String activeFile) {
+
+ //引擎配置
+ ftEngine = new FaceEngine(ArcFaceAutoConfiguration.CACHE_LIB_FOLDER);
+ int activeCode;
+ if (StringUtils.isNotEmpty(activeFile)) {
+ activeCode = ftEngine.activeOffline(activeFile);
+ } else {
+ activeCode = ftEngine.activeOnline(appId, sdkKey, activeKey);
+ }
+
+ EngineConfiguration ftEngineCfg = new EngineConfiguration();
+ ftEngineCfg.setDetectMode(DetectMode.ASF_DETECT_MODE_VIDEO);
+ ftEngineCfg.setFunctionConfiguration(FunctionConfiguration.builder().supportFaceDetect(true).build());
+ int ftInitCode = ftEngine.init(ftEngineCfg);
+
+ //引擎配置
+ regEngine = new FaceEngine(ArcFaceAutoConfiguration.CACHE_LIB_FOLDER);
+
+ EngineConfiguration regEngineCfg = new EngineConfiguration();
+ regEngineCfg.setDetectMode(DetectMode.ASF_DETECT_MODE_IMAGE);
+ regEngineCfg.setFunctionConfiguration(FunctionConfiguration.builder().supportFaceDetect(true).supportFaceRecognition(true).build());
+ int regInitCode = regEngine.init(regEngineCfg);
+
+
+ GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
+ poolConfig.setMaxIdle(5);
+ poolConfig.setMaxTotal(5);
+ poolConfig.setMinIdle(5);
+ poolConfig.setLifo(false);
+ EngineConfiguration frEngineCfg = new EngineConfiguration();
+ frEngineCfg.setFunctionConfiguration(FunctionConfiguration.builder().supportFaceRecognition(true).build());
+ frEnginePool = new GenericObjectPool(new FaceEngineFactory(appId, sdkKey, activeKey,activeFile, frEngineCfg), poolConfig);//底层库算法对象池
+
+
+ if (!(activeCode == ErrorInfo.MOK.getValue() || activeCode == ErrorInfo.MERR_ASF_ALREADY_ACTIVATED.getValue())) {
+ log.error("activeCode: " + activeCode);
+ throw new RuntimeException("activeCode: " + activeCode);
+ }
+ if (ftInitCode != ErrorInfo.MOK.getValue()) {
+ log.error("ftInitEngine: " + ftInitCode);
+ throw new RuntimeException("ftInitEngine: " + ftInitCode);
+ }
+
+ if (regInitCode != ErrorInfo.MOK.getValue()) {
+ log.error("regInitEngine: " + regInitCode);
+ throw new RuntimeException("regInitEngine: " + regInitCode);
+ }
+
+ }
+
+
+ public static void registerFace(String imagePath) {
+
+ log.info("正在注册人脸");
+
+ int count = 0;
+ if (regEngine != null) {
+ File file = new File(imagePath);
+ File[] files = file.listFiles();
+
+ for (File file1 : files) {
+ ImageInfo imageInfo = ImageFactory.getRGBData(file1);
+ if (imageInfo != null) {
+ List faceInfoList = new ArrayList<>();
+ int code = regEngine.detectFaces(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(),
+ imageInfo.getImageFormat(), faceInfoList);
+
+ if (code == 0 && faceInfoList.size() > 0) {
+ FaceFeature faceFeature = new FaceFeature();
+ int resCode = regEngine.extractFaceFeature(imageInfo, faceInfoList.get(0), ExtractType.REGISTER, 0, faceFeature);
+ if (resCode == 0) {
+ int lastIndexOf = file1.getName().lastIndexOf(".");
+ String name = file1.getName().substring(0, file1.getName().length() - lastIndexOf - 1);
+ faceFeatureRegistry.put(name, faceFeature.getFeatureData());
+ log.info("成功注册人脸:" + name);
+ count++;
+ }
+ }
+ }
+ }
+ log.info("人脸注册完成,共注册:" + count + "张人脸");
+ } else {
+ throw new RuntimeException("注册失败,引擎未初始化或初始化失败");
+ }
+
+
+ }
+
+ public static void registerFace(Map face) {
+ face.forEach((k, v) -> {
+ faceFeatureRegistry.put(k, v.clone());
+ });
+ }
+
+ public static void removeFace(String name) {
+ faceFeatureRegistry.remove(name);
+ }
+
+ public static void clearFace() {
+ faceFeatureRegistry.clear();
+ }
+
+ public static FaceResult getFaceResult(FaceInfo faceInfo, ImageInfo imageInfo) {
+ FaceResult faceResult = faceResultRegistry.get(faceInfo.getFaceId());
+ if (faceResult == null) {
+ faceResult = new FaceResult();
+ faceResultRegistry.put(faceInfo.getFaceId(), faceResult);
+ frService.submit(new FaceInfoRunnable(faceInfo, imageInfo, faceResult));
+ } else if (faceResult.isFlag()) {
+ return faceResult;
+ }
+ return null;
+ }
+
+ public List detectFaces(ImageInfo imageInfo) {
+ if (ftEngine != null) {
+ List faceInfoList = new ArrayList<>();
+ int code = ftEngine.detectFaces(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(),
+ imageInfo.getImageFormat(), faceInfoList);
+
+ List previewInfoList = new LinkedList<>();
+ for (FaceInfo faceInfo : faceInfoList) {
+ FacePreviewInfo facePreviewInfo = new FacePreviewInfo();
+ facePreviewInfo.setFaceInfo(faceInfo);
+ previewInfoList.add(facePreviewInfo);
+ }
+
+ clearFaceResultRegistry(faceInfoList);
+ return previewInfoList;
+
+ }
+ return null;
+ }
+
+
+ private long lastClearTime = System.currentTimeMillis();
+
+ //清理过时的人脸
+ private void clearFaceResultRegistry(List faceInfoList) {
+ if (System.currentTimeMillis() - lastClearTime > 5000) {
+ Iterator iterator = faceResultRegistry.keySet().iterator();
+ for (; iterator.hasNext(); ) {
+ Integer next = iterator.next();
+ boolean flag = false;
+ for (FaceInfo faceInfo : faceInfoList) {
+ if (next.equals(faceInfo.getFaceId())) {
+ flag = true;
+ }
+ }
+ if (!flag) {
+ iterator.remove();
+ }
+
+ }
+ lastClearTime = System.currentTimeMillis();
+ }
+
+
+ }
+
+
+ @Data
+ public static class FaceResult {
+ private boolean flag = false;
+ private String name;
+ private float score;
+
+
+ }
+
+ @Data
+ public class FacePreviewInfo {
+
+ private FaceInfo faceInfo;
+ private int age;
+ private boolean liveness;
+
+ }
+
+
+ private static class FaceInfoRunnable implements Runnable {
+ private FaceInfo faceInfo;
+ private ImageInfo imageInfo;
+ private FaceResult faceResult;
+
+ public FaceInfoRunnable(FaceInfo faceInfo, ImageInfo imageInfo, FaceResult faceResult) {
+ this.faceInfo = faceInfo;
+ this.imageInfo = imageInfo;
+ this.faceResult = faceResult;
+ }
+
+ @Override
+ public void run() {
+ FaceEngine frEngine = null;
+ try {
+ frEngine = frEnginePool.borrowObject();
+ if (frEngine != null) {
+ FaceFeature faceFeature = new FaceFeature();
+ int resCode = frEngine.extractFaceFeature(imageInfo, faceInfo, ExtractType.RECOGNIZE, 0, faceFeature);
+ if (resCode == 0) {
+
+ float score = 0.0F;
+ Iterator> iterator = faceFeatureRegistry.entrySet().iterator();
+ for (; iterator.hasNext(); ) {
+ Map.Entry next = iterator.next();
+ FaceFeature faceFeatureTarget = new FaceFeature();
+ faceFeatureTarget.setFeatureData(next.getValue());
+
+ FaceSimilar faceSimilar = new FaceSimilar();
+ frEngine.compareFaceFeature(faceFeatureTarget, faceFeature, faceSimilar);
+ if (faceSimilar.getScore() > score) {
+ score = faceSimilar.getScore();
+ faceResult.setName(next.getKey());
+ }
+ }
+
+ log.info("相似度:" + score);
+ if (score >= 0.8f) {
+ faceResult.setScore(score);
+ faceResult.setFlag(true);
+ faceResultRegistry.put(faceInfo.getFaceId(), faceResult);
+ } else {
+ faceResultRegistry.remove(faceInfo.getFaceId());
+ }
+
+ }
+ }
+ } catch (Exception e) {
+
+ } finally {
+ if (frEngine != null) {
+ frEnginePool.returnObject(frEngine);
+ }
+ }
+
+
+ }
+ }
+
+
+}
diff --git a/login/src/main/java/com/guwan/face/factory/FaceEngineFactory.java b/login/src/main/java/com/guwan/face/factory/FaceEngineFactory.java
new file mode 100644
index 0000000..568856e
--- /dev/null
+++ b/login/src/main/java/com/guwan/face/factory/FaceEngineFactory.java
@@ -0,0 +1,73 @@
+package com.guwan.face.factory;
+
+import com.arcsoft.face.EngineConfiguration;
+import com.arcsoft.face.FaceEngine;
+import com.arcsoft.face.enums.ErrorInfo;
+import com.guwan.face.config.ArcFaceAutoConfiguration;
+import com.guwan.face.enums.ErrorCodeEnum;
+import com.guwan.face.rpc.BusinessException;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.pool2.BasePooledObjectFactory;
+import org.apache.commons.pool2.PooledObject;
+import org.apache.commons.pool2.impl.DefaultPooledObject;
+
+@Slf4j
+public class FaceEngineFactory extends BasePooledObjectFactory {
+
+ private String appId;
+ private String sdkKey;
+ private String activeKey;
+ private String activeFile;
+ private EngineConfiguration engineConfiguration;
+
+
+ public FaceEngineFactory(String appId, String sdkKey, String activeKey, String activeFile, EngineConfiguration engineConfiguration) {
+ this.appId = appId;
+ this.sdkKey = sdkKey;
+ this.activeKey = activeKey;
+ this.activeFile=activeFile;
+ this.engineConfiguration = engineConfiguration;
+ }
+
+
+ @Override
+ public FaceEngine create() {
+
+
+ FaceEngine faceEngine = new FaceEngine(ArcFaceAutoConfiguration.CACHE_LIB_FOLDER);
+
+// FaceEngine faceEngine = new FaceEngine("/home/huangyifang/gb/咸阳师范/ArcSoft_ArcFacePro_linux_java_V4.1/libs/LINUX64/");
+ int activeCode;
+ if (StringUtils.isNotEmpty(activeFile)) {
+ activeCode = faceEngine.activeOffline(activeFile);
+ } else {
+ activeCode = faceEngine.activeOnline(appId, sdkKey, activeKey);
+ }
+ log.debug("引擎激活errorCode:" + activeCode);
+ if (activeCode != ErrorInfo.MOK.getValue() && activeCode != ErrorInfo.MERR_ASF_ALREADY_ACTIVATED.getValue()) {
+ log.error("引擎激活失败" + activeCode);
+ throw new BusinessException(ErrorCodeEnum.FAIL, "引擎激活失败" + activeCode);
+ }
+ int initCode = faceEngine.init(engineConfiguration);
+ if (initCode != ErrorInfo.MOK.getValue()) {
+ log.error("引擎初始化失败" + initCode);
+ throw new BusinessException(ErrorCodeEnum.FAIL, "引擎初始化失败" + initCode);
+ }
+ log.debug("初始化引擎errorCode:" + initCode);
+ return faceEngine;
+ }
+
+ @Override
+ public PooledObject wrap(FaceEngine faceEngine) {
+ return new DefaultPooledObject<>(faceEngine);
+ }
+
+
+ @Override
+ public void destroyObject(PooledObject p) throws Exception {
+ FaceEngine faceEngine = p.getObject();
+ int result = faceEngine.unInit();
+ super.destroyObject(p);
+ }
+}
diff --git a/login/src/main/java/com/guwan/face/rpc/BusinessException.java b/login/src/main/java/com/guwan/face/rpc/BusinessException.java
new file mode 100644
index 0000000..a9df4b3
--- /dev/null
+++ b/login/src/main/java/com/guwan/face/rpc/BusinessException.java
@@ -0,0 +1,64 @@
+package com.guwan.face.rpc;
+
+import lombok.Data;
+
+/**
+ * @Author: st7251
+ * @Date: 2018/11/23 14:18
+ */
+@Data
+public class BusinessException extends RuntimeException {
+ private ErrorCode errorCode;
+ private String msg;
+ private String msgCN;
+
+ public BusinessException(Response response) {
+ this.errorCode = new ErrorCode() {
+ @Override
+ public Integer getCode() {
+ return response.getCode();
+ }
+
+ @Override
+ public String getDesc() {
+ return response.getMsg();
+ }
+
+ @Override
+ public String getDescCN() {
+ return response.getMsg();
+ }
+ };
+ this.msg=response.getMsg();
+ this.msgCN=response.getMsg();
+ }
+
+ public BusinessException(ErrorCode errorCode) {
+ super(errorCode.getDesc());
+ this.errorCode = errorCode;
+ this.msg= errorCode.getDesc();
+ this.msgCN=errorCode.getDescCN();
+ }
+
+ public BusinessException(ErrorCode errorCode, String msg) {
+ super(errorCode.getDesc());
+ this.errorCode = errorCode;
+ this.msg = msg;
+ this.msgCN=msg;
+ }
+
+ public BusinessException(Throwable cause, ErrorCode errorCode) {
+ super(cause);
+ this.errorCode = errorCode;
+ this.msg= errorCode.getDesc();
+ this.msgCN=errorCode.getDescCN();
+ }
+
+
+ public BusinessException(Throwable cause, ErrorCode errorCode, String msg) {
+ super(cause);
+ this.errorCode = errorCode;
+ this.msg = msg;
+ this.msgCN=msg;
+ }
+}
diff --git a/login/src/main/java/com/guwan/face/rpc/ErrorCode.java b/login/src/main/java/com/guwan/face/rpc/ErrorCode.java
new file mode 100644
index 0000000..abca5bb
--- /dev/null
+++ b/login/src/main/java/com/guwan/face/rpc/ErrorCode.java
@@ -0,0 +1,12 @@
+package com.guwan.face.rpc;
+
+public interface ErrorCode {
+
+
+ Integer getCode();
+
+ String getDesc();
+
+ String getDescCN();
+
+}
diff --git a/login/src/main/java/com/guwan/face/rpc/GlobalExceptionHandler.java b/login/src/main/java/com/guwan/face/rpc/GlobalExceptionHandler.java
new file mode 100644
index 0000000..93b7761
--- /dev/null
+++ b/login/src/main/java/com/guwan/face/rpc/GlobalExceptionHandler.java
@@ -0,0 +1,47 @@
+package com.guwan.face.rpc;
+
+
+import com.guwan.face.enums.ErrorCodeEnum;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+@RestControllerAdvice
+@Slf4j
+public class GlobalExceptionHandler{
+
+
+ /**
+ * 自定义异常
+ */
+ @ExceptionHandler(BusinessException.class)
+ public Response businessException(BusinessException e) {
+ log.error(e.getMessage(), e);
+ Response response = new Response();
+ response.setCode(e.getErrorCode().getCode());
+ response.setMsg(e.getMsgCN());
+ return response;
+ }
+
+ @ExceptionHandler(IllegalArgumentException.class)
+ public Response handleIllegalArgumentException(IllegalArgumentException e) {
+ log.error(e.getMessage(), e);
+ Response response = new Response();
+ response.setCode(ErrorCodeEnum.PARAM_ERROR.getCode());
+ response.setMsg(e.getMessage());
+ return response;
+ }
+
+ @ExceptionHandler(Exception.class)
+ public Response handleException(Exception e) {
+ log.error(e.getMessage(), e);
+ Response response = new Response();
+ response.setCode(ErrorCodeEnum.SYSTEM_ERROR.getCode());
+ response.setMsg(ErrorCodeEnum.SYSTEM_ERROR.getDescCN());
+ return response;
+ }
+
+
+
+
+}
diff --git a/login/src/main/java/com/guwan/face/rpc/Response.java b/login/src/main/java/com/guwan/face/rpc/Response.java
new file mode 100644
index 0000000..6b7fc6c
--- /dev/null
+++ b/login/src/main/java/com/guwan/face/rpc/Response.java
@@ -0,0 +1,39 @@
+package com.guwan.face.rpc;
+
+import lombok.Data;
+
+@Data
+public class Response {
+
+ private int code = -1;
+ private String msg = "success";
+ private T data;
+
+ public static Response newSuccessResponse(T data) {
+ return newResponse(data, 0, "success");
+ }
+
+ public static Response newFailedResponse(Integer code, String message) {
+ return newResponse(null, code, message);
+ }
+
+ public static Response newFailedResponse(ErrorCode ErrorCode) {
+ return newResponse(null, ErrorCode.getCode(), ErrorCode.getDesc());
+ }
+
+ public static Response newFailedResponse(ErrorCode ErrorCode, String message) {
+ return newResponse(null, ErrorCode.getCode(), message);
+ }
+
+ public static Response newResponse(T data, Integer code, String message) {
+ Response response = new Response();
+ response.setCode(code);
+ response.setMsg(message);
+ if (data != null && data instanceof String && "".equals(data)) {
+ response.setData(null);
+ } else {
+ response.setData(data);
+ }
+ return response;
+ }
+}
diff --git a/login/src/main/java/com/guwan/face/rtsp/RtspFrameGrabber.java b/login/src/main/java/com/guwan/face/rtsp/RtspFrameGrabber.java
new file mode 100644
index 0000000..fbd913a
--- /dev/null
+++ b/login/src/main/java/com/guwan/face/rtsp/RtspFrameGrabber.java
@@ -0,0 +1,420 @@
+/*
+package com.guwan.face.rtsp;
+
+import cn.hutool.core.collection.CollectionUtil;
+import com.arcsoft.face.FaceInfo;
+import com.arcsoft.face.enums.ExtractType;
+import com.arcsoft.face.toolkit.ImageFactory;
+import com.arcsoft.face.toolkit.ImageInfo;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.guwan.face.dto.FaceVideoVo;
+import io.minio.MinioClient;
+import io.minio.PutObjectOptions;
+import lombok.extern.slf4j.Slf4j;
+import net.shapelight.common.config.GlobalValue;
+import net.shapelight.common.config.MinioConfig;
+import net.shapelight.common.utils.Constant;
+import net.shapelight.common.utils.UUIDUtil;
+import net.shapelight.modules.face.entity.UserCompareInfo;
+import net.shapelight.modules.face.service.FaceEngineService;
+import net.shapelight.modules.face.util.UserInfo;
+import net.shapelight.modules.face.util.UserRamGroup;
+import net.shapelight.modules.feignClient.CxFeignClient;
+
+import net.shapelight.modules.ten.dao.TenCellDao;
+import net.shapelight.modules.ten.entity.TenCellEntity;
+import net.shapelight.modules.ten.entity.TenPersonEntity;
+import net.shapelight.modules.ten.service.TenPersonService;
+import net.shapelight.modules.ten.service.impl.TenPersonServiceImpl;
+import org.bytedeco.javacpp.avutil;
+import org.bytedeco.javacv.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static org.bytedeco.javacpp.avutil.AV_LOG_ERROR;
+
+@Component
+@Slf4j
+public class RtspFrameGrabber {
+
+ */
+/* @Autowired
+ private FaceEngineService faceEngineService;
+
+ @Autowired
+ private TenPersonService personService;
+
+ @Autowired
+ private GlobalValue globalValue;
+
+ @Autowired
+ private CxFeignClient feignClient;
+ @Autowired
+ private TenPersonServiceImpl tenPersonService;
+
+ @Autowired
+ private TenCellDao tenCellDao;
+
+ @Autowired
+ private MinioConfig minioConfig;
+ @Autowired
+ private MinioClient minioClient;
+
+
+ *//*
+
+ */
+/**
+ * 用于记录人脸识别相关状态
+ *//*
+
+ public ConcurrentHashMap requestFeatureStatusMap = new ConcurrentHashMap<>();
+ */
+/**
+ * rtsp视频流url
+ *//*
+
+ @Value("${global.Url.rtspUrl}")
+ private String rtspUrl;
+ */
+/**
+ * 帧抓取器
+ *//*
+
+ private FFmpegFrameGrabber grabber;
+ */
+/**
+ * 视频帧率
+ *//*
+
+ private int frameRate = 25;
+ */
+/**
+ * 视频码率
+ *//*
+
+// private int bitRate = 2000000;
+ private int bitRate = 128000;
+ */
+/**
+ * 视频宽度
+ *//*
+
+ private int frameWidth = 480;
+ */
+/**
+ * 视频高度
+ *//*
+
+ private int frameHeight = 270;
+
+
+
+ private void createGrabber() {
+ try {
+
+ grabber = FFmpegFrameGrabber.createDefault(rtspUrl);
+ grabber.setOption("rtsp_transport", "tcp");
+
+// grabber.setOption("reconnect", "1");
+// grabber.setOption("reconnect_at_eof", "1");
+// grabber.setOption("reconnect_streamed", "1");
+// grabber.setOption("reconnect_delay_max", "2");
+// grabber.setOption("preset", "veryfast");
+// grabber.setOption("probesize", "192");
+// grabber.setOption("tune", "zerolatency");
+// grabber.setFrameRate(30.0);
+// grabber.setOption("buffer_size", "" + this.bufferSize);
+// grabber.setOption("max_delay", "500000");
+// grabber.setOption("stimeout", String.valueOf(20000));
+// grabber.setOption("loglevel", "quiet");
+
+
+// grabber.setOption("appkey", "****");//海康视频 appkey
+// grabber.setOption("secret", byte2Base64);//海康视频 secret
+// grabber.setOption("port", "446");//默认443
+// grabber.setOption("enableHTTPS", "1"); //是否启用HTTPS协议,这里总是填1
+// grabber.setOption("rtsp_flags", "prefer_tcp");
+ grabber.setOption("stimeout", "5000000");//5秒
+
+
+ //设置帧率
+ grabber.setFrameRate(frameRate);
+ //设置获取的视频宽度
+ grabber.setImageWidth(frameWidth);
+ //设置获取的视频高度
+ grabber.setImageHeight(frameHeight);
+ //设置视频bit率
+ grabber.setVideoBitrate(bitRate);
+ grabber.start();
+ } catch (Exception e) {
+ log.error(e.getMessage());
+ }
+ }
+ public List startGrabber(String cellId) {
+
+ List faceVideoVos = new ArrayList<>();
+
+ avutil.av_log_set_level(AV_LOG_ERROR);
+ Java2DFrameConverter java2DFrameConverter = new Java2DFrameConverter();
+ if (grabber == null) {
+ //log.info("连接rtsp:" + rstp + ",开始创建grabber");
+ createGrabber();
+ }
+ try {
+ Frame frame = grabber.grabImage();
+ if (frame != null) {
+// logger.info("处理帧.............................................");
+ BufferedImage bi = java2DFrameConverter.getBufferedImage(frame);
+
+ byte[] bytes = imageToBytes(bi, "jpg");
+
+ */
+/* InputStream frameInputStream = new ByteArrayInputStream(bytes);
+ String frameFileName = "temp/" + "frame_" + UUIDUtil.uuid()
+ + ".jpg";
+
+ PutObjectOptions framePutObjectOptions = new PutObjectOptions(bytes.length, -1);
+ framePutObjectOptions.setContentType("image/jpeg");
+
+ minioClient.putObject(
+ minioConfig.getBucketName(), frameFileName, frameInputStream, framePutObjectOptions);
+
+ System.out.println("文件名 = " + globalValue.getMinioEndpoint() + "/" +
+ globalValue.getMinioBucketName() + "/" + frameFileName);*//*
+
+ */
+/* // 读取图片
+ BufferedImage image = ImageIO.read(new File("C:\\Users\\zhangbo\\OneDrive\\图片\\Camera Roll\\1寸相片.jpg"));
+
+ // 创建字节输出流
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ // 使用ImageIO将BufferedImage编码为byte[]
+ ImageIO.write(image, "jpg", baos);
+
+ // 转换为byte数组
+ byte[] imageBytes = baos.toByteArray();*//*
+
+ faceVideoVos = imageRecognition(bytes, cellId);
+ System.out.println("faceVideoVos = " + faceVideoVos);
+
+ } else {
+ log.error("解码失败");
+ if (grabber != null) {
+ try {
+ grabber.stop();
+ } catch (FrameGrabber.Exception ex) {
+ log.error("grabber stop exception: " + ex.getMessage());
+ } finally {
+ grabber = null;
+ }
+ }
+ }
+ } catch (Exception e) {
+ log.error(e.getMessage());
+
+ if (grabber != null) {
+ try {
+ grabber.stop();
+ } catch (FrameGrabber.Exception ex) {
+ log.error("grabber stop exception: " + ex.getMessage());
+ } finally {
+ grabber = null;
+ }
+ }
+
+ } finally {
+ grabber = null;
+ }
+// try {
+// Thread.sleep(100);
+// } catch (InterruptedException e) {
+// logger.error(e.getMessage());
+// }
+
+ return faceVideoVos;
+ }
+
+ public List recognition(MultipartFile file,String cellId) {
+ try {
+ byte[] bytes = file.getBytes();
+ return imageRecognition(bytes, cellId);
+
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private List imageRecognition(byte[] bytes,String cellId) {
+ List temp = new ArrayList<>();
+ if (bytes != null && bytes.length > 0) {
+ ImageInfo imageInfo = ImageFactory.getRGBData(bytes);
+ List faceInfoList = faceEngineService.detectFaces(imageInfo);
+
+
+ */
+/* for (FaceInfo faceInfo : faceInfoList) {
+ System.out.println(faceInfo.getFace3DAngle());
+ //Yaw上下 Pitch左右
+ if (faceInfo.getFace3DAngle().getYaw() > 20 || faceInfo.getFace3DAngle().getYaw() < -20) {
+ System.out.println("没在好好看!!!");
+ // faceInfoList.remove(faceInfo);
+ }
+ if (faceInfo.getFace3DAngle().getPitch() > 20 || faceInfo.getFace3DAngle().getPitch() < -20) {
+ System.out.println("没在好好看!!!");
+ }
+ }*//*
+
+
+
+ if (CollectionUtil.isNotEmpty(faceInfoList)) {
+ faceInfoList.forEach(faceInfo -> {
+ */
+/* FaceRecognitionResDTO faceRecognitionResDTO = new FaceRecognitionResDTO();
+ faceRecognitionResDTO.setRect(faceInfo.getRect());*//*
+
+
+ byte[] featureBytes = faceEngineService.extractFaceFeature(imageInfo,
+ faceInfo, ExtractType.REGISTER);
+ if (featureBytes != null) {
+ //底库
+ List userInfoList = UserRamGroup.getUserList(cellId);
+ //人脸对比 这里长度永远为1
+ List userCompareInfoList = faceEngineService
+ .faceRecognition(featureBytes, userInfoList, Float.parseFloat(globalValue.getRecFaceThd()));
+
+ for (UserCompareInfo userCompareInfo : userCompareInfoList) {
+ FaceVideoVo faceVideoVo = new FaceVideoVo();
+ if (faceInfo.getFace3DAngle().getYaw() > 20 || faceInfo.getFace3DAngle().getYaw() < -20) {
+ faceVideoVo.setIsHeadOnView(0);
+ }else if (faceInfo.getFace3DAngle().getPitch() > 20 || faceInfo.getFace3DAngle().getPitch() < -20) {
+ faceVideoVo.setIsHeadOnView(0);
+ }else {
+ faceVideoVo.setIsHeadOnView(1);
+ }
+
+ faceVideoVo.setPersonId(userCompareInfo.getFaceId()).setName(userCompareInfo.getName());
+
+
+
+ InputStream frameInputStream = new ByteArrayInputStream(bytes);
+ String frameFileName = "temp/" + "frame_" + UUIDUtil.uuid()
+ + ".jpg";
+
+ PutObjectOptions framePutObjectOptions = new PutObjectOptions(bytes.length, -1);
+ framePutObjectOptions.setContentType("image/jpeg");
+
+ try {
+ frameInputStream.close();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ try {
+ minioClient.putObject(
+ minioConfig.getBucketName(), frameFileName, frameInputStream, framePutObjectOptions);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ System.out.println("文件名 = " + globalValue.getMinioEndpoint() + "/" +
+ globalValue.getMinioBucketName() + "/" + frameFileName);
+
+
+
+ faceVideoVo.setImageUrl(frameFileName);
+
+ temp.add(faceVideoVo);
+ }
+ if (!userCompareInfoList.isEmpty()) {
+
+ for (UserCompareInfo userCompareInfo : userCompareInfoList) {
+ TenPersonEntity tenPerson = personService.getOne(new LambdaQueryWrapper()
+ .eq(TenPersonEntity::getPersonId, userCompareInfo.getFaceId()));
+ Map personnelTypeMap = new HashMap<>();
+ personnelTypeMap.put(Constant.PERSON_TYPE_OWNER, "2");//内部人员
+ personnelTypeMap.put(Constant.PERSON_TYPE_MEMBER, "1");//承包商
+ personnelTypeMap.put(Constant.PERSON_TYPE_TENANT, "3");//长期供应商
+ personnelTypeMap.put(Constant.PERSON_TYPE_GUEST, "4");//访客
+
+ //
+ Map params = new HashMap<>();
+ params.put("pmWatchVideoRecordId", "");
+ params.put("orgId", tenPerson.getOrgId());
+ params.put("orgName", tenCellDao.selectOne(new QueryWrapper().eq("cell_id", tenPerson.getCellId())));
+ params.put("personnelName", tenPerson.getName());
+ params.put("personnelId", tenPerson.getOpenId());
+ params.put("personnelCardId", tenPerson.getIdCard());
+ params.put("personnelType", personnelTypeMap.get(tenPerson.getPersonType()));
+ params.put("dictSex", tenPerson.getGender() == 0 ? "女" : "男");
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
+ params.put("watchVideoTime", sdf.format(System.currentTimeMillis()));
+ tenPerson.setIsWatchSafeVideo(1);
+ tenPersonService.updateById(tenPerson);
+
+ System.out.println("params = " + params);
+
+ */
+/* JSONObject jsonObject = feignClient.savePmWatchVideoRecord(params);
+ if (jsonObject.getBool("success") != null && jsonObject.getBool("success")) {
+ personService.update(new LambdaUpdateWrapper()
+ .set(TenPersonEntity::getIsWatchSafeVideo, 1)
+ .eq(TenPersonEntity::getPersonId, userCompareInfo.getFaceId()));
+ }*//*
+
+ }
+
+
+ }
+ } else {
+ log.error("图片不合格,未检测到人脸");
+ }
+ });
+
+ } else {
+ log.error("图片不合格,未检测到人脸");
+ }
+
+ } else {
+ }
+ return temp;
+ }
+
+ */
+/**
+ * 图片转字节数组
+ *
+ * @param _bi 图片数据
+ * @return 图片字节码
+ *//*
+
+ private byte[] imageToBytes(BufferedImage _bi, String _format) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try {
+ ImageIO.write(_bi, _format, baos);
+ } catch (IOException e) {
+ log.error(e.getMessage());
+ return null;
+ }
+ return baos.toByteArray();
+ }
+
+}
+*/
diff --git a/login/src/main/java/com/guwan/face/service/FaceEngineService.java b/login/src/main/java/com/guwan/face/service/FaceEngineService.java
new file mode 100644
index 0000000..abf2a39
--- /dev/null
+++ b/login/src/main/java/com/guwan/face/service/FaceEngineService.java
@@ -0,0 +1,29 @@
+package com.guwan.face.service;
+
+
+import com.arcsoft.face.FaceInfo;
+import com.arcsoft.face.enums.ExtractType;
+import com.arcsoft.face.toolkit.ImageInfo;
+import com.guwan.face.entity.ProcessInfo;
+import com.guwan.face.entity.UserCompareInfo;
+import com.guwan.face.util.UserInfo;
+
+
+import java.util.List;
+
+
+public interface FaceEngineService {
+
+ List detectFaces(ImageInfo imageInfo);
+
+ Float compareFace(ImageInfo imageInfo1, ImageInfo imageInfo2) ;
+
+ byte[] extractFaceFeature(ImageInfo imageInfo, FaceInfo faceInfo, ExtractType extractType);
+
+ List faceRecognition(byte[] faceFeature, List userInfoList, float passRate) ;
+
+ List process(ImageInfo imageInfo, List faceInfoList);
+
+
+
+}
diff --git a/login/src/main/java/com/guwan/face/service/impl/FaceEngineServiceImpl.java b/login/src/main/java/com/guwan/face/service/impl/FaceEngineServiceImpl.java
new file mode 100644
index 0000000..1c883ff
--- /dev/null
+++ b/login/src/main/java/com/guwan/face/service/impl/FaceEngineServiceImpl.java
@@ -0,0 +1,353 @@
+package com.guwan.face.service.impl;
+
+import cn.hutool.core.collection.CollectionUtil;
+import com.arcsoft.face.*;
+import com.arcsoft.face.enums.DetectMode;
+import com.arcsoft.face.enums.DetectOrient;
+import com.arcsoft.face.enums.ExtractType;
+import com.arcsoft.face.toolkit.ImageInfo;
+import com.google.common.collect.Lists;
+import com.guwan.face.entity.ProcessInfo;
+import com.guwan.face.entity.UserCompareInfo;
+import com.guwan.face.enums.ErrorCodeEnum;
+import com.guwan.face.factory.FaceEngineFactory;
+import com.guwan.face.rpc.BusinessException;
+import com.guwan.face.service.FaceEngineService;
+import com.guwan.face.util.UserInfo;
+import jakarta.annotation.PostConstruct;
+import lombok.extern.slf4j.Slf4j;
+
+import org.apache.commons.pool2.impl.GenericObjectPool;
+import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import jakarta.annotation.PostConstruct;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.*;
+
+
+@Service("faceEngineService")
+@Slf4j
+public class FaceEngineServiceImpl implements FaceEngineService {
+
+ public final static Logger logger = LoggerFactory.getLogger(FaceEngineServiceImpl.class);
+
+ @Value("${config.arcface-sdk.app-id}")
+ public String appId;
+
+ @Value("${config.arcface-sdk.sdk-key}")
+ public String sdkKey;
+
+ @Value("${config.arcface-sdk.active-key}")
+ public String activeKey;
+
+ @Value("${config.arcface-sdk.active-file}")
+ public String activeFile;
+
+ @Value("${config.arcface-sdk.detect-pool-size}")
+ public Integer detectPooSize;
+
+ @Value("${config.arcface-sdk.compare-pool-size}")
+ public Integer comparePooSize;
+
+ private ExecutorService compareExecutorService;
+
+ //通用人脸识别引擎池
+ private GenericObjectPool faceEngineGeneralPool;
+
+ //人脸比对引擎池
+ private GenericObjectPool faceEngineComparePool;
+
+ @PostConstruct
+ public void init() {
+
+
+ GenericObjectPoolConfig detectPoolConfig = new GenericObjectPoolConfig();
+ detectPoolConfig.setMaxIdle(detectPooSize);
+ detectPoolConfig.setMaxTotal(detectPooSize);
+ detectPoolConfig.setMinIdle(detectPooSize);
+ detectPoolConfig.setLifo(false);
+ EngineConfiguration detectCfg = new EngineConfiguration();
+ FunctionConfiguration detectFunctionCfg = new FunctionConfiguration();
+ detectFunctionCfg.setSupportFaceDetect(true);//开启人脸检测功能
+ detectFunctionCfg.setSupportFaceRecognition(true);//开启人脸识别功能
+ detectFunctionCfg.setSupportAge(true);//开启年龄检测功能
+ detectFunctionCfg.setSupportGender(true);//开启性别检测功能
+ detectFunctionCfg.setSupportLiveness(true);//开启活体检测功能
+ detectCfg.setFunctionConfiguration(detectFunctionCfg);
+ detectCfg.setDetectMode(DetectMode.ASF_DETECT_MODE_IMAGE);//图片检测模式,如果是连续帧的视频流图片,那么改成VIDEO模式
+ detectCfg.setDetectFaceOrientPriority(DetectOrient.ASF_OP_0_ONLY);//人脸旋转角度
+ faceEngineGeneralPool = new GenericObjectPool(new FaceEngineFactory(appId, sdkKey, activeKey, activeFile, detectCfg), detectPoolConfig);//底层库算法对象池
+
+
+ //初始化特征比较线程池
+ GenericObjectPoolConfig comparePoolConfig = new GenericObjectPoolConfig();
+ comparePoolConfig.setMaxIdle(comparePooSize);
+ comparePoolConfig.setMaxTotal(comparePooSize);
+ comparePoolConfig.setMinIdle(comparePooSize);
+ comparePoolConfig.setLifo(false);
+ EngineConfiguration compareCfg = new EngineConfiguration();
+ FunctionConfiguration compareFunctionCfg = new FunctionConfiguration();
+ compareFunctionCfg.setSupportFaceRecognition(true);//开启人脸识别功能
+ compareCfg.setFunctionConfiguration(compareFunctionCfg);
+ compareCfg.setDetectMode(DetectMode.ASF_DETECT_MODE_IMAGE);//图片检测模式,如果是连续帧的视频流图片,那么改成VIDEO模式
+ compareCfg.setDetectFaceOrientPriority(DetectOrient.ASF_OP_0_ONLY);//人脸旋转角度
+ faceEngineComparePool = new GenericObjectPool(new FaceEngineFactory(appId, sdkKey, activeKey, activeFile, compareCfg), comparePoolConfig);//底层库算法对象池
+ compareExecutorService = Executors.newFixedThreadPool(comparePooSize);
+ }
+
+
+ @Override
+ public List detectFaces(ImageInfo imageInfo) {
+
+ FaceEngine faceEngine = null;
+ try {
+ faceEngine = faceEngineGeneralPool.borrowObject();
+ if (faceEngine == null) {
+ throw new BusinessException(ErrorCodeEnum.FAIL, "获取引擎失败");
+ }
+
+ //人脸检测得到人脸列表
+ List faceInfoList = new ArrayList<>();
+ //人脸检测
+ int errorCode = faceEngine.detectFaces(imageInfo.getImageData(),
+ imageInfo.getWidth(), imageInfo.getHeight(),
+ imageInfo.getImageFormat(), faceInfoList);
+ if (errorCode == 0) {
+ return faceInfoList;
+ } else {
+ log.error("人脸检测失败,errorCode:" + errorCode);
+ }
+
+ } catch (Exception e) {
+ log.error("", e);
+ } finally {
+ if (faceEngine != null) {
+ //释放引擎对象
+ faceEngineGeneralPool.returnObject(faceEngine);
+ }
+ }
+
+ return null;
+
+ }
+
+ @Override
+ public Float compareFace(ImageInfo imageInfo1, ImageInfo imageInfo2) {
+
+ List faceInfoList1 = detectFaces(imageInfo1);
+ List faceInfoList2 = detectFaces(imageInfo2);
+
+ if (CollectionUtil.isEmpty(faceInfoList1)) {
+ throw new BusinessException(ErrorCodeEnum.FAIL, "照片1未检测到人脸");
+ }
+ if (CollectionUtil.isEmpty(faceInfoList2)) {
+ throw new BusinessException(ErrorCodeEnum.FAIL, "照片2未检测到人脸");
+ }
+
+ byte[] feature1 = extractFaceFeature(imageInfo1, faceInfoList1.get(0), ExtractType.REGISTER);
+ byte[] feature2 = extractFaceFeature(imageInfo2, faceInfoList2.get(0), ExtractType.RECOGNIZE);
+
+ FaceEngine faceEngine = null;
+ try {
+ faceEngine = faceEngineGeneralPool.borrowObject();
+ if (faceEngine == null) {
+ throw new BusinessException(ErrorCodeEnum.FAIL, "获取引擎失败");
+ }
+
+ FaceFeature faceFeature1 = new FaceFeature();
+ faceFeature1.setFeatureData(feature1);
+ FaceFeature faceFeature2 = new FaceFeature();
+ faceFeature2.setFeatureData(feature2);
+ //提取人脸特征
+ FaceSimilar faceSimilar = new FaceSimilar();
+ int errorCode = faceEngine.compareFaceFeature(faceFeature1, faceFeature2, faceSimilar);
+ if (errorCode == 0) {
+ return faceSimilar.getScore();
+ } else {
+ log.error("特征提取失败,errorCode:" + errorCode);
+ }
+
+ } catch (Exception e) {
+ log.error("", e);
+ } finally {
+ if (faceEngine != null) {
+ //释放引擎对象
+ faceEngineGeneralPool.returnObject(faceEngine);
+ }
+ }
+
+ return null;
+
+ }
+
+ /**
+ * 人脸特征
+ *
+ * @param imageInfo
+ * @return
+ */
+ @Override
+ public byte[] extractFaceFeature(ImageInfo imageInfo, FaceInfo faceInfo, ExtractType extractType) {
+
+ FaceEngine faceEngine = null;
+ try {
+ faceEngine = faceEngineGeneralPool.borrowObject();
+ if (faceEngine == null) {
+ throw new BusinessException(ErrorCodeEnum.FAIL, "获取引擎失败");
+ }
+
+ FaceFeature faceFeature = new FaceFeature();
+ //提取人脸特征
+ int errorCode = faceEngine.extractFaceFeature(imageInfo, faceInfo, extractType, 0, faceFeature);
+ if (errorCode == 0) {
+ return faceFeature.getFeatureData();
+ } else {
+ log.error("特征提取失败,errorCode:" + errorCode);
+ }
+
+ } catch (Exception e) {
+ log.error("", e);
+ } finally {
+ if (faceEngine != null) {
+ //释放引擎对象
+ faceEngineGeneralPool.returnObject(faceEngine);
+ }
+ }
+
+ return null;
+
+ }
+
+ @Override
+ public List faceRecognition(byte[] faceFeature, List userInfoList, float passRate) {
+ List resultUserInfoList = Lists.newLinkedList();//识别到的人脸列表
+
+ FaceFeature targetFaceFeature = new FaceFeature();
+ targetFaceFeature.setFeatureData(faceFeature);
+
+ List> faceUserInfoPartList = Lists.partition(userInfoList, 1000);//分成1000一组,多线程处理
+ CompletionService> completionService = new ExecutorCompletionService(compareExecutorService);
+ for (List part : faceUserInfoPartList) {
+ completionService.submit(new CompareFaceTask(part, targetFaceFeature, passRate));
+ }
+ for (int i = 0; i < faceUserInfoPartList.size(); i++) {
+ List faceUserInfoList = null;
+ try {
+ faceUserInfoList = completionService.take().get();
+ } catch (InterruptedException | ExecutionException e) {
+ }
+ if (CollectionUtil.isNotEmpty(userInfoList)) {
+ resultUserInfoList.addAll(faceUserInfoList);
+ }
+ }
+
+ resultUserInfoList.sort((h1, h2) -> h2.getSimilar().compareTo(h1.getSimilar()));//从大到小排序
+
+ return resultUserInfoList;
+ }
+
+
+
+ @Override
+ public List process(ImageInfo imageInfo, List faceInfoList) {
+ FaceEngine faceEngine = null;
+ try {
+ //获取引擎对象
+ faceEngine = faceEngineGeneralPool.borrowObject();
+ if (faceEngine == null) {
+ throw new BusinessException(ErrorCodeEnum.FAIL, "获取引擎失败");
+ }
+
+
+ int errorCode = faceEngine.process(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList, FunctionConfiguration.builder().supportAge(true).supportGender(true).supportLiveness(true).build());
+ if (errorCode == 0) {
+ List processInfoList = Lists.newLinkedList();
+
+ //性别列表
+ List genderInfoList = new ArrayList();
+ faceEngine.getGender(genderInfoList);
+
+ //年龄列表
+ List ageInfoList = new ArrayList();
+ faceEngine.getAge(ageInfoList);
+ //活体结果列表
+ List livenessInfoList = new ArrayList();
+ faceEngine.getLiveness(livenessInfoList);
+
+
+ for (int i = 0; i < genderInfoList.size(); i++) {
+ ProcessInfo processInfo = new ProcessInfo();
+ processInfo.setGender(genderInfoList.get(i).getGender());
+ processInfo.setAge(ageInfoList.get(i).getAge());
+ processInfo.setLiveness(livenessInfoList.get(i).getLiveness());
+ processInfoList.add(processInfo);
+ }
+ return processInfoList;
+
+ }
+
+
+ } catch (Exception e) {
+ logger.error("", e);
+ } finally {
+ if (faceEngine != null) {
+ //释放引擎对象
+ faceEngineGeneralPool.returnObject(faceEngine);
+ }
+ }
+
+ return null;
+
+ }
+
+
+ private class CompareFaceTask implements Callable> {
+
+ private List userInfoList;
+ private FaceFeature targetFaceFeature;
+ private float passRate;
+
+
+ public CompareFaceTask(List userInfoList, FaceFeature targetFaceFeature, float passRate) {
+ this.userInfoList = userInfoList;
+ this.targetFaceFeature = targetFaceFeature;
+ this.passRate = passRate;
+ }
+
+ @Override
+ public List call() throws Exception {
+ FaceEngine faceEngine = null;
+ List resultUserInfoList = Lists.newLinkedList();//识别到的人脸列表
+ try {
+ faceEngine = faceEngineComparePool.borrowObject();
+ for (UserInfo userInfo : userInfoList) {
+ FaceFeature sourceFaceFeature = new FaceFeature();
+ sourceFaceFeature.setFeatureData(userInfo.getFaceFeature());
+ FaceSimilar faceSimilar = new FaceSimilar();
+ faceEngine.compareFaceFeature(targetFaceFeature, sourceFaceFeature, faceSimilar);
+ if (faceSimilar.getScore() > passRate) {//相似值大于配置预期,加入到识别到人脸的列表
+ UserCompareInfo info = new UserCompareInfo();
+ info.setName(userInfo.getName());
+ info.setFaceId(userInfo.getFaceId());
+ info.setSimilar(faceSimilar.getScore());
+ resultUserInfoList.add(info);
+ }
+ }
+ } catch (Exception e) {
+ logger.error("", e);
+ } finally {
+ if (faceEngine != null) {
+ faceEngineComparePool.returnObject(faceEngine);
+ }
+ }
+
+ return resultUserInfoList;
+ }
+
+ }
+}
diff --git a/login/src/main/java/com/guwan/face/util/Base64Util.java b/login/src/main/java/com/guwan/face/util/Base64Util.java
new file mode 100644
index 0000000..be51cb7
--- /dev/null
+++ b/login/src/main/java/com/guwan/face/util/Base64Util.java
@@ -0,0 +1,33 @@
+package com.guwan.face.util;
+
+import org.springframework.util.ObjectUtils;
+
+import java.util.Base64;
+
+public class Base64Util {
+ public static String base64Process(String base64Str) {
+ if (!ObjectUtils.isEmpty(base64Str)) {
+ String photoBase64 = base64Str.substring(0, 30).toLowerCase();
+ int indexOf = photoBase64.indexOf("base64,");
+ if (indexOf > 0) {
+ base64Str = base64Str.substring(indexOf + 7);
+ }
+ base64Str = base64Str.replaceAll(" ", "+");
+ base64Str = base64Str.replaceAll("\r|\n", "");
+ return base64Str;
+ }
+ return "";
+ }
+
+ public static byte[] base64ToBytes(String base64) {
+ if (ObjectUtils.isEmpty(base64)) {
+ return null;
+ }
+ String base64Process = base64Process(base64);
+
+ byte[] decode = Base64.getDecoder().decode(base64Process);
+ return decode;
+
+
+ }
+}
diff --git a/login/src/main/java/com/guwan/face/util/FaceEngineTest.java b/login/src/main/java/com/guwan/face/util/FaceEngineTest.java
new file mode 100644
index 0000000..6606b09
--- /dev/null
+++ b/login/src/main/java/com/guwan/face/util/FaceEngineTest.java
@@ -0,0 +1,225 @@
+package com.guwan.face.util;
+
+import com.arcsoft.face.*;
+import com.arcsoft.face.enums.*;
+import com.arcsoft.face.toolkit.ImageFactory;
+import com.arcsoft.face.toolkit.ImageInfo;
+import com.arcsoft.face.toolkit.ImageInfoEx;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+public class FaceEngineTest {
+
+
+ public static void main(String[] args) {
+
+ //激活码,从官网获取
+ String appId = "DEnAZa1bWXcaAxyWUg33QZaKCmMkNmrQxuKZJQGmZsHJ";
+ String sdkKey = "vWbvUyStZeartSaM6QoTzPYWFpSaj4uhfDmRifSzCd6";
+ String activeKey = "82G1-11QA-713Y-8NB4";
+
+ System.err.println("注意,如果返回的errorCode不为0,可查看com.arcsoft.face.enums.ErrorInfo类获取相应的错误信息");
+
+ //人脸识别引擎库存放路径
+ FaceEngine faceEngine = new FaceEngine("/home/huangyifang/gb/咸阳师范/ArcSoft_ArcFacePro_linux_java_V4.1/libs/LINUX64");
+ //激活引擎
+ int errorCode = faceEngine.activeOnline(appId, sdkKey, activeKey);
+ System.out.println("引擎激活errorCode:" + errorCode);
+
+ ActiveDeviceInfo activeDeviceInfo = new ActiveDeviceInfo();
+ //采集设备信息(可离线)
+ errorCode = faceEngine.getActiveDeviceInfo(activeDeviceInfo);
+ System.out.println("采集设备信息errorCode:" + errorCode);
+ System.out.println("设备信息:" + activeDeviceInfo.getDeviceInfo());
+
+// faceEngine.activeOffline("d:\\ArcFacePro64.dat.offline");
+
+ ActiveFileInfo activeFileInfo = new ActiveFileInfo();
+ errorCode = faceEngine.getActiveFileInfo(activeFileInfo);
+ System.out.println("获取激活文件errorCode:" + errorCode);
+ System.out.println("激活文件信息:" + activeFileInfo.toString());
+
+ //引擎配置
+ EngineConfiguration engineConfiguration = new EngineConfiguration();
+ engineConfiguration.setDetectMode(DetectMode.ASF_DETECT_MODE_IMAGE);
+ engineConfiguration.setDetectFaceOrientPriority(DetectOrient.ASF_OP_ALL_OUT);
+ engineConfiguration.setDetectFaceMaxNum(10);
+ //功能配置
+ FunctionConfiguration functionConfiguration = new FunctionConfiguration();
+ functionConfiguration.setSupportAge(true);
+ functionConfiguration.setSupportFaceDetect(true);
+ functionConfiguration.setSupportFaceRecognition(true);
+ functionConfiguration.setSupportGender(true);
+ functionConfiguration.setSupportLiveness(true);
+ functionConfiguration.setSupportIRLiveness(true);
+ functionConfiguration.setSupportImageQuality(true);
+ functionConfiguration.setSupportMaskDetect(true);
+ functionConfiguration.setSupportUpdateFaceData(true);
+ engineConfiguration.setFunctionConfiguration(functionConfiguration);
+
+ //初始化引擎
+ errorCode = faceEngine.init(engineConfiguration);
+ System.out.println("初始化引擎errorCode:" + errorCode);
+ VersionInfo version = faceEngine.getVersion();
+ System.out.println(version);
+
+ //人脸检测
+ ImageInfo imageInfo = ImageFactory.getRGBData(new File("/home/huangyifang/gb/咸阳师范/10.jpg"));
+ List faceInfoList = new ArrayList();
+ errorCode = faceEngine.detectFaces(imageInfo, faceInfoList);
+ System.out.println("人脸检测errorCode:" + errorCode);
+ System.out.println("检测到人脸数:" + faceInfoList.size());
+
+ ImageQuality imageQuality = new ImageQuality();
+ errorCode = faceEngine.imageQualityDetect(imageInfo, faceInfoList.get(0), 0, imageQuality);
+ System.out.println("图像质量检测errorCode:" + errorCode);
+ System.out.println("图像质量分数:" + imageQuality.getFaceQuality());
+
+ //特征提取
+ FaceFeature faceFeature = new FaceFeature();
+ errorCode = faceEngine.extractFaceFeature(imageInfo, faceInfoList.get(0), ExtractType.REGISTER, 0, faceFeature);
+ System.out.println("特征提取errorCode:" + errorCode);
+
+ //人脸检测2
+ ImageInfo imageInfo2 = ImageFactory.getRGBData(new File("/home/huangyifang/gb/咸阳师范/10.jpg"));
+ List faceInfoList2 = new ArrayList();
+ errorCode = faceEngine.detectFaces(imageInfo2, faceInfoList2);
+ System.out.println("人脸检测errorCode:" + errorCode);
+ System.out.println("检测到人脸数:" + faceInfoList.size());
+
+ //特征提取2
+ FaceFeature faceFeature2 = new FaceFeature();
+ errorCode = faceEngine.extractFaceFeature(imageInfo2, faceInfoList2.get(0), ExtractType.RECOGNIZE, 0, faceFeature2);
+ System.out.println("特征提取errorCode:" + errorCode);
+
+ //特征比对
+ FaceFeature targetFaceFeature = new FaceFeature();
+ targetFaceFeature.setFeatureData(faceFeature.getFeatureData());
+ FaceFeature sourceFaceFeature = new FaceFeature();
+ sourceFaceFeature.setFeatureData(faceFeature2.getFeatureData());
+ FaceSimilar faceSimilar = new FaceSimilar();
+
+ errorCode = faceEngine.compareFaceFeature(targetFaceFeature, sourceFaceFeature, faceSimilar);
+ System.out.println("特征比对errorCode:" + errorCode);
+ System.out.println("人脸相似度:" + faceSimilar.getScore());
+
+
+ //人脸属性检测
+ FunctionConfiguration configuration = new FunctionConfiguration();
+ configuration.setSupportAge(true);
+ configuration.setSupportGender(true);
+ configuration.setSupportLiveness(true);
+ configuration.setSupportMaskDetect(true);
+ errorCode = faceEngine.process(imageInfo, faceInfoList, configuration);
+ System.out.println("图像属性处理errorCode:" + errorCode);
+
+ //性别检测
+ List genderInfoList = new ArrayList();
+ errorCode = faceEngine.getGender(genderInfoList);
+ System.out.println("性别:" + genderInfoList.get(0).getGender());
+
+ //年龄检测
+ List ageInfoList = new ArrayList();
+ errorCode = faceEngine.getAge(ageInfoList);
+ System.out.println("年龄:" + ageInfoList.get(0).getAge());
+
+ //活体检测
+ List livenessInfoList = new ArrayList();
+ errorCode = faceEngine.getLiveness(livenessInfoList);
+ System.out.println("活体:" + livenessInfoList.get(0).getLiveness());
+
+ //口罩检测
+ List maskInfoList = new ArrayList();
+ errorCode = faceEngine.getMask(maskInfoList);
+ System.out.println("口罩:" + maskInfoList.get(0).getMask());
+
+
+ //IR属性处理
+ ImageInfo imageInfoGray = ImageFactory.getGrayData(new File("/home/huangyifang/gb/咸阳师范/10.jpg"));
+ List faceInfoListGray = new ArrayList();
+ errorCode = faceEngine.detectFaces(imageInfoGray, faceInfoListGray);
+
+ FunctionConfiguration configuration2 = new FunctionConfiguration();
+ configuration2.setSupportIRLiveness(true);
+ errorCode = faceEngine.processIr(imageInfoGray, faceInfoListGray, configuration2);
+ //IR活体检测
+ List irLivenessInfo = new ArrayList<>();
+ errorCode = faceEngine.getLivenessIr(irLivenessInfo);
+ System.out.println("IR活体:" + irLivenessInfo.get(0).getLiveness());
+
+ //获取激活文件信息
+ ActiveFileInfo activeFileInfo2 = new ActiveFileInfo();
+ errorCode = faceEngine.getActiveFileInfo(activeFileInfo2);
+
+ //更新人脸数据
+ errorCode = faceEngine.updateFaceData(imageInfo, faceInfoList);
+
+ //高级人脸图像处理接口
+ ImageInfoEx imageInfoEx = new ImageInfoEx();
+ imageInfoEx.setHeight(imageInfo.getHeight());
+ imageInfoEx.setWidth(imageInfo.getWidth());
+ imageInfoEx.setImageFormat(imageInfo.getImageFormat());
+ imageInfoEx.setImageDataPlanes(new byte[][]{imageInfo.getImageData()});
+ imageInfoEx.setImageStrides(new int[]{imageInfo.getWidth() * 3});
+ List faceInfoList1 = new ArrayList<>();
+ errorCode = faceEngine.detectFaces(imageInfoEx, DetectModel.ASF_DETECT_MODEL_RGB, faceInfoList1);
+ ImageQuality imageQuality1 = new ImageQuality();
+ errorCode = faceEngine.imageQualityDetect(imageInfoEx, faceInfoList1.get(0), 0, imageQuality1);
+ FunctionConfiguration fun = new FunctionConfiguration();
+ fun.setSupportAge(true);
+ errorCode = faceEngine.process(imageInfoEx, faceInfoList1, fun);
+ List ageInfoList1 = new ArrayList<>();
+ int age = faceEngine.getAge(ageInfoList1);
+ FaceFeature feature = new FaceFeature();
+ errorCode = faceEngine.extractFaceFeature(imageInfoEx, faceInfoList1.get(0), ExtractType.REGISTER, 0, feature);
+ errorCode = faceEngine.updateFaceData(imageInfoEx, faceInfoList1);
+
+ //设置活体测试
+ errorCode = faceEngine.setLivenessParam(0.5f, 0.7f, 0.3f);
+ System.out.println("设置活体活体阈值errorCode:" + errorCode);
+
+ LivenessParam livenessParam=new LivenessParam();
+ errorCode = faceEngine.getLivenessParam(livenessParam);
+
+ //注册人脸信息1
+ FaceFeatureInfo faceFeatureInfo = new FaceFeatureInfo();
+ faceFeatureInfo.setSearchId(5);
+ faceFeatureInfo.setFaceTag("FeatureData1");
+ faceFeatureInfo.setFeatureData(faceFeature.getFeatureData());
+ errorCode = faceEngine.registerFaceFeature(faceFeatureInfo);
+
+ //注册人脸信息2
+ FaceFeatureInfo faceFeatureInfo2 = new FaceFeatureInfo();
+ faceFeatureInfo2.setSearchId(6);
+ faceFeatureInfo2.setFaceTag("FeatureData2");
+ faceFeatureInfo2.setFeatureData(faceFeature2.getFeatureData());
+ errorCode = faceEngine.registerFaceFeature(faceFeatureInfo2);
+
+ //获取注册人脸个数
+ FaceSearchCount faceSearchCount = new FaceSearchCount();
+ errorCode = faceEngine.getFaceCount(faceSearchCount);
+ System.out.println("注册人脸个数:" + faceSearchCount.getCount());
+
+ //搜索最相似人脸
+ SearchResult searchResult = new SearchResult();
+ errorCode = faceEngine.searchFaceFeature(faceFeature, CompareModel.LIFE_PHOTO, searchResult);
+ System.out.println("最相似人脸Id:" + searchResult.getFaceFeatureInfo().getSearchId());
+
+ //更新人脸信息
+ FaceFeatureInfo faceFeatureInfo3 = new FaceFeatureInfo();
+ faceFeatureInfo3.setSearchId(6);
+ faceFeatureInfo3.setFaceTag("FeatureData2Update");
+ faceFeatureInfo3.setFeatureData(faceFeature2.getFeatureData());
+ errorCode = faceEngine.updateFaceFeature(faceFeatureInfo3);
+
+ //移除人脸信息
+ errorCode = faceEngine.removeFaceFeature(6);
+
+ //引擎卸载
+ errorCode = faceEngine.unInit();
+
+
+ }
+}
\ No newline at end of file
diff --git a/login/src/main/java/com/guwan/face/util/UserInfo.java b/login/src/main/java/com/guwan/face/util/UserInfo.java
new file mode 100644
index 0000000..a5f3bba
--- /dev/null
+++ b/login/src/main/java/com/guwan/face/util/UserInfo.java
@@ -0,0 +1,11 @@
+package com.guwan.face.util;
+
+
+import lombok.Data;
+
+@Data
+public class UserInfo {
+ private String faceId;
+ private String name;
+ private byte[] faceFeature;
+}
diff --git a/login/src/main/java/com/guwan/face/util/UserRamCache.java b/login/src/main/java/com/guwan/face/util/UserRamCache.java
new file mode 100644
index 0000000..911fa7a
--- /dev/null
+++ b/login/src/main/java/com/guwan/face/util/UserRamCache.java
@@ -0,0 +1,66 @@
+package com.guwan.face.util;
+
+import com.google.common.collect.Lists;
+
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+public class UserRamCache {
+
+ private final ConcurrentHashMap USER_INFO_MAP = new ConcurrentHashMap<>();
+
+ private final Set REGISTER = new CopyOnWriteArraySet<>();
+
+ public void addUser(UserInfo userInfo) {
+ USER_INFO_MAP.put(userInfo.getFaceId(), userInfo);
+ for (Listener listener : REGISTER) {
+ listener.onAdd(userInfo);
+ }
+ }
+
+ public void removeUser(String faceId) {
+ UserInfo userInfo = USER_INFO_MAP.remove(faceId);
+ for (Listener listener : REGISTER) {
+ listener.onRemove(userInfo);
+ }
+ }
+
+ public List getUserList() {
+ List userInfoList = Lists.newLinkedList();
+ userInfoList.addAll(USER_INFO_MAP.values());
+ return userInfoList;
+ }
+
+ public void clear(){
+ USER_INFO_MAP.clear();
+ REGISTER.clear();
+ }
+
+ public void addListener(Listener listener) {
+ REGISTER.add(listener);
+ }
+
+ public void removeListener(Listener listener) {
+ REGISTER.remove(listener);
+ }
+
+// @Data
+// public class UserInfo {
+//
+// private String faceId;
+// private String name;
+// private byte[] faceFeature;
+//
+// }
+
+ public interface Listener {
+ default void onAdd(UserInfo userInfo) {
+ }
+
+ default void onRemove(UserInfo userInfo) {
+
+ }
+ }
+}
diff --git a/login/src/main/java/com/guwan/face/util/UserRamGroup.java b/login/src/main/java/com/guwan/face/util/UserRamGroup.java
new file mode 100644
index 0000000..429724b
--- /dev/null
+++ b/login/src/main/java/com/guwan/face/util/UserRamGroup.java
@@ -0,0 +1,42 @@
+package com.guwan.face.util;
+
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class UserRamGroup {
+
+ private static final ConcurrentHashMap USER_RAM_GROUP_MAP = new ConcurrentHashMap<>();
+ private static final ConcurrentHashMap ORG_CELL_MAP = new ConcurrentHashMap<>();
+
+ public static void addCell(String cellId){
+ UserRamCache cell = new UserRamCache();
+ USER_RAM_GROUP_MAP.put(cellId,cell);
+ }
+
+ public static void removeCell(String cellId){
+ USER_RAM_GROUP_MAP.remove(cellId);
+ }
+
+ public static void addUser(UserInfo userInfo, String cellId) {
+ USER_RAM_GROUP_MAP.get(cellId).addUser(userInfo);
+ }
+
+ public static void removeUser(String faceId, String cellId) {
+ USER_RAM_GROUP_MAP.get(cellId).removeUser(faceId);
+ }
+
+ public static List getUserList(String cellId) {
+ return USER_RAM_GROUP_MAP.get(cellId).getUserList();
+ }
+
+ public static void addOrgId(String orgId,String cellId){
+ ORG_CELL_MAP.put(orgId,cellId);
+ }
+ public static String getOrgCellMap(String orgId) {
+ return ORG_CELL_MAP.get(orgId);
+ }
+
+ public static void clear(){
+ USER_RAM_GROUP_MAP.clear();
+ }
+}
diff --git a/login/src/main/java/com/guwan/util/PathUtil.java b/login/src/main/java/com/guwan/util/PathUtil.java
new file mode 100644
index 0000000..fab958a
--- /dev/null
+++ b/login/src/main/java/com/guwan/util/PathUtil.java
@@ -0,0 +1,12 @@
+package com.guwan.util;
+
+public class PathUtil {
+
+ public static String path(){
+ return System.getProperty("user.dir") + "\\Guwan\\";
+ }
+
+ public static String path(String path){
+ return System.getProperty("user.dir") + "\\Guwan\\" + path;
+ }
+}
diff --git a/login/src/main/resources/application.yml b/login/src/main/resources/application.yml
index 4ace2f2..ad1fe7e 100644
--- a/login/src/main/resources/application.yml
+++ b/login/src/main/resources/application.yml
@@ -9,10 +9,12 @@ spring:
password: aliredis666
database: 1
datasource:
- driver-class-name: com.mysql.cj.jdbc.Driver
- url: jdbc:mysql://127.0.0.1:3306/studb
- username: root
- password: 123456
+ druid:
+ driver-class-name: com.mysql.cj.jdbc.Driver
+ url: jdbc:mysql://127.0.0.1:3306/studb
+ username: root
+ password: X1p6x5irECRCLpqsOAIjh1w4VBPK0x3AP1WNNz8xVmhGx98BANEsw2KQKmBIagzCVo6aBrveoHwWa6FA9gXcwQ==
+ connection-properties: config.decrypt=true;config.decrypt.key=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIQ/kwu9OapBDTOTUzM7CGWbbo2+qfCybUDctQcKeGptz8nhQYAzsU9JyfaDQE9RhFj7pwwD8JgB4qJWycicdXcCAwEAAQ==
servlet:
multipart:
@@ -50,4 +52,20 @@ global:
port: 9000
accessKey: admin
secretKey: admin123456
- bucketName: cuwan
\ No newline at end of file
+ bucketName: cuwan
+
+ file_path:
+ static-locations: \Guwan\
+
+
+config:
+ arcface-sdk:
+ version: 4.1
+ app-id: FnMJV3NVD5ddwF43mdjNDLWPJwXjLAcp8qJDdkaijus4
+ sdk-key: AWJo7q7994q97qHrXKvZ54mAADcrkLvEBLZ1voPdUxZE
+ active-key: 86L1-11RL-613B-GT8B #本机
+ active-file:
+ detect-pool-size: 16
+ compare-pool-size: 16
+ rec-face-thd: 0.8
+ rec-id-thd: 0.5
\ No newline at end of file
diff --git a/login/src/main/resources/banner.txt b/login/src/main/resources/banner.txt
new file mode 100644
index 0000000..189afd3
--- /dev/null
+++ b/login/src/main/resources/banner.txt
@@ -0,0 +1 @@
+零基础!学挨踢!!月薪过ONE!!!
\ No newline at end of file
diff --git a/login/src/test/java/com/guwan/EncryptPwdUtil.java b/login/src/test/java/com/guwan/EncryptPwdUtil.java
new file mode 100644
index 0000000..e9fef0f
--- /dev/null
+++ b/login/src/test/java/com/guwan/EncryptPwdUtil.java
@@ -0,0 +1,19 @@
+package com.guwan;
+
+import com.alibaba.druid.filter.config.ConfigTools;
+
+public class EncryptPwdUtil {
+
+ public static void main(String[] args) {
+ try {
+ String password = "123456";
+ String[] arr = ConfigTools.genKeyPair(512);
+
+ // System.out.println("privateKey:" + arr[0]);
+ System.out.println("publicKey:" + arr[1]);
+ System.out.println("password:" + ConfigTools.encrypt(arr[0], password));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
\ No newline at end of file