package me.zhengjie.base.face; import com.alibaba.fastjson.JSONObject; import com.arcsoft.face.*; import com.arcsoft.face.enums.DetectMode; import com.arcsoft.face.enums.DetectOrient; import com.arcsoft.face.enums.ErrorInfo; import com.arcsoft.face.toolkit.ImageInfo; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import me.zhengjie.base.ResultCode; import me.zhengjie.base.config.thread.ThreadPoolExecutorUtil; import me.zhengjie.base.util.FileUploadUtil; import me.zhengjie.base.util.tencent.utils.HttpClientUtil; import me.zhengjie.dao.mybatis.FaceCompareRepository; import me.zhengjie.dao.mybatis.entity.FaceCompareEntity; import me.zhengjie.dao.mybatis.entity.FileInfoEntity; import me.zhengjie.dao.mybatis.mapper.FileInfoMapper; import me.zhengjie.utils.RedisUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import javax.annotation.PostConstruct; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; import java.util.Base64; import java.util.List; import static com.arcsoft.face.toolkit.ImageFactory.getRGBData; @Component @RequiredArgsConstructor @Slf4j public class FaceCompareUtil { private final FileInfoMapper fileInfoMapper; private final RedisUtils redis; private final FaceCompareRepository thirdPartyInterfaceRepository; private static FaceEngine faceEngine; private static FunctionConfiguration functionConfiguration; private static EngineConfiguration engineConfiguration; private static int errorCode; //以下为测试部署环境 @Value("${hongruan.appid}") private String appid; @Value("${hongruan.sdkkey}") private String sdkkey; @Value("${hongruan.libpath}") private String libpath; @PostConstruct private void init(){ //从官网获取 faceEngine = new FaceEngine(libpath); //激活引擎 int errorCode = faceEngine.activeOnline(appid, sdkkey); if (errorCode != ErrorInfo.MOK.getValue() && errorCode != ErrorInfo.MERR_ASF_ALREADY_ACTIVATED.getValue()) { throw new RuntimeException("引擎激活失败"); } ActiveFileInfo activeFileInfo = new ActiveFileInfo(); errorCode = faceEngine.getActiveFileInfo(activeFileInfo); if (errorCode != ErrorInfo.MOK.getValue() && errorCode != ErrorInfo.MERR_ASF_ALREADY_ACTIVATED.getValue()) { throw new RuntimeException("获取激活文件信息失败"); } //引擎配置 engineConfiguration = new EngineConfiguration(); engineConfiguration.setDetectMode(DetectMode.ASF_DETECT_MODE_IMAGE); engineConfiguration.setDetectFaceOrientPriority(DetectOrient.ASF_OP_ALL_OUT); engineConfiguration.setDetectFaceMaxNum(10); engineConfiguration.setDetectFaceScaleVal(16); //功能配置 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()) { throw new RuntimeException("初始化引擎失败"); } } /** * 验证照片是否居中 * @param base * @return */ public boolean imageCenter(File base) { //人脸检测 ImageInfo imageInfo = getRGBData(base); List faceInfoList = new ArrayList(); errorCode = faceEngine.detectFaces(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList); System.out.println(faceInfoList); //人脸属性检测 FunctionConfiguration configuration = new FunctionConfiguration(); configuration.setSupportFace3dAngle(true); errorCode = faceEngine.process(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList, configuration); //3D信息检测 List face3DAngleList = new ArrayList(); errorCode = faceEngine.getFace3DAngle(face3DAngleList); if (CollectionUtils.isEmpty(face3DAngleList)) { return false; } //俯仰角 float pitch = Math.abs(face3DAngleList.get(0).getPitch()); //偏向角 float yaw = Math.abs(face3DAngleList.get(0).getYaw()); log.info("俯仰角:{}", pitch); log.info("偏向角:{}", yaw); if (pitch >= 10 || yaw >= 10) { //照片不符合标准 log.info("图片不符合标准"); return false; } return true; } /** * 校验图片的当事人是否为一个 * @param base * @return */ public boolean imageSingle(File base) { //人脸检测 ImageInfo imageInfo = getRGBData(base); List faceInfoList = new ArrayList(); errorCode = faceEngine.detectFaces(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList); System.out.println(faceInfoList); if (faceInfoList.size()>1){ return false; } return true; } /** * 虹软的人脸照片比对 * * @param base 照片 * @param id 文件库中照片的id * @param redisCount 数据库中的键 * @param count redis当中的次数 * @return */ public ResultCode compareImage(File base, Integer id, String redisCount, FaceCompareEntity faceCompareEntity) { //人脸检测 ImageInfo imageInfo = getRGBData(base); List faceInfoList = new ArrayList(); errorCode = faceEngine.detectFaces(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList); System.out.println(faceInfoList); //活体检测 /*List livenessInfoList = new ArrayList(); errorCode = faceEngine.getLiveness(livenessInfoList); if (CollectionUtils.isEmpty(livenessInfoList)){ log.info("活体验证失败"); return false; } System.out.println("活体:" + livenessInfoList.get(0).getLiveness()); //IR属性处理 ImageInfo imageInfoGray = getGrayData(base); List faceInfoListGray = new ArrayList(); errorCode = faceEngine.detectFaces(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoListGray); FunctionConfiguration configuration2 = new FunctionConfiguration(); configuration2.setSupportIRLiveness(true); errorCode = faceEngine.processIr(imageInfoGray.getImageData(), imageInfoGray.getWidth(), imageInfoGray.getHeight(), imageInfoGray.getImageFormat(), faceInfoListGray, configuration2); //IR活体检测 List irLivenessInfo = new ArrayList<>(); errorCode = faceEngine.getLivenessIr(irLivenessInfo); if (CollectionUtils.isEmpty(irLivenessInfo)){ log.info("活体验证失败"); return false; } System.out.println("IR活体:" + irLivenessInfo.get(0).getLiveness());*/ //特征提取 FaceFeature faceFeature = new FaceFeature(); errorCode = faceEngine.extractFaceFeature(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList.get(0), faceFeature); //根据id 查找文件 QueryWrapper fileInfoQw = new QueryWrapper<>(); fileInfoQw.eq("id", id); FileInfoEntity fileInfoEntity = fileInfoMapper.selectOne(fileInfoQw); String filePath = fileInfoEntity.getPath(); File file = null; try { file= FileUploadUtil.getFileWithPath(filePath); } catch (Exception e) { throw new RuntimeException(e); } //人脸检测2 ImageInfo imageInfo2 = getRGBData(file); List faceInfoList2 = new ArrayList(); errorCode = faceEngine.detectFaces(imageInfo2.getImageData(), imageInfo2.getWidth(), imageInfo2.getHeight(), imageInfo2.getImageFormat(), faceInfoList2); //特征提取2 FaceFeature faceFeature2 = new FaceFeature(); errorCode = faceEngine.extractFaceFeature(imageInfo2.getImageData(), imageInfo2.getWidth(), imageInfo2.getHeight(), imageInfo2.getImageFormat(), faceInfoList2.get(0), faceFeature2); //特征比对 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); //如果通过 上传文件 修改用户绑定id 如果没通过 返回null证明失败了 //引擎卸载 errorCode = faceEngine.unInit(); float score = faceSimilar.getScore(); faceCompareEntity.setScore(score+""); FileInputStream fileInputStream = null; try { fileInputStream = new FileInputStream(base); } catch (FileNotFoundException e) { throw new RuntimeException(e); } byte[] bytes = new byte[(int) base.length()]; try { fileInputStream.read(bytes); } catch (IOException e) { throw new RuntimeException(e); }finally { try { fileInputStream.close(); } catch (IOException e) { throw new RuntimeException(e); } } String s = Base64.getEncoder().encodeToString(bytes); FileInfoEntity fileInfo = uploadFaceFile(s); faceCompareEntity.setFileId(fileInfo.getId()+""); faceCompareEntity.setType(0); if (score > 0.8) { log.info("人脸照片比对通过"); faceCompareEntity.setResult(1); thirdPartyInterfaceRepository.insert(faceCompareEntity); file.delete(); base.delete(); redis.del(redisCount); return ResultCode.SUCCESS; } redis.increment(redisCount); log.info("人脸照片比对未通过"); faceCompareEntity.setMessage("验证失败"); faceCompareEntity.setResult(0); thirdPartyInterfaceRepository.insert(faceCompareEntity); file.delete(); base.delete(); return ResultCode.LIVE_VIDEO_INVALID; } public FileInfoEntity uploadFaceFile(String base64){ String s = FileUploadUtil.saveFaceImage(base64); ThreadPoolExecutorUtil.getPoll().execute(new Runnable() { @Override public void run() { uploadFile(base64,s); } }); String[] split = s.split("/"); FileInfoEntity fileInfo = new FileInfoEntity(); fileInfo.setLoanNo(split[0]); fileInfo.setFileName(split[split.length-1]); fileInfo.setPath(s); fileInfoMapper.insert(fileInfo); return fileInfo; } /** * 上传对比照片到minio * @param base64 */ public void uploadFile(String base64,String filePath){ JSONObject params = new JSONObject(); params.put("base64", base64); params.put("filePath",filePath); HttpClientUtil httpClientUtil = new HttpClientUtil(); String xmlData = httpClientUtil.doPost("https://fqgz.flowbb.cn:6001/sp/upload/uploadFaceImage",params.toString(),"utf-8"); JSONObject result = JSONObject.parseObject(xmlData); String code = result.getString("code"); if ("100".equals(code)){ log.info("上传成功"); } } }