package me.zhengjie.domain.notary.impl; 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.file.FileHandle; import me.zhengjie.base.file.FileHandleVo; import me.zhengjie.base.file.MinioFileHandle; import me.zhengjie.base.util.FileUploadUtil; import me.zhengjie.base.util.JuheServiceUtil; import me.zhengjie.base.util.tencent.utils.HttpClientUtil; 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 org.springframework.stereotype.Component; import org.springframework.util.ObjectUtils; import org.springframework.web.multipart.MultipartFile; 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 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(); //根据业务编号获取订单 判断当事人名字 String businessNo = compareImageDomain.getBusinessNo(); QueryWrapper contractOrderEntityQueryWrapper = new QueryWrapper<>(); contractOrderEntityQueryWrapper.eq("business_no", businessNo); ContractOrderEntity contractOrderEntity = contractOrderMapper.selectOne(contractOrderEntityQueryWrapper); Integer id = null; //看是哪个当事人 if (nickName.equals(contractOrderEntity.getName())) { id = contractOrderEntity.getCompareImgId(); } else if (nickName.equals(contractOrderEntity.getJointName())) { id = contractOrderEntity.getJointCompareImgId(); } //后面需要的三个参数 base64 身份证号 姓名 String redisCount = "idCard:" + idCard + ":COUNT:"; Integer count = null; if (redis.hasKey(redisCount)) { count = (Integer) redis.get(redisCount); System.err.println("redis存入次数" + count); } 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; } FileUploadUtil.saveFaceImage(base64); FileInfoEntity fileInfo = uploadFaceFile(base64); boolean redisFlag = (count != null && count >= 2); if (ObjectUtils.isEmpty(id) || redisFlag) { //要做人脸核身 ThirdPartyInterfaceEntity thirdPartyInterfaceEntity = JuheServiceUtil.URLPost(idCard, nickName, base64); thirdPartyInterfaceEntity.setFileId(fileInfo.getId() + ""); thirdPartyInterfaceEntity.setBusinessNo(compareImageDomain.getBusinessNo()); thirdPartyInterfaceRepository.insert(thirdPartyInterfaceEntity); if (thirdPartyInterfaceEntity.getResult() == 1) { ContractOrderEntity orderEntity = new ContractOrderEntity(); orderEntity.setId(contractOrderEntity.getId()); //判断是共同责任人还是当事人 if (nickName.equals(contractOrderEntity.getName())) { orderEntity.setCompareImgId(fileInfo.getId()); } if (nickName.equals(contractOrderEntity.getJointName())) { orderEntity.setJointCompareImgId(fileInfo.getId()); } contractOrderMapper.updateById(orderEntity); log.info("当事人人脸核身通过"); redis.del(redisCount); return ResultCode.SUCCESS; } return ResultCode.LIVE_VIDEO_INVALID; } //要做照片比对 if (!compareImage(base, id, redisCount, count)) { return ResultCode.LIVE_VIDEO_INVALID; } if (count != null) { redis.del(redisCount); } return ResultCode.SUCCESS; } /** * 照片比对 * * @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(); QueryWrapper orderEntityQueryWrapper = new QueryWrapper<>(); orderEntityQueryWrapper.eq("business_no", compareImageDomain.getBusinessNo()); ContractOrderEntity contractOrder = contractOrderMapper.selectOne(orderEntityQueryWrapper); if (ObjectUtils.isEmpty(contractOrder)) { return ResultCode.PARAM_IS_INVALID; } Integer compareImageId = null; 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 { //说明是当事人 if (compareImageDomain.getName().equals(contractOrder.getName())) { compareImageId = contractOrder.getCompareImgId(); } else if (compareImageDomain.getName().equals(contractOrder.getJointName())) { compareImageId = contractOrder.getJointCompareImgId(); } } //后面需要的三个参数 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; } boolean redisFlag = (count != null && count >= 2); if (flag) { //说明是客户经理 if (sysUserEntity.getCompareImgId() == null || redisFlag) { //说明客户经理需要做人脸核身 FileInfoEntity fileInfo = uploadFaceFile(base64); ThirdPartyInterfaceEntity thirdPartyInterfaceEntity = JuheServiceUtil.URLPost(idCard, nickName, base64); thirdPartyInterfaceEntity.setFileId(fileInfo.getId() + ""); thirdPartyInterfaceEntity.setBusinessNo(compareImageDomain.getBusinessNo()); if (thirdPartyInterfaceEntity.getResult() == 1) { //上传图片到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 (ObjectUtils.isEmpty(compareImageId) || redisFlag) { //说明当事人需要做人脸核身 FileInfoEntity fileInfo = uploadFaceFile(base64); ThirdPartyInterfaceEntity thirdPartyInterfaceEntity = JuheServiceUtil.URLPost(idCard, nickName, base64); thirdPartyInterfaceEntity.setFileId(fileInfo.getId() + ""); thirdPartyInterfaceEntity.setBusinessNo(compareImageDomain.getBusinessNo()); thirdPartyInterfaceRepository.insert(thirdPartyInterfaceEntity); if (thirdPartyInterfaceEntity.getResult() == 1) { //上传图片到minio FileInfo; ContractOrderEntity orderEntity = new ContractOrderEntity(); orderEntity.setId(contractOrder.getId()); //判断是共同责任人还是当事人 if (nickName.equals(contractOrder.getName())) { orderEntity.setCompareImgId(fileInfo.getId()); } if (nickName.equals(contractOrder.getJointName())) { orderEntity.setJointCompareImgId(fileInfo.getId()); } redis.del(redisCount); contractOrderMapper.updateById(orderEntity); log.info("当事人人脸核身通过"); return ResultCode.SUCCESS; } log.info("当事人人脸核身失败"); return ResultCode.LIVE_VIDEO_INVALID; } //如果不用做人脸核身 那么就去做照片比对 //获取比较图片的id Integer id = null; if (!ObjectUtils.isEmpty(sysUserEntity)) { id = sysUserEntity.getCompareImgId(); } if (!ObjectUtils.isEmpty(compareImageId)) { id = compareImageId; } if (!ObjectUtils.isEmpty(id)) { 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()) { base.delete(); throw new RuntimeException("引擎激活失败"); } ActiveFileInfo activeFileInfo = new ActiveFileInfo(); errorCode = faceEngine.getActiveFileInfo(activeFileInfo); if (errorCode != ErrorInfo.MOK.getValue() && errorCode != ErrorInfo.MERR_ASF_ALREADY_ACTIVATED.getValue()) { base.delete(); 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()) { base.delete(); 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()); log.info("俯仰角:{}",pitch); log.info("偏向角:{}",yaw); if (pitch >= 10 || yaw >= 10) { //照片不符合标准 log.info("图片不符合标准"); base.delete(); 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=FileUploadUtil.getFileWithPath(filePath); } catch (Exception e) { throw new RuntimeException(e); }finally { base.delete(); if (file!=null){ file.delete(); } } //人脸检测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("人脸照片比对通过"); base.delete(); file.delete(); return true; } if (count == null) { redis.set(redisCount, 1, 30, TimeUnit.MINUTES); } else { redis.set(redisCount, count + 1, 30, TimeUnit.MINUTES); } log.info("人脸照片比对未通过"); base.delete(); file.delete(); return false; } /** * 上传对比照片到minio * @param base64 */ public void uploadFile(String base64){ JSONObject params = new JSONObject(); params.put("base64", base64); 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("上传成功"); } } public FileInfoEntity uploadFaceFile(String base64){ String s = FileUploadUtil.saveFaceImage(base64); 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; } }