Commit 8a7c9aae authored by 廖旭伟's avatar 廖旭伟

人脸识别1:N比对功能

parent 9fc18906
package com.mortals.xhx.face;
import com.arcsoft.face.*;
import com.arcsoft.face.toolkit.ImageInfo;
import com.google.common.collect.Lists;
import com.mortals.xhx.face.factory.FaceEnginePoolFactory;
import com.mortals.xhx.module.identity.model.SysFaceEntity;
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.pool2.impl.AbandonedConfig;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import static com.arcsoft.face.toolkit.ImageFactory.getRGBData;
@Slf4j
@Component
public class ArcsoftFaceUtil {
@Value(value = "${faceAppId}")
private String appId;
@Value(value = "${winSdkKey}")
private String winSdkKey;
@Value(value = "${linuxSdkkey}")
private String linuxSdkKey;
public Integer threadPoolSize=5;
private GenericObjectPool<FaceEngine> faceEngineGenericObjectPool;
public ArcsoftFaceUtil(){
String sdkLibPath = getClass().getResource(getOsName()).getPath();
String sdkKey = getSdkKey(sdkLibPath);
// 对象池工厂
FaceEnginePoolFactory personPoolFactory = new FaceEnginePoolFactory(appId,sdkKey,sdkLibPath);
// 对象池配置
GenericObjectPoolConfig<FaceEngine> objectPoolConfig = new GenericObjectPoolConfig<>();
objectPoolConfig.setMaxTotal(threadPoolSize);
AbandonedConfig abandonedConfig = new AbandonedConfig();
//在Maintenance的时候检查是否有泄漏
abandonedConfig.setRemoveAbandonedOnMaintenance(true);
//borrow 的时候检查泄漏
abandonedConfig.setRemoveAbandonedOnBorrow(true);
//如果一个对象borrow之后10秒还没有返还给pool,认为是泄漏的对象
abandonedConfig.setRemoveAbandonedTimeout(10);
// 对象池
faceEngineGenericObjectPool = new GenericObjectPool<>(personPoolFactory, objectPoolConfig);
faceEngineGenericObjectPool.setAbandonedConfig(abandonedConfig);
faceEngineGenericObjectPool.setTimeBetweenEvictionRunsMillis(5000); //5秒运行一次维护任务
log.info("引擎池开启成功");
}
private String getOsName() {
String os = System.getProperty("os.name");
String osName = os.toLowerCase().startsWith("win") ? "/face_lib/win64" : "/face_lib/linux";
return osName;
}
private String getSdkKey(String sdkLibPath) {
return sdkLibPath.equals("/face_lib/win64") ? winSdkKey : linuxSdkKey;
}
/**
* 人脸检测
*
* @param fileInputStream
* @return
*/
public List<FaceInfo> faceFind(InputStream fileInputStream) throws IOException {
FaceEngine faceEngine = null;
try {
faceEngine = faceEngineGenericObjectPool.borrowObject();
ImageInfo imageInfo = getRGBData(fileInputStream);
List<FaceInfo> faceInfoList = new ArrayList<FaceInfo>();
int errorCode = faceEngine.detectFaces(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList);
return faceInfoList;
} catch (Exception e) {
log.error("人脸检测出现了异常");
e.printStackTrace();
return new ArrayList<FaceInfo>();
} finally {
fileInputStream.close();
// 回收对象到对象池
if (faceEngine != null) {
faceEngineGenericObjectPool.returnObject(faceEngine);
}
}
}
/**
* 人脸截取
*
* @param fileInputStream
* @param rect
* @return
*/
public String faceCrop(InputStream fileInputStream, Rect rect) {
try {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
BufferedImage bufImage = ImageIO.read(fileInputStream);
int height = bufImage.getHeight();
int width = bufImage.getWidth();
int top = rect.getTop();
int bottom = rect.getBottom();
int left = rect.getLeft();
int right = rect.getRight();
//System.out.println(top + "-" + bottom + "-" + left + "-" + right);
try {
BufferedImage subimage = bufImage.getSubimage(left, top, right - left, bottom - left);
ImageIO.write(subimage, "png", stream);
String base64 = Base64.encode(stream.toByteArray());
return base64;
}catch (Exception e){
return null;
}finally {
stream.close();
fileInputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}finally {
}
return null;
}
/**
* 人脸特征值提取
*/
public byte[] faceFeature(byte[] bytes) {
FaceEngine faceEngine = null;
try {
faceEngine = faceEngineGenericObjectPool.borrowObject();
ImageInfo imageInfo = getRGBData(bytes);
//人脸检测得到人脸列表
List<FaceInfo> faceInfoList = new ArrayList<FaceInfo>();
faceEngine.detectFaces(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList);
FaceFeature faceFeature = new FaceFeature();
faceEngine.extractFaceFeature(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList.get(0), faceFeature);
byte[] featureData = faceFeature.getFeatureData();
return featureData;
} catch (Exception e) {
log.error("人脸特征值提取出现了异常");
e.printStackTrace();
return new byte[0];
} finally {
// 回收对象到对象池
if (faceEngine != null) {
faceEngineGenericObjectPool.returnObject(faceEngine);
}
}
}
/**
* 人脸对比
*/
public float faceCompared(byte [] source,byte [] des) throws IOException {
FaceEngine faceEngine = null;
try {
faceEngine = faceEngineGenericObjectPool.borrowObject();
FaceFeature targetFaceFeature = new FaceFeature();
targetFaceFeature.setFeatureData(source);
FaceFeature sourceFaceFeature = new FaceFeature();
sourceFaceFeature.setFeatureData(des);
FaceSimilar faceSimilar = new FaceSimilar();
faceEngine.compareFaceFeature(targetFaceFeature, sourceFaceFeature, faceSimilar);
float score = faceSimilar.getScore();
return score;
} catch (Exception e) {
log.error("人脸对比出现了异常");
e.printStackTrace();
return 0;
} finally {
// 回收对象到对象池
if (faceEngine != null) {
faceEngineGenericObjectPool.returnObject(faceEngine);
}
}
}
/**
* 人脸搜索
*/
public List<SysFaceEntity> faceSearch(FaceFeature targetFaceFeature,List<SysFaceEntity> sourceList) throws IOException {
FaceEngine faceEngine = null;
List<SysFaceEntity> resultFaceInfoList = Lists.newLinkedList();//识别到的人脸列表
try {
faceEngine = faceEngineGenericObjectPool.borrowObject();
for(SysFaceEntity faceUserInfo : sourceList) {
FaceFeature sourceFaceFeature = new FaceFeature();
sourceFaceFeature.setFeatureData(faceUserInfo.getFaceFeature());
FaceSimilar faceSimilar = new FaceSimilar();
faceEngine.compareFaceFeature(targetFaceFeature, sourceFaceFeature, faceSimilar);
float score = faceSimilar.getScore();
if(score > 0.8){
faceUserInfo.setSimilarValue(plusHundred(score));
resultFaceInfoList.add(faceUserInfo);
}
}
} catch (Exception e) {
log.error("人脸对比出现了异常");
e.printStackTrace();
} finally {
// 回收对象到对象池
if (faceEngine != null) {
faceEngineGenericObjectPool.returnObject(faceEngine);
}
}
return resultFaceInfoList;
}
private int plusHundred(Float value) {
BigDecimal target = new BigDecimal(value);
BigDecimal hundred = new BigDecimal(100f);
return target.multiply(hundred).intValue();
}
}
package com.mortals.xhx.face.factory;
import com.arcsoft.face.ActiveFileInfo;
import com.arcsoft.face.EngineConfiguration;
import com.arcsoft.face.FaceEngine;
import com.arcsoft.face.FunctionConfiguration;
import com.arcsoft.face.enums.DetectMode;
import com.arcsoft.face.enums.DetectOrient;
import com.arcsoft.face.enums.ErrorInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
@Slf4j
public class FaceEnginePoolFactory extends BasePooledObjectFactory<FaceEngine> {
private String appId;
private String sdkKey;
private String sdkLibPath;
public FaceEnginePoolFactory(String appId, String sdkKey, String sdkLibPath) {
this.appId = appId;
this.sdkKey = sdkKey;
this.sdkLibPath = sdkLibPath;
//this.sdkLibPath = "D:\\face\\win64";
}
/**
* 在对象池中创建对象
* @return
* @throws Exception
*/
@Override
public FaceEngine create() throws Exception {
FaceEngine faceEngine = new FaceEngine(sdkLibPath);
//激活引擎
int errorCode = faceEngine.activeOnline(appId, sdkKey);
if (errorCode != ErrorInfo.MOK.getValue() && errorCode != ErrorInfo.MERR_ASF_ALREADY_ACTIVATED.getValue()) {
log.warn("引擎激活失败");
}
ActiveFileInfo activeFileInfo=new ActiveFileInfo();
errorCode = faceEngine.getActiveFileInfo(activeFileInfo);
if (errorCode != ErrorInfo.MOK.getValue() && errorCode != ErrorInfo.MERR_ASF_ALREADY_ACTIVATED.getValue()) {
log.warn("获取激活文件信息失败");
}
//引擎配置
EngineConfiguration engineConfiguration = new EngineConfiguration();
engineConfiguration.setDetectMode(DetectMode.ASF_DETECT_MODE_IMAGE);
engineConfiguration.setDetectFaceOrientPriority(DetectOrient.ASF_OP_ALL_OUT);
engineConfiguration.setDetectFaceMaxNum(10);
engineConfiguration.setDetectFaceScaleVal(16);
//功能配置
FunctionConfiguration functionConfiguration = new FunctionConfiguration();
functionConfiguration.setSupportAge(true);
functionConfiguration.setSupportFace3dAngle(true);
functionConfiguration.setSupportFaceDetect(true);
functionConfiguration.setSupportFaceRecognition(true);
functionConfiguration.setSupportGender(true);
functionConfiguration.setSupportLiveness(true);
functionConfiguration.setSupportIRLiveness(true);
engineConfiguration.setFunctionConfiguration(functionConfiguration);
//初始化引擎
errorCode = faceEngine.init(engineConfiguration);
if (errorCode != ErrorInfo.MOK.getValue()) {
log.error("初始化引擎失败");
}
return faceEngine;
}
/**
* 包装对象
* @param faceEngine
* @return
*/
@Override
public PooledObject<FaceEngine> wrap(FaceEngine faceEngine) {
return new DefaultPooledObject<>(faceEngine);
}
/**
* 销毁对象
* @param faceEngine 对象池
* @throws Exception 异常
*/
@Override
public void destroyObject(PooledObject<FaceEngine> faceEngine) throws Exception {
super.destroyObject(faceEngine);
}
/**
* 校验对象是否可用
* @param faceEngine 对象池
* @return 对象是否可用结果,boolean
*/
@Override
public boolean validateObject(PooledObject<FaceEngine> faceEngine) {
return super.validateObject(faceEngine);
}
/**
* 激活钝化的对象系列操作
* @param faceEngine 对象池
* @throws Exception 异常信息
*/
@Override
public void activateObject(PooledObject<FaceEngine> faceEngine) throws Exception {
super.activateObject(faceEngine);
}
/**
* 钝化未使用的对象
* @param faceEngine 对象池
* @throws Exception 异常信息
*/
@Override
public void passivateObject(PooledObject<FaceEngine> faceEngine) throws Exception {
super.passivateObject(faceEngine);
}
}
package com.mortals.xhx.module.identity.dao;
import com.mortals.framework.dao.ICRUDDao;
import com.mortals.xhx.module.identity.model.PeopleInfoEntity;
import java.util.List;
/**
* 用户信息Dao
* 用户信息 DAO接口
*
* @author zxfei
* @date 2022-08-08
*/
public interface PeopleInfoDao extends ICRUDDao<PeopleInfoEntity,Long>{
}
package com.mortals.xhx.module.identity.dao.ibatis;
import org.springframework.stereotype.Repository;
import com.mortals.xhx.module.identity.dao.PeopleInfoDao;
import com.mortals.xhx.module.identity.model.PeopleInfoEntity;
import java.util.Date;
import com.mortals.framework.dao.ibatis.BaseCRUDDaoMybatis;
import java.util.List;
/**
* 用户信息DaoImpl DAO接口
*
* @author zxfei
* @date 2022-08-08
*/
@Repository("peopleInfoDao")
public class PeopleInfoDaoImpl extends BaseCRUDDaoMybatis<PeopleInfoEntity,Long> implements PeopleInfoDao {
}
package com.mortals.xhx.module.identity.model;
import java.util.Date;
import java.util.List;
import java.util.ArrayList;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.mortals.framework.annotation.Excel;
import com.mortals.framework.model.BaseEntityLong;
import com.mortals.xhx.module.identity.model.vo.PeopleInfoVo;
/**
* 用户信息实体对象
*
* @author zxfei
* @date 2022-08-08
*/
public class PeopleInfoEntity extends PeopleInfoVo {
private static final long serialVersionUID = 1L;
/**
* 姓名
*/
private String name;
/**
* 性别
*/
private String sex;
/**
* 民族
*/
private String nation;
/**
* 出生日期
*/
private String born;
/**
* 地址
*/
private String address;
/**
* 身份证号
*/
private String idCardNo;
/**
* 发证机关
*/
private String grantDept;
/**
* 有效期开始
*/
private String userLifeBegin;
/**
* 有效期结束
*/
private String userLifeEnd;
/**
* 照片
*/
private String photoFileName;
/**
* 手机
*/
private String phone;
/**
*
*/
private String openid;
/**
* 最近登录时间
*/
private Date lastTime;
/**
*
*/
private Date upTime;
/**
* 微信头像
*/
private String icon;
/**
* 微信昵称
*/
private String nickname;
/**
* 身份证正面照片
*/
private String zImg;
/**
* 身份证背面照片
*/
private String bImg;
/**
* 默认选择的站点id
*/
private Long siteid;
/**
* 天府通办用户名
*/
private String username;
public PeopleInfoEntity(){}
/**
* 获取 姓名
* @return String
*/
public String getName(){
return name;
}
/**
* 设置 姓名
* @param name
*/
public void setName(String name){
this.name = name;
}
/**
* 获取 性别
* @return String
*/
public String getSex(){
return sex;
}
/**
* 设置 性别
* @param sex
*/
public void setSex(String sex){
this.sex = sex;
}
/**
* 获取 民族
* @return String
*/
public String getNation(){
return nation;
}
/**
* 设置 民族
* @param nation
*/
public void setNation(String nation){
this.nation = nation;
}
/**
* 获取 出生日期
* @return String
*/
public String getBorn(){
return born;
}
/**
* 设置 出生日期
* @param born
*/
public void setBorn(String born){
this.born = born;
}
/**
* 获取 地址
* @return String
*/
public String getAddress(){
return address;
}
/**
* 设置 地址
* @param address
*/
public void setAddress(String address){
this.address = address;
}
/**
* 获取 身份证号
* @return String
*/
public String getIdCardNo(){
return idCardNo;
}
/**
* 设置 身份证号
* @param idCardNo
*/
public void setIdCardNo(String idCardNo){
this.idCardNo = idCardNo;
}
/**
* 获取 发证机关
* @return String
*/
public String getGrantDept(){
return grantDept;
}
/**
* 设置 发证机关
* @param grantDept
*/
public void setGrantDept(String grantDept){
this.grantDept = grantDept;
}
/**
* 获取 有效期开始
* @return String
*/
public String getUserLifeBegin(){
return userLifeBegin;
}
/**
* 设置 有效期开始
* @param userLifeBegin
*/
public void setUserLifeBegin(String userLifeBegin){
this.userLifeBegin = userLifeBegin;
}
/**
* 获取 有效期结束
* @return String
*/
public String getUserLifeEnd(){
return userLifeEnd;
}
/**
* 设置 有效期结束
* @param userLifeEnd
*/
public void setUserLifeEnd(String userLifeEnd){
this.userLifeEnd = userLifeEnd;
}
/**
* 获取 照片
* @return String
*/
public String getPhotoFileName(){
return photoFileName;
}
/**
* 设置 照片
* @param photoFileName
*/
public void setPhotoFileName(String photoFileName){
this.photoFileName = photoFileName;
}
/**
* 获取 手机
* @return String
*/
public String getPhone(){
return phone;
}
/**
* 设置 手机
* @param phone
*/
public void setPhone(String phone){
this.phone = phone;
}
/**
* 获取
* @return String
*/
public String getOpenid(){
return openid;
}
/**
* 设置
* @param openid
*/
public void setOpenid(String openid){
this.openid = openid;
}
/**
* 获取 最近登录时间
* @return Date
*/
public Date getLastTime(){
return lastTime;
}
/**
* 设置 最近登录时间
* @param lastTime
*/
public void setLastTime(Date lastTime){
this.lastTime = lastTime;
}
/**
* 获取
* @return Date
*/
public Date getUpTime(){
return upTime;
}
/**
* 设置
* @param upTime
*/
public void setUpTime(Date upTime){
this.upTime = upTime;
}
/**
* 获取 微信头像
* @return String
*/
public String getIcon(){
return icon;
}
/**
* 设置 微信头像
* @param icon
*/
public void setIcon(String icon){
this.icon = icon;
}
/**
* 获取 微信昵称
* @return String
*/
public String getNickname(){
return nickname;
}
/**
* 设置 微信昵称
* @param nickname
*/
public void setNickname(String nickname){
this.nickname = nickname;
}
/**
* 获取 身份证正面照片
* @return String
*/
public String getZImg(){
return zImg;
}
/**
* 设置 身份证正面照片
* @param zImg
*/
public void setZImg(String zImg){
this.zImg = zImg;
}
/**
* 获取 身份证背面照片
* @return String
*/
public String getBImg(){
return bImg;
}
/**
* 设置 身份证背面照片
* @param bImg
*/
public void setBImg(String bImg){
this.bImg = bImg;
}
/**
* 获取 默认选择的站点id
* @return Long
*/
public Long getSiteid(){
return siteid;
}
/**
* 设置 默认选择的站点id
* @param siteid
*/
public void setSiteid(Long siteid){
this.siteid = siteid;
}
/**
* 获取 天府通办用户名
* @return String
*/
public String getUsername(){
return username;
}
/**
* 设置 天府通办用户名
* @param username
*/
public void setUsername(String username){
this.username = username;
}
@Override
public int hashCode() {
return this.getId().hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj == null) return false;
if (obj instanceof PeopleInfoEntity) {
PeopleInfoEntity tmp = (PeopleInfoEntity) obj;
if (this.getId() == tmp.getId()) {
return true;
}
}
return false;
}
public String toString(){
StringBuilder sb = new StringBuilder("");
sb.append(",name:").append(getName());
sb.append(",sex:").append(getSex());
sb.append(",nation:").append(getNation());
sb.append(",born:").append(getBorn());
sb.append(",address:").append(getAddress());
sb.append(",idCardNo:").append(getIdCardNo());
sb.append(",grantDept:").append(getGrantDept());
sb.append(",userLifeBegin:").append(getUserLifeBegin());
sb.append(",userLifeEnd:").append(getUserLifeEnd());
sb.append(",photoFileName:").append(getPhotoFileName());
sb.append(",phone:").append(getPhone());
sb.append(",openid:").append(getOpenid());
sb.append(",lastTime:").append(getLastTime());
sb.append(",upTime:").append(getUpTime());
sb.append(",icon:").append(getIcon());
sb.append(",nickname:").append(getNickname());
sb.append(",zImg:").append(getZImg());
sb.append(",bImg:").append(getBImg());
sb.append(",siteid:").append(getSiteid());
sb.append(",username:").append(getUsername());
return sb.toString();
}
public void initAttrValue(){
this.name = "";
this.sex = "";
this.nation = "";
this.born = "";
this.address = "";
this.idCardNo = "";
this.grantDept = "";
this.userLifeBegin = "";
this.userLifeEnd = "";
this.photoFileName = "";
this.phone = "";
this.openid = "微信开放认证id";
this.lastTime = null;
this.upTime = null;
this.icon = "";
this.nickname = "";
this.zImg = "";
this.bImg = "";
this.siteid = 0L;
this.username = "";
}
}
\ No newline at end of file
package com.mortals.xhx.module.identity.model.vo;
import com.mortals.framework.model.BaseEntityLong;
import com.mortals.xhx.module.identity.model.PeopleInfoEntity;
import java.util.ArrayList;
import java.util.List;
/**
* 用户信息视图对象
*
* @author zxfei
* @date 2022-08-08
*/
public class PeopleInfoVo extends BaseEntityLong {
}
\ No newline at end of file
...@@ -11,4 +11,14 @@ import java.util.List; ...@@ -11,4 +11,14 @@ import java.util.List;
*/ */
public class SysFaceVo extends BaseEntityStr { public class SysFaceVo extends BaseEntityStr {
/** 相似度 */
private Integer similarValue;
public Integer getSimilarValue() {
return similarValue;
}
public void setSimilarValue(Integer similarValue) {
this.similarValue = similarValue;
}
} }
\ No newline at end of file
package com.mortals.xhx.module.identity.service;
import com.mortals.framework.exception.AppException;
import com.mortals.framework.service.ICRUDService;
import com.mortals.xhx.module.identity.model.PeopleInfoEntity;
/**
* PeopleInfoService
*
* 用户信息 service接口
*
* @author zxfei
* @date 2022-08-08
*/
public interface PeopleInfoService extends ICRUDService<PeopleInfoEntity,Long>{
/**
* 获取身份详细数据
* @param reqVo
* @return
* @throws AppException
*/
PeopleInfoEntity findPeopleInfo(PeopleInfoEntity reqVo) throws AppException;
}
\ No newline at end of file
...@@ -6,6 +6,7 @@ import com.mortals.xhx.module.identity.model.vo.FaceInfoResVO; ...@@ -6,6 +6,7 @@ import com.mortals.xhx.module.identity.model.vo.FaceInfoResVO;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutionException;
/** /**
* SysFaceService * SysFaceService
...@@ -39,4 +40,12 @@ public interface SysFaceService extends ICRUDService<SysFaceEntity,String>{ ...@@ -39,4 +40,12 @@ public interface SysFaceService extends ICRUDService<SysFaceEntity,String>{
* @return * @return
*/ */
void batchAddFace( List<MultipartFile> files,String placeId,String placeName); void batchAddFace( List<MultipartFile> files,String placeId,String placeName);
/**
* 人脸特征识别
* @param faceFeature
* @return
*/
List<FaceInfoResVO> searchUserByFace(byte[] faceFeature) throws InterruptedException, ExecutionException;
} }
\ No newline at end of file
package com.mortals.xhx.module.identity.service.impl;
import cn.hutool.core.util.IdcardUtil;
import cn.hutool.core.util.PhoneUtil;
import com.mortals.framework.exception.AppException;
import com.mortals.framework.model.Context;
import com.mortals.framework.util.StringUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import com.mortals.framework.service.impl.AbstractCRUDServiceImpl;
import com.mortals.xhx.module.identity.dao.PeopleInfoDao;
import com.mortals.xhx.module.identity.model.PeopleInfoEntity;
import com.mortals.xhx.module.identity.service.PeopleInfoService;
import java.util.List;
/**
* PeopleInfoService
* 用户信息 service实现
*
* @author zxfei
* @date 2022-08-08
*/
@Service("peopleInfoService")
public class PeopleInfoServiceImpl extends AbstractCRUDServiceImpl<PeopleInfoDao, PeopleInfoEntity, Long> implements PeopleInfoService {
@Override
protected void validData(PeopleInfoEntity entity, Context context) throws AppException {
if(StringUtils.isEmpty(entity.getIdCardNo())){
throw new AppException("身份证号不能为空");
}
if(StringUtils.isEmpty(entity.getName())){
throw new AppException("身份证姓名不能为空");
}
if(!IdcardUtil.isValidCard18(entity.getIdCardNo())){
throw new AppException("身份证号码格式不正确");
}
if(StringUtils.isEmpty(entity.getPhone())){
throw new AppException("手机号不能为空");
}
if(!PhoneUtil.isPhone(entity.getPhone())){
throw new AppException("手机号码格式不正确");
}
}
@Override
protected void saveBefore(PeopleInfoEntity entity, Context context) throws AppException {
this.validData(entity, context);
PeopleInfoEntity query = new PeopleInfoEntity();
query.setIdCardNo(entity.getIdCardNo());
List<PeopleInfoEntity> list = dao.getList(query);
if(CollectionUtils.isNotEmpty(list)){
throw new AppException("身份证号码重复");
}
}
@Override
public PeopleInfoEntity findPeopleInfo(PeopleInfoEntity reqVo) throws AppException {
if(StringUtils.isEmpty(reqVo.getIdCardNo())){
throw new AppException("身份证号不能为空");
}
if(!IdcardUtil.isValidCard18(reqVo.getIdCardNo())){
throw new AppException("身份证号码格式不正确");
}
List<PeopleInfoEntity> list = dao.getList(reqVo);
if(CollectionUtils.isEmpty(list)){
throw new AppException("无身份数据");
}
return list.get(0);
}
}
\ No newline at end of file
package com.mortals.xhx.module.identity.service.impl; package com.mortals.xhx.module.identity.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.img.Img; import cn.hutool.core.img.Img;
import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.IdUtil;
import com.arcsoft.face.FaceEngine; import com.arcsoft.face.FaceEngine;
import com.arcsoft.face.FaceFeature;
import com.arcsoft.face.FaceSimilar;
import com.google.common.collect.Lists;
import com.mortals.framework.exception.AppException; import com.mortals.framework.exception.AppException;
import com.mortals.framework.model.Context; import com.mortals.framework.model.Context;
import com.mortals.framework.service.impl.AbstractCRUDServiceImpl; import com.mortals.framework.service.impl.AbstractCRUDServiceImpl;
import com.mortals.framework.util.StringUtils; import com.mortals.framework.util.StringUtils;
import com.mortals.xhx.common.utils.FaceUtil; import com.mortals.xhx.common.utils.FaceUtil;
import com.mortals.xhx.face.ArcsoftFaceUtil;
import com.mortals.xhx.module.identity.dao.SysFaceDao; import com.mortals.xhx.module.identity.dao.SysFaceDao;
import com.mortals.xhx.module.identity.model.SysFaceEntity; import com.mortals.xhx.module.identity.model.SysFaceEntity;
import com.mortals.xhx.module.identity.model.SysIdentityEntity; import com.mortals.xhx.module.identity.model.SysIdentityEntity;
...@@ -22,12 +27,14 @@ import org.springframework.stereotype.Service; ...@@ -22,12 +27,14 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import javax.annotation.PostConstruct;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.Base64; import java.util.Base64;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.concurrent.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
...@@ -40,6 +47,8 @@ import java.util.stream.Collectors; ...@@ -40,6 +47,8 @@ import java.util.stream.Collectors;
@Service("sysFaceService") @Service("sysFaceService")
public class SysFaceServiceImpl extends AbstractCRUDServiceImpl<SysFaceDao, SysFaceEntity, String> implements SysFaceService { public class SysFaceServiceImpl extends AbstractCRUDServiceImpl<SysFaceDao, SysFaceEntity, String> implements SysFaceService {
private Integer passRate = 80;
public static final int WIDTH = 100; public static final int WIDTH = 100;
public static final int HEIGHT = 100; public static final int HEIGHT = 100;
...@@ -52,12 +61,24 @@ public class SysFaceServiceImpl extends AbstractCRUDServiceImpl<SysFaceDao, SysF ...@@ -52,12 +61,24 @@ public class SysFaceServiceImpl extends AbstractCRUDServiceImpl<SysFaceDao, SysF
@Value(value = "${linuxSdkkey}") @Value(value = "${linuxSdkkey}")
private String linuxSdkKey; private String linuxSdkKey;
public Integer threadPoolSize = 5;
@Autowired @Autowired
private FaceUtil faceUtil; private FaceUtil faceUtil;
@Autowired @Autowired
private SysIdentityService sysIdentityService; private SysIdentityService sysIdentityService;
@Autowired
private ArcsoftFaceUtil arcsoftFaceUtil;
private ExecutorService executorService;
@PostConstruct
public void init() {
executorService = Executors.newFixedThreadPool(threadPoolSize);
}
@Override @Override
protected void saveBefore(SysFaceEntity entity, Context context) throws AppException { protected void saveBefore(SysFaceEntity entity, Context context) throws AppException {
//非系统自增,需这里设置主键 //非系统自增,需这里设置主键
...@@ -168,4 +189,60 @@ public class SysFaceServiceImpl extends AbstractCRUDServiceImpl<SysFaceDao, SysF ...@@ -168,4 +189,60 @@ public class SysFaceServiceImpl extends AbstractCRUDServiceImpl<SysFaceDao, SysF
private String getSdkKey() { private String getSdkKey() {
return faceUtil.getOsName().equals("/win") ? winSdkKey : linuxSdkKey; return faceUtil.getOsName().equals("/win") ? winSdkKey : linuxSdkKey;
} }
@Override
public List<FaceInfoResVO> searchUserByFace(byte[] bytes) throws InterruptedException, ExecutionException{
List<SysFaceEntity> resultFaceInfoList = Lists.newLinkedList();//识别到的人脸列表
byte[] faceFeature = arcsoftFaceUtil.faceFeature(bytes);
FaceFeature targetFaceFeature = new FaceFeature();
targetFaceFeature.setFeatureData(faceFeature);
List<SysFaceEntity> faceInfoList = this.find(new SysFaceEntity());
List<List<SysFaceEntity>> faceUserInfoPartList = Lists.partition(faceInfoList, 1000);//分成1000一组,多线程处理
CompletionService<List<SysFaceEntity>> completionService = new ExecutorCompletionService(executorService);
for (List<SysFaceEntity> part : faceUserInfoPartList) {
completionService.submit(new CompareFaceTask(part, targetFaceFeature));
}
for (int i = 0; i < faceUserInfoPartList.size(); i++) {
List<SysFaceEntity> faceUserInfoList = completionService.take().get();
if (CollectionUtil.isNotEmpty(faceInfoList)) {
resultFaceInfoList.addAll(faceUserInfoList);
}
}
resultFaceInfoList.sort((h1, h2) -> h2.getSimilarValue().compareTo(h1.getSimilarValue()));//从大到小排序
return resultFaceInfoList.stream().map(o -> {
FaceInfoResVO resVO = new FaceInfoResVO();
SysIdentityEntity resVO1 = sysIdentityService.findIdEntityDetail(o.getIdCard(), 1);
resVO.setId(o.getId());
resVO.setPlaceId(o.getPlaceId());
resVO.setPlaceName(o.getPlaceName());
resVO.setCardId(resVO1.getId());
resVO.setName(resVO1.getName());
resVO.setPhone(resVO1.getPhone());
resVO.setFace(Base64.getEncoder().encodeToString(o.getFace()));
resVO.setFaceFeature(Base64.getEncoder().encodeToString(o.getFaceFeature()));
return resVO;
}).collect(Collectors.toList());
}
private class CompareFaceTask implements Callable<List<SysFaceEntity>> {
private List<SysFaceEntity> faceUserInfoList;
private FaceFeature targetFaceFeature;
public CompareFaceTask(List<SysFaceEntity> faceUserInfoList, FaceFeature targetFaceFeature) {
this.faceUserInfoList = faceUserInfoList;
this.targetFaceFeature = targetFaceFeature;
}
@Override
public List<SysFaceEntity> call() throws Exception {
return arcsoftFaceUtil.faceSearch(targetFaceFeature,faceUserInfoList);
}
}
} }
\ No newline at end of file
package com.mortals.xhx.module.identity.web;
import com.mortals.framework.annotation.RepeatSubmit;
import com.mortals.framework.annotation.UnAuth;
import com.mortals.framework.service.IUser;
import com.mortals.framework.web.BaseCRUDJsonBodyMappingController;
import com.mortals.xhx.base.system.param.service.ParamService;
import com.mortals.xhx.module.identity.model.SysIdentityEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import com.mortals.framework.model.Context;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.mortals.framework.web.BaseCRUDJsonBodyMappingController;
import com.mortals.xhx.module.identity.model.PeopleInfoEntity;
import com.mortals.xhx.module.identity.service.PeopleInfoService;
import org.apache.commons.lang3.ArrayUtils;
import com.mortals.framework.util.StringUtils;
import java.util.*;
import java.util.stream.Collectors;
import com.alibaba.fastjson.JSONObject;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import static com.mortals.framework.ap.SysConstains.*;
/**
*
* 用户信息
*
* @author zxfei
* @date 2022-08-08
*/
@RestController
@RequestMapping("people/info")
public class PeopleInfoController extends BaseCRUDJsonBodyMappingController<PeopleInfoService,PeopleInfoEntity,Long> {
@Autowired
private ParamService paramService;
public PeopleInfoController(){
super.setModuleDesc( "用户信息");
}
@Override
protected void init(Map<String, Object> model, Context context) {
super.init(model, context);
}
@PostMapping({"save"})
@RepeatSubmit
@UnAuth
public String save(@RequestBody PeopleInfoEntity entity) {
Map<String, Object> model = new HashMap();
Context context = this.getContext();
int code = 1;
String busiDesc = "保存" + this.getModuleDesc();
try {
this.saveBefore(entity, model, context);
IUser user;
if (entity.newEntity()) {
busiDesc = "新增" + this.getModuleDesc();
entity.setCreateTime(new Date());
entity.setUpdateTime(entity.getCreateTime());
user = this.getCurUser();
if (user != null) {
entity.setCreateUserId(user.getId());
entity.setCreateUser(user.getLoginName());
entity.setCreateUserName(user.getRealName());
entity.setCreateUserDeptId(user.getDeptId());
entity.setCreateUserDeptName(user.getDeptName());
entity.setUpdateUserId(user.getId());
entity.setUpdateUser(user.getLoginName());
entity.setUpdateUserName(user.getRealName());
entity.setUpdateUserDeptId(user.getDeptId());
entity.setUpdateUserDeptName(user.getDeptName());
}
this.service.save(entity, context);
} else {
busiDesc = "修改" + this.getModuleDesc();
entity.setUpdateTime(new Date());
user = this.getCurUser();
if (user != null) {
entity.setUpdateUserId(user.getId());
entity.setUpdateUser(user.getLoginName());
entity.setUpdateUserName(user.getRealName());
entity.setUpdateUserDeptId(user.getDeptId());
entity.setUpdateUserDeptName(user.getDeptName());
}
this.service.update(entity, context);
}
model.put("id", entity.getId());
code = this.saveAfter(entity, model, context);
model.put("entity", entity);
model.put("message_info", busiDesc + "成功");
this.recordSysLog(this.request, busiDesc + " 【成功】 [id:" + entity.getId() + "]");
} catch (Exception var7) {
this.doException(this.request, busiDesc, model, var7);
model.put("entity", entity);
this.init(model, context);
code = this.saveException(entity, model, context, var7);
}
this.init(model, context);
JSONObject ret = new JSONObject();
ret.put("code", code);
ret.put("msg", model.remove("message_info"));
ret.put("data", model);
return ret.toJSONString();
}
@PostMapping({"findIdEntity"})
@UnAuth
public String findIdEntity(@RequestBody PeopleInfoEntity entity) {
Map<String, Object> model = new HashMap();
JSONObject ret = new JSONObject();
String busiDesc = "获取基础信息";
Context context = this.getContext();
try {
PeopleInfoEntity peopleInfo = service.findPeopleInfo(entity);
model.put("data",peopleInfo);
model.put("message_info", busiDesc + "成功");
this.recordSysLog(this.request, busiDesc + " 【成功】");
} catch (Exception var8) {
this.doException(this.request, busiDesc, model, var8);
Object msg = model.get("message_info");
return this.createFailJsonResp(msg == null ? "系统异常" : msg.toString());
}
this.init(model, context);
ret.put("data", model.get("data"));
ret.put("code", 1);
ret.put("msg", model.remove("message_info"));
return ret.toJSONString();
}
}
\ No newline at end of file
...@@ -113,4 +113,28 @@ public class SysFaceController extends BaseCRUDJsonBodyMappingController<SysFace ...@@ -113,4 +113,28 @@ public class SysFaceController extends BaseCRUDJsonBodyMappingController<SysFace
ret.put("msg", model.remove("message_info")); ret.put("msg", model.remove("message_info"));
return ret.toJSONString(); return ret.toJSONString();
} }
@PostMapping({"search"})
@UnAuth
public String search(@RequestPart("file") MultipartFile file) {
Map<String, Object> model = new HashMap();
JSONObject ret = new JSONObject();
String busiDesc = "人脸识别";
Context context = this.getContext();
try {
List<FaceInfoResVO> list = service.searchUserByFace(file.getBytes());
model.put("data",list);
this.recordSysLog(this.request, busiDesc + " 【成功】");
} catch (Exception var8) {
this.doException(this.request, busiDesc, model, var8);
Object msg = model.get("message_info");
return this.createFailJsonResp(msg == null ? "系统异常" : msg.toString());
}
this.init(model, context);
ret.put("data", model.get("data"));
ret.put("code", 1);
ret.put("msg", model.remove("message_info"));
return ret.toJSONString();
}
} }
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment