package me.zhengjie.domain.notary.impl; 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.file.FaceMinioFileHandle; import me.zhengjie.base.file.FileHandleVo; import me.zhengjie.base.file.MinioFileHandle; import me.zhengjie.base.util.JuheServiceUtil; import me.zhengjie.base.util.tencent.utils.Img2Base64Util; import me.zhengjie.dao.mybatis.ThirdPartyInterfaceRepository; import me.zhengjie.dao.mybatis.entity.*; import me.zhengjie.dao.mybatis.mapper.ContractOrderMapper; import me.zhengjie.dao.mybatis.mapper.FileInfoMapper; import me.zhengjie.dao.mybatis.mapper.SysUserMapper; import me.zhengjie.dao.mybatis.mapper.UserAXQInfoMapper; import me.zhengjie.domain.img.CompareImageDomain; import me.zhengjie.domain.notary.NotaryDomain; import me.zhengjie.utils.RedisUtils; import me.zhengjie.utils.StringUtils; import org.springframework.stereotype.Component; import org.springframework.util.ObjectUtils; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; import static com.arcsoft.face.toolkit.ImageFactory.getRGBData; @Component @RequiredArgsConstructor @Slf4j public class NotaryDomainImpl implements NotaryDomain { private final SysUserMapper userMapper; private final UserAXQInfoMapper userAXQInfoMapper; private final ContractOrderMapper contractOrderMapper; private final FaceMinioFileHandle minioFileHandle; private final FileInfoMapper fileInfoMapper; private final RedisUtils redis; private final ThirdPartyInterfaceRepository thirdPartyInterfaceRepository; //以下为测试部署环境 // private static final String APPID = "6F5JVsCCeSEbBSLSXWVwPki71yK5Y4Jf7oUjA4Y3mLtu"; // private static final String SDKKEY = "5qKM4a9oNSXNhXdwd7Ycrvnxdw2JXjcyeccYmb4zND7S"; // private static final String LIBPATH = "/home/tom/nt-test/lib/so"; //以下为本地测试 private static final String APPID = "H6Er8ksqAcKc7Dk4Yum9Rkz4g9Gm77ZXAEMgvenjkTQQ"; private static final String SDKKEY = "Abd9D8xZQUqG8vDtU2a1tEkdfThkK1tZppjXzydGwEd6"; private static final String LIBPATH = "D:\\arcsoft_lib"; /** * 获取base64取消文件头 * @param base64 * @return */ public String getBase64(String base64){ String[] base64s = base64.split("base64"); if (base64s!=null && base64s.length>1){ base64 = base64s[1]; } return base64; } /** * app端的人脸核身 * @param compareImageDomain * @return */ public ResultCode appCompareFace(CompareImageDomain compareImageDomain){ String base64 = compareImageDomain.getBase64(); if (base64==null){ return ResultCode.PARAM_IS_BLANK; } base64 = getBase64(base64); String idCard = compareImageDomain.getIdCard(); String nickName = compareImageDomain.getName(); //当事人的人脸核身 QueryWrapper userAXQInfoEntityQueryWrapper = new QueryWrapper<>(); userAXQInfoEntityQueryWrapper.eq("id_card",idCard).eq("nick_name",nickName); UserAXQInfoEntity userAXQInfoEntity = userAXQInfoMapper.selectOne(userAXQInfoEntityQueryWrapper); if (ObjectUtils.isEmpty(userAXQInfoEntity)){ return ResultCode.PARAM_IS_INVALID; } //做过安心签的用户 直接人脸核身 保存图片 ThirdPartyInterfaceEntity thirdPartyInterfaceEntity = JuheServiceUtil.URLPost(idCard, nickName, base64); File base = null; try { base = File.createTempFile("compare", ".jpeg"); base.deleteOnExit(); } catch (IOException e) { throw new RuntimeException(e); } if (!Img2Base64Util.generateImage(base64, base.getPath())) { log.info("base64转图片异常"); return ResultCode.FACEAUTH_FAIL; } FileInfoEntity fileInfo = saveCompareImage(base); fileInfoMapper.insert(fileInfo); thirdPartyInterfaceEntity.setFileId(fileInfo.getId()+""); thirdPartyInterfaceEntity.setBusinessNo(compareImageDomain.getBusinessNo()); if (StringUtils.isNotBlank(thirdPartyInterfaceEntity.getMessage())){ //没有message说明人脸核身成功 UserAXQInfoEntity userAxq = new UserAXQInfoEntity(); userAxq.setId(userAXQInfoEntity.getId()); userAxq.setCompareImgId(fileInfo.getId()); userAXQInfoMapper.updateById(userAxq); log.info("当事人人脸核身通过"); thirdPartyInterfaceRepository.insert(thirdPartyInterfaceEntity); return ResultCode.SUCCESS; } thirdPartyInterfaceRepository.insert(thirdPartyInterfaceEntity); return ResultCode.LIVE_VIDEO_INVALID; } /** * 照片比对 * * @param compareImageDomain * @return */ public ResultCode compareFace(CompareImageDomain compareImageDomain) { String base64 = compareImageDomain.getBase64(); if (base64==null){ return ResultCode.PARAM_IS_BLANK; } base64 = getBase64(base64); //先判断是银行客户经理还是当事人 String roleId = compareImageDomain.getRoleId(); SysUserEntity sysUserEntity = null; UserAXQInfoEntity userAXQInfoEntity = null; String idCard = compareImageDomain.getIdCard(); String nickName = compareImageDomain.getName(); boolean flag = "-1".equals(roleId); if (flag) { //说明是银行客户经理 QueryWrapper contractOrderEntityQueryWrapper = new QueryWrapper<>(); contractOrderEntityQueryWrapper.eq("business_no",compareImageDomain.getBusinessNo()).eq("customer_name",compareImageDomain.getName()); ContractOrderEntity contractOrderEntity = contractOrderMapper.selectOne(contractOrderEntityQueryWrapper); if (ObjectUtils.isEmpty(contractOrderEntity)){ return ResultCode.ACCOUNT_MANAGER_NO_ASSIGNED; } QueryWrapper sysUserEntityQueryWrapper = new QueryWrapper<>(); sysUserEntityQueryWrapper.eq("id_card", idCard).eq("nick_name", nickName); sysUserEntity = userMapper.selectOne(sysUserEntityQueryWrapper); } else { //说明是当事人 QueryWrapper userAXQInfoEntityQueryWrapper = new QueryWrapper<>(); userAXQInfoEntityQueryWrapper.eq("id_card", idCard).eq("user_name", nickName); userAXQInfoEntity = userAXQInfoMapper.selectOne(userAXQInfoEntityQueryWrapper); } if (ObjectUtils.isEmpty(sysUserEntity) && ObjectUtils.isEmpty(userAXQInfoEntity)) { return ResultCode.PARAM_IS_INVALID; } //后面需要的三个参数 base64 身份证号 姓名 String redisCount = "idCard:" + idCard + ":COUNT:"; Integer count = null; if (redis.hasKey(redisCount)) { count = (Integer) redis.get(redisCount); System.err.println("redis存入次数" + count); } //将base64转成图片 File base = null; try { base = File.createTempFile("compare", ".jpeg"); base.deleteOnExit(); } catch (IOException e) { throw new RuntimeException(e); } if (!Img2Base64Util.generateImage(base64, base.getPath())) { log.info("base64转图片异常"); return ResultCode.FACEAUTH_FAIL; } FileInfoEntity fileInfo = saveCompareImage(base); fileInfoMapper.insert(fileInfo); boolean redisFlag = (count != null && count >= 2); if (flag) { //说明是客户经理 if (sysUserEntity.getCompareImgId() == null || redisFlag) { //说明客户经理需要做人脸核身 ThirdPartyInterfaceEntity thirdPartyInterfaceEntity = JuheServiceUtil.URLPost(idCard, nickName, base64); thirdPartyInterfaceEntity.setFileId(fileInfo.getId()+""); thirdPartyInterfaceEntity.setBusinessNo(compareImageDomain.getBusinessNo()); if (StringUtils.isNotBlank(thirdPartyInterfaceEntity.getMessage())){ //上传图片到minio FileInfo SysUserEntity bank = new SysUserEntity(); bank.setUserId(sysUserEntity.getUserId()); bank.setCompareImgId(fileInfo.getId()); userMapper.updateById(bank); log.info("银行客户经理人脸核身通过"); redis.del(redisCount); thirdPartyInterfaceRepository.insert(thirdPartyInterfaceEntity); return ResultCode.SUCCESS; } log.info("客户经理人脸核身失败"); thirdPartyInterfaceRepository.insert(thirdPartyInterfaceEntity); return ResultCode.LIVE_VIDEO_INVALID; } } else { //说明是当事人 if (userAXQInfoEntity.getCompareImgId() == null || redisFlag) { //说明当事人需要做人脸核身 ThirdPartyInterfaceEntity thirdPartyInterfaceEntity = JuheServiceUtil.URLPost(idCard, nickName, base64); thirdPartyInterfaceEntity.setFileId(fileInfo.getId()+""); thirdPartyInterfaceEntity.setBusinessNo(compareImageDomain.getBusinessNo()); if (thirdPartyInterfaceEntity.getResult()==1){ //上传图片到minio FileInfo UserAXQInfoEntity userAxq = new UserAXQInfoEntity(); userAxq.setId(userAXQInfoEntity.getId()); userAxq.setCompareImgId(fileInfo.getId()); userAXQInfoMapper.updateById(userAxq); log.info("当事人人脸核身通过"); redis.del(redisCount); thirdPartyInterfaceRepository.insert(thirdPartyInterfaceEntity); return ResultCode.SUCCESS; } log.info("当事人人脸核身失败"); thirdPartyInterfaceRepository.insert(thirdPartyInterfaceEntity); return ResultCode.LIVE_VIDEO_INVALID; } } //如果不用做人脸核身 那么就去做照片比对 //获取比较图片的id Integer id = null; if (!ObjectUtils.isEmpty(sysUserEntity)) { id = sysUserEntity.getCompareImgId(); } if (!ObjectUtils.isEmpty(userAXQInfoEntity)) { id = userAXQInfoEntity.getCompareImgId(); } if (! compareImage(base, id,redisCount,count)) { return ResultCode.LIVE_VIDEO_INVALID; } if (count != null) { redis.del(redisCount); } return ResultCode.SUCCESS; } /** * 虹软的人脸照片比对 * @param base 照片 * @param id 文件库中照片的id * @param redisCount 数据库中的键 * @param count redis当中的次数 * @return */ public boolean compareImage(File base, Integer id,String redisCount,Integer count) { //从官网获取 FaceEngine 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 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()) { throw new RuntimeException("初始化引擎失败"); } //人脸检测 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); //俯仰角 float pitch = Math.abs(face3DAngleList.get(0).getPitch()); //偏向角 float yaw = Math.abs(face3DAngleList.get(0).getYaw()); if (pitch > 10 || yaw > 10) { //照片不符合标准 log.info("图片不符合标准"); return false; } //特征提取 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 = minioFileHandle.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证明失败了 if (faceSimilar.getScore() > 0.8) { log.info("人脸照片比对通过"); return true; } if (count == null) { redis.set(redisCount, 1, 30, TimeUnit.MINUTES); } else { redis.set(redisCount, count + 1, 30, TimeUnit.MINUTES); } log.info("人脸照片比对未通过");; return false; } private FileInfoEntity saveCompareImage(File base) { FileHandleVo fileHandleVo = new FileHandleVo(); fileHandleVo.setFilePath(base.getPath()); fileHandleVo.setSourceFilePath("/face/" + base.getName()); fileHandleVo.setContentType("image/jpeg"); try { minioFileHandle.uploadfilePath(fileHandleVo); } catch (Exception e) { throw new RuntimeException("照片保存到minio异常"); } FileInfoEntity fileInfo = new FileInfoEntity(); fileInfo.setLoanNo("face"); fileInfo.setFileName(base.getName()); fileInfo.setPath(fileInfo.getLoanNo() + "/" + base.getName()); return fileInfo; } }