人脸提取特征值(后台服务--公司版)

This commit is contained in:
jjLv 2025-09-22 17:33:20 +08:00
parent be5c5a8b86
commit eb5c31e5a9
3 changed files with 178 additions and 35 deletions

View File

@ -1,13 +1,17 @@
package com.bonus.canteen.core.kitchen.service.impl;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bonus.canteen.core.common.utils.FileUrlUtil;
import com.bonus.canteen.core.common.utils.MqUtil;
import com.bonus.canteen.core.kitchen.domain.KitchenStaffFace;
import com.bonus.canteen.core.kitchen.mapper.KitchenStaffFaceMapper;
import com.bonus.canteen.core.kitchen.service.IKitchenStaffFaceService;
import com.bonus.canteen.core.user.domain.DeviceMqPersonalUpdateMessageDTO;
import com.bonus.canteen.core.user.domain.UserFace;
import com.bonus.canteen.core.user.utils.ArcFaceHelper;
import com.bonus.canteen.core.user.utils.FaceFeatureDetector;
import com.bonus.canteen.core.user.utils.FaceResult;
import com.bonus.common.core.exception.ServiceException;
import com.bonus.common.core.utils.DateUtils;
@ -57,16 +61,29 @@ public class KitchenStaffFaceServiceImpl implements IKitchenStaffFaceService {
DeviceMqPersonalUpdateMessageDTO bean = new DeviceMqPersonalUpdateMessageDTO().setUpdatePersonPhoto(dto.getStaffId().intValue(),"del");
MqUtil.pushToTenantAllDevice(bean, LeMqConstant.Topic.MORNING_INSPECTION_DEVICE_UPDATE_PERSONAL_CONFIG_V4);
} else {
log.info("开始采集虹软人脸");
ArcFaceHelper arcFaceHelper = new ArcFaceHelper();
long startTime = System.currentTimeMillis();
//发送请求 调用人脸特征提取接口
String url = FileUrlUtil.getFileUrl(dto.getPhotoUrl());
FaceResult faceResult = arcFaceHelper.getFaceFeatures(url);
log.info("采集结束");
System.out.println("人脸特征提取url" + url);
String response = FaceFeatureDetector.detectFaceFeature(url);
System.out.println("人脸特征提取接口返回结果:" + response);
JSONObject jsonResponse = JSONObject.parseObject(response.toString());
if (jsonResponse.getInteger("code") != 30002) {
System.out.println("人脸特征提取失败," + jsonResponse.getString("msg"));
log.error("人脸特征提取失败,{}", jsonResponse.getString("msg"));
throw new ServiceException("人脸特征提取失败," + jsonResponse.getString("msg"));
}
long endTime = System.currentTimeMillis();
System.out.println("人脸特征提取耗时:" + (endTime - startTime) + "ms");
List<KitchenStaffFace> list = new ArrayList<>();
if (faceResult != null) {
String dataStr = jsonResponse.getString("data");
// 将data字符串解析为JSONArray
JSONArray dataArray = JSONArray.parseArray(dataStr);
if (dataArray != null && !dataArray.isEmpty()) {
Object faceFeature = dataArray.get(0);
KitchenStaffFace faceVO = new KitchenStaffFace();
faceVO.setErrorMsg("[软件]成功");
faceVO.setFeatures(Base64.getEncoder().encodeToString(faceResult.getFeatures()));
faceVO.setFeatures(faceFeature.toString());
faceVO.setCreateBy(String.valueOf(SecurityUtils.getUserId()));
faceVO.setStaffId(dto.getStaffId());
faceVO.setPhotoUrl(dto.getPhotoUrl());
@ -75,18 +92,17 @@ public class KitchenStaffFaceServiceImpl implements IKitchenStaffFaceService {
faceVO.setCreateTime(DateUtils.getTime());
faceVO.setUpdateTime(DateUtils.getTime());
list.add(faceVO);
log.info("faceResult.getFeatures():" + Base64.getEncoder().encodeToString(faceResult.getFeatures()));
log.info("人脸采集成功");
} else {
throw new ServiceException("人脸照片识别失败");
int code = kitchenStaffFaceMapper.insertStaffFace(list.get(0));
if (code == 0) {
System.out.println("[人脸识别算法]:保存失败");
log.error("[人脸识别算法]:保存失败");
throw new ServiceException("[人脸识别算法]:保存失败");
}
DeviceMqPersonalUpdateMessageDTO bean = new DeviceMqPersonalUpdateMessageDTO().setUpdatePersonPhoto(dto.getStaffId().intValue(),"update");
MqUtil.pushToTenantAllDevice(bean, LeMqConstant.Topic.MORNING_INSPECTION_DEVICE_UPDATE_PERSONAL_CONFIG_V4);
}else{
throw new ServiceException("人脸特征提取失败,未检测到人脸");
}
int code = kitchenStaffFaceMapper.insertStaffFace(list.get(0));
if (code == 0){
throw new ServiceException("人脸照片保存失败");
}
// //发送mq
DeviceMqPersonalUpdateMessageDTO bean = new DeviceMqPersonalUpdateMessageDTO().setUpdatePersonPhoto(dto.getStaffId().intValue(),"update");
MqUtil.pushToTenantAllDevice(bean, LeMqConstant.Topic.MORNING_INSPECTION_DEVICE_UPDATE_PERSONAL_CONFIG_V4);
}
return AjaxResult.success();
}

View File

@ -1,15 +1,22 @@
package com.bonus.canteen.core.user.service.impl;
import java.beans.FeatureDescriptor;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bonus.canteen.core.common.utils.FileUrlUtil;
import com.bonus.canteen.core.common.utils.HttpClient;
import com.bonus.canteen.core.common.utils.MqUtil;
import com.bonus.canteen.core.user.domain.DeviceMqPersonalUpdateMessageDTO;
import com.bonus.canteen.core.user.utils.ArcFaceHelper;
import com.bonus.canteen.core.user.utils.FaceFeatureDetector;
import com.bonus.canteen.core.user.utils.FaceResult;
import com.bonus.common.core.exception.ServiceException;
import com.bonus.common.core.utils.DateUtils;
@ -46,6 +53,7 @@ public class UserFaceServiceImpl implements IUserFaceService {
*/
@Override
public AjaxResult uploadUserFace(UserFace dto) {
System.out.println("开始人脸识别");
if (ObjectUtil.isNull(dto)) {
throw new ServiceException("参数为空!");
}
@ -55,19 +63,32 @@ public class UserFaceServiceImpl implements IUserFaceService {
if (StringUtils.isEmpty(dto.getPhotoUrl())) {
userFaceMapper.deleteUserFace(dto);
//发送mq
DeviceMqPersonalUpdateMessageDTO bean = new DeviceMqPersonalUpdateMessageDTO().setUpdatePersonPhoto(dto.getUserId().intValue(),"del");
DeviceMqPersonalUpdateMessageDTO bean = new DeviceMqPersonalUpdateMessageDTO().setUpdatePersonPhoto(dto.getUserId().intValue(), "del");
MqUtil.pushToTenantAllDevice(bean, LeMqConstant.Topic.DEVICE_UPDATE_PERSONAL_CONFIG_V4);
} else {
log.info("开始采集虹软人脸");
ArcFaceHelper arcFaceHelper = new ArcFaceHelper();
long startTime = System.currentTimeMillis();
//发送请求 调用人脸特征提取接口
String url = FileUrlUtil.getFileUrl(dto.getPhotoUrl());
FaceResult faceResult = arcFaceHelper.getFaceFeatures(url);
log.info("采集结束");
System.out.println("人脸特征提取url" + url);
String response = FaceFeatureDetector.detectFaceFeature(url);
System.out.println("人脸特征提取接口返回结果:" + response);
JSONObject jsonResponse = JSONObject.parseObject(response.toString());
if (jsonResponse.getInteger("code") != 30002) {
System.out.println("人脸特征提取失败," + jsonResponse.getString("msg"));
log.error("人脸特征提取失败,{}", jsonResponse.getString("msg"));
throw new ServiceException("人脸特征提取失败," + jsonResponse.getString("msg"));
}
long endTime = System.currentTimeMillis();
System.out.println("人脸特征提取耗时:" + (endTime - startTime) + "ms");
List<UserFace> list = new ArrayList<>();
if (faceResult != null) {
String dataStr = jsonResponse.getString("data");
// 将data字符串解析为JSONArray
JSONArray dataArray = JSONArray.parseArray(dataStr);
if (dataArray != null && !dataArray.isEmpty()) {
Object faceFeature = dataArray.get(0);
UserFace faceVO = new UserFace();
faceVO.setErrorMsg("[软件]成功");
faceVO.setFeatures(Base64.getEncoder().encodeToString(faceResult.getFeatures()));
faceVO.setFeatures(faceFeature.toString());
faceVO.setCreateBy(String.valueOf(SecurityUtils.getUserId()));
faceVO.setUserId(dto.getUserId());
faceVO.setPhotoUrl(dto.getPhotoUrl());
@ -76,18 +97,17 @@ public class UserFaceServiceImpl implements IUserFaceService {
faceVO.setCreateTime(DateUtils.getTime());
faceVO.setUpdateTime(DateUtils.getTime());
list.add(faceVO);
log.info("faceResult.getFeatures():" + Base64.getEncoder().encodeToString(faceResult.getFeatures()));
log.info("人脸采集成功");
} else {
throw new ServiceException("[虹软算法]:特征值提取失败");
int code = userFaceMapper.insertUserFace(list.get(0));
if (code == 0) {
System.out.println("[人脸识别算法]:保存失败");
log.error("[人脸识别算法]:保存失败");
throw new ServiceException("[人脸识别算法]:保存失败");
}
DeviceMqPersonalUpdateMessageDTO bean = new DeviceMqPersonalUpdateMessageDTO().setUpdatePersonPhoto(dto.getUserId().intValue(), "update");
MqUtil.pushToTenantAllDevice(bean, LeMqConstant.Topic.DEVICE_UPDATE_PERSONAL_CONFIG_V4);
}else{
throw new ServiceException("人脸特征提取失败,未检测到人脸");
}
int code = userFaceMapper.insertUserFace(list.get(0));
if (code == 0){
throw new ServiceException("[虹软算法]:保存失败");
}
//发送mq
DeviceMqPersonalUpdateMessageDTO bean = new DeviceMqPersonalUpdateMessageDTO().setUpdatePersonPhoto(dto.getUserId().intValue(),"update");
MqUtil.pushToTenantAllDevice(bean, LeMqConstant.Topic.DEVICE_UPDATE_PERSONAL_CONFIG_V4);
}
return AjaxResult.success();
}

View File

@ -0,0 +1,107 @@
package com.bonus.canteen.core.user.utils;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class FaceFeatureDetector {
/**
* 检测人脸特征
* @param imageInput 图片路径base64编码或URL
* @return 服务器响应
*/
public static String detectFaceFeature(String imageInput) {
String apiUrl = "http://10.145.136.229:16699/featuredetect/";
try {
// 判断输入类型
String imgType = determineImageInputType(imageInput);
String imgData;
if ("path".equals(imgType)) {
// 如果是本地路径读取文件并转为base64
imgData = fileToBase64(imageInput);
} else {
// 如果是base64或URL直接使用
imgData = imageInput;
}
// 创建JSON请求体
String jsonInputString = String.format("{\"img\":\"%s\"}", imgData);
// 创建连接
URL url = new URL(apiUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json; utf-8");
connection.setRequestProperty("Accept", "application/json");
connection.setDoOutput(true);
// 发送请求
try (OutputStream os = connection.getOutputStream()) {
byte[] input = jsonInputString.getBytes(StandardCharsets.UTF_8);
os.write(input, 0, input.length);
}
// 获取响应
StringBuilder response = new StringBuilder();
try (BufferedReader br = new BufferedReader(
new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {
String responseLine;
while ((responseLine = br.readLine()) != null) {
response.append(responseLine.trim());
}
}
return response.toString();
} catch (IOException e) {
e.printStackTrace();
return "{\"code\":\"500\",\"msg\":\"请求失败: " + e.getMessage() + "\"}";
}
}
/**
* 判断图片输入类型
* @param input 输入字符串
* @return 类型path, base64, url
*/
private static String determineImageInputType(String input) {
// 检查是否是文件路径
if (new File(input).exists()) {
return "path";
}
// 检查是否是base64编码简单检查
if (input.matches("^[A-Za-z0-9+/]+={0,2}$")) {
return "base64";
}
// 检查是否是URL
if (input.startsWith("http://") || input.startsWith("https://")) {
return "url";
}
// 默认认为是base64
return "base64";
}
/**
* 将文件转为base64编码
* @param filePath 文件路径
* @return base64编码字符串
* @throws IOException
*/
private static String fileToBase64(String filePath) throws IOException {
File file = new File(filePath);
try (FileInputStream imageInFile = new FileInputStream(file)) {
byte[] fileData = new byte[(int) file.length()];
imageInFile.read(fileData);
return Base64.getEncoder().encodeToString(fileData);
}
}
}