FaceCompareUtil.java 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. package me.zhengjie.base.face;
  2. import com.alibaba.fastjson.JSONObject;
  3. import com.arcsoft.face.*;
  4. import com.arcsoft.face.enums.DetectMode;
  5. import com.arcsoft.face.enums.DetectOrient;
  6. import com.arcsoft.face.enums.ErrorInfo;
  7. import com.arcsoft.face.toolkit.ImageInfo;
  8. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  9. import lombok.RequiredArgsConstructor;
  10. import lombok.extern.slf4j.Slf4j;
  11. import me.zhengjie.base.ResultCode;
  12. import me.zhengjie.base.config.thread.ThreadPoolExecutorUtil;
  13. import me.zhengjie.base.util.FileUploadUtil;
  14. import me.zhengjie.base.util.tencent.utils.HttpClientUtil;
  15. import me.zhengjie.dao.mybatis.FaceCompareRepository;
  16. import me.zhengjie.dao.mybatis.entity.FaceCompareEntity;
  17. import me.zhengjie.dao.mybatis.entity.FileInfoEntity;
  18. import me.zhengjie.dao.mybatis.mapper.FileInfoMapper;
  19. import me.zhengjie.utils.RedisUtils;
  20. import org.springframework.beans.factory.annotation.Value;
  21. import org.springframework.stereotype.Component;
  22. import org.springframework.util.CollectionUtils;
  23. import javax.annotation.PostConstruct;
  24. import java.io.File;
  25. import java.io.FileInputStream;
  26. import java.io.FileNotFoundException;
  27. import java.io.IOException;
  28. import java.util.ArrayList;
  29. import java.util.Base64;
  30. import java.util.List;
  31. import static com.arcsoft.face.toolkit.ImageFactory.getRGBData;
  32. @Component
  33. @RequiredArgsConstructor
  34. @Slf4j
  35. public class FaceCompareUtil {
  36. private final FileInfoMapper fileInfoMapper;
  37. private final RedisUtils redis;
  38. private final FaceCompareRepository thirdPartyInterfaceRepository;
  39. private static FaceEngine faceEngine;
  40. private static FunctionConfiguration functionConfiguration;
  41. private static EngineConfiguration engineConfiguration;
  42. private static int errorCode;
  43. //以下为测试部署环境
  44. @Value("${hongruan.appid}")
  45. private String appid;
  46. @Value("${hongruan.sdkkey}")
  47. private String sdkkey;
  48. @Value("${hongruan.libpath}")
  49. private String libpath;
  50. @PostConstruct
  51. private void init(){
  52. //从官网获取
  53. faceEngine = new FaceEngine(libpath);
  54. //激活引擎
  55. int errorCode = faceEngine.activeOnline(appid, sdkkey);
  56. if (errorCode != ErrorInfo.MOK.getValue() && errorCode != ErrorInfo.MERR_ASF_ALREADY_ACTIVATED.getValue()) {
  57. throw new RuntimeException("引擎激活失败");
  58. }
  59. ActiveFileInfo activeFileInfo = new ActiveFileInfo();
  60. errorCode = faceEngine.getActiveFileInfo(activeFileInfo);
  61. if (errorCode != ErrorInfo.MOK.getValue() && errorCode != ErrorInfo.MERR_ASF_ALREADY_ACTIVATED.getValue()) {
  62. throw new RuntimeException("获取激活文件信息失败");
  63. }
  64. //引擎配置
  65. engineConfiguration = new EngineConfiguration();
  66. engineConfiguration.setDetectMode(DetectMode.ASF_DETECT_MODE_IMAGE);
  67. engineConfiguration.setDetectFaceOrientPriority(DetectOrient.ASF_OP_ALL_OUT);
  68. engineConfiguration.setDetectFaceMaxNum(10);
  69. engineConfiguration.setDetectFaceScaleVal(16);
  70. //功能配置
  71. functionConfiguration = new FunctionConfiguration();
  72. functionConfiguration.setSupportAge(true);
  73. functionConfiguration.setSupportFace3dAngle(true);
  74. functionConfiguration.setSupportFaceDetect(true);
  75. functionConfiguration.setSupportFaceRecognition(true);
  76. functionConfiguration.setSupportGender(true);
  77. functionConfiguration.setSupportLiveness(true);
  78. functionConfiguration.setSupportIRLiveness(true);
  79. engineConfiguration.setFunctionConfiguration(functionConfiguration);
  80. //初始化引擎
  81. errorCode = faceEngine.init(engineConfiguration);
  82. if (errorCode != ErrorInfo.MOK.getValue()) {
  83. throw new RuntimeException("初始化引擎失败");
  84. }
  85. }
  86. /**
  87. * 验证照片是否居中
  88. * @param base
  89. * @return
  90. */
  91. public boolean imageCenter(File base) {
  92. //人脸检测
  93. ImageInfo imageInfo = getRGBData(base);
  94. List<FaceInfo> faceInfoList = new ArrayList<FaceInfo>();
  95. errorCode = faceEngine.detectFaces(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList);
  96. System.out.println(faceInfoList);
  97. //人脸属性检测
  98. FunctionConfiguration configuration = new FunctionConfiguration();
  99. configuration.setSupportFace3dAngle(true);
  100. errorCode = faceEngine.process(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList, configuration);
  101. //3D信息检测
  102. List<Face3DAngle> face3DAngleList = new ArrayList<Face3DAngle>();
  103. errorCode = faceEngine.getFace3DAngle(face3DAngleList);
  104. if (CollectionUtils.isEmpty(face3DAngleList)) {
  105. return false;
  106. }
  107. //俯仰角
  108. float pitch = Math.abs(face3DAngleList.get(0).getPitch());
  109. //偏向角
  110. float yaw = Math.abs(face3DAngleList.get(0).getYaw());
  111. log.info("俯仰角:{}", pitch);
  112. log.info("偏向角:{}", yaw);
  113. if (pitch >= 10 || yaw >= 10) {
  114. //照片不符合标准
  115. log.info("图片不符合标准");
  116. return false;
  117. }
  118. return true;
  119. }
  120. /**
  121. * 校验图片的当事人是否为一个
  122. * @param base
  123. * @return
  124. */
  125. public boolean imageSingle(File base) {
  126. //人脸检测
  127. ImageInfo imageInfo = getRGBData(base);
  128. List<FaceInfo> faceInfoList = new ArrayList<FaceInfo>();
  129. errorCode = faceEngine.detectFaces(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList);
  130. System.out.println(faceInfoList);
  131. if (faceInfoList.size()>1){
  132. return false;
  133. }
  134. return true;
  135. }
  136. /**
  137. * 虹软的人脸照片比对
  138. *
  139. * @param base 照片
  140. * @param id 文件库中照片的id
  141. * @param redisCount 数据库中的键
  142. * @param count redis当中的次数
  143. * @return
  144. */
  145. public ResultCode compareImage(File base, Integer id, String redisCount, FaceCompareEntity faceCompareEntity) {
  146. //人脸检测
  147. ImageInfo imageInfo = getRGBData(base);
  148. List<FaceInfo> faceInfoList = new ArrayList<FaceInfo>();
  149. errorCode = faceEngine.detectFaces(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList);
  150. System.out.println(faceInfoList);
  151. //活体检测
  152. /*List<LivenessInfo> livenessInfoList = new ArrayList<LivenessInfo>();
  153. errorCode = faceEngine.getLiveness(livenessInfoList);
  154. if (CollectionUtils.isEmpty(livenessInfoList)){
  155. log.info("活体验证失败");
  156. return false;
  157. }
  158. System.out.println("活体:" + livenessInfoList.get(0).getLiveness());
  159. //IR属性处理
  160. ImageInfo imageInfoGray = getGrayData(base);
  161. List<FaceInfo> faceInfoListGray = new ArrayList<FaceInfo>();
  162. errorCode = faceEngine.detectFaces(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoListGray);
  163. FunctionConfiguration configuration2 = new FunctionConfiguration();
  164. configuration2.setSupportIRLiveness(true);
  165. errorCode = faceEngine.processIr(imageInfoGray.getImageData(), imageInfoGray.getWidth(), imageInfoGray.getHeight(), imageInfoGray.getImageFormat(), faceInfoListGray, configuration2);
  166. //IR活体检测
  167. List<IrLivenessInfo> irLivenessInfo = new ArrayList<>();
  168. errorCode = faceEngine.getLivenessIr(irLivenessInfo);
  169. if (CollectionUtils.isEmpty(irLivenessInfo)){
  170. log.info("活体验证失败");
  171. return false;
  172. }
  173. System.out.println("IR活体:" + irLivenessInfo.get(0).getLiveness());*/
  174. //特征提取
  175. FaceFeature faceFeature = new FaceFeature();
  176. errorCode = faceEngine.extractFaceFeature(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList.get(0), faceFeature);
  177. //根据id 查找文件
  178. QueryWrapper<FileInfoEntity> fileInfoQw = new QueryWrapper<>();
  179. fileInfoQw.eq("id", id);
  180. FileInfoEntity fileInfoEntity = fileInfoMapper.selectOne(fileInfoQw);
  181. String filePath = fileInfoEntity.getPath();
  182. File file = null;
  183. try {
  184. file= FileUploadUtil.getFileWithPath(filePath);
  185. } catch (Exception e) {
  186. throw new RuntimeException(e);
  187. }
  188. //人脸检测2
  189. ImageInfo imageInfo2 = getRGBData(file);
  190. List<FaceInfo> faceInfoList2 = new ArrayList<FaceInfo>();
  191. errorCode = faceEngine.detectFaces(imageInfo2.getImageData(), imageInfo2.getWidth(), imageInfo2.getHeight(), imageInfo2.getImageFormat(), faceInfoList2);
  192. //特征提取2
  193. FaceFeature faceFeature2 = new FaceFeature();
  194. errorCode = faceEngine.extractFaceFeature(imageInfo2.getImageData(), imageInfo2.getWidth(), imageInfo2.getHeight(), imageInfo2.getImageFormat(), faceInfoList2.get(0), faceFeature2);
  195. //特征比对
  196. FaceFeature targetFaceFeature = new FaceFeature();
  197. targetFaceFeature.setFeatureData(faceFeature.getFeatureData());
  198. FaceFeature sourceFaceFeature = new FaceFeature();
  199. sourceFaceFeature.setFeatureData(faceFeature2.getFeatureData());
  200. FaceSimilar faceSimilar = new FaceSimilar();
  201. errorCode = faceEngine.compareFaceFeature(targetFaceFeature, sourceFaceFeature, faceSimilar);
  202. //如果通过 上传文件 修改用户绑定id 如果没通过 返回null证明失败了
  203. //引擎卸载
  204. errorCode = faceEngine.unInit();
  205. float score = faceSimilar.getScore();
  206. faceCompareEntity.setScore(score+"");
  207. FileInputStream fileInputStream = null;
  208. try {
  209. fileInputStream = new FileInputStream(base);
  210. } catch (FileNotFoundException e) {
  211. throw new RuntimeException(e);
  212. }
  213. byte[] bytes = new byte[(int) base.length()];
  214. try {
  215. fileInputStream.read(bytes);
  216. } catch (IOException e) {
  217. throw new RuntimeException(e);
  218. }finally {
  219. try {
  220. fileInputStream.close();
  221. } catch (IOException e) {
  222. throw new RuntimeException(e);
  223. }
  224. }
  225. String s = Base64.getEncoder().encodeToString(bytes);
  226. FileInfoEntity fileInfo = uploadFaceFile(s);
  227. faceCompareEntity.setFileId(fileInfo.getId()+"");
  228. faceCompareEntity.setType(0);
  229. if (score > 0.8) {
  230. log.info("人脸照片比对通过");
  231. faceCompareEntity.setResult(1);
  232. thirdPartyInterfaceRepository.insert(faceCompareEntity);
  233. file.delete();
  234. base.delete();
  235. redis.del(redisCount);
  236. return ResultCode.SUCCESS;
  237. }
  238. redis.increment(redisCount);
  239. log.info("人脸照片比对未通过");
  240. faceCompareEntity.setMessage("验证失败");
  241. faceCompareEntity.setResult(0);
  242. thirdPartyInterfaceRepository.insert(faceCompareEntity);
  243. file.delete();
  244. base.delete();
  245. return ResultCode.LIVE_VIDEO_INVALID;
  246. }
  247. public FileInfoEntity uploadFaceFile(String base64){
  248. String s = FileUploadUtil.saveFaceImage(base64);
  249. ThreadPoolExecutorUtil.getPoll().execute(new Runnable() {
  250. @Override
  251. public void run() {
  252. uploadFile(base64,s);
  253. }
  254. });
  255. String[] split = s.split("/");
  256. FileInfoEntity fileInfo = new FileInfoEntity();
  257. fileInfo.setLoanNo(split[0]);
  258. fileInfo.setFileName(split[split.length-1]);
  259. fileInfo.setPath(s);
  260. fileInfoMapper.insert(fileInfo);
  261. return fileInfo;
  262. }
  263. /**
  264. * 上传对比照片到minio
  265. * @param base64
  266. */
  267. public void uploadFile(String base64,String filePath){
  268. JSONObject params = new JSONObject();
  269. params.put("base64", base64);
  270. params.put("filePath",filePath);
  271. HttpClientUtil httpClientUtil = new HttpClientUtil();
  272. String xmlData = httpClientUtil.doPost("https://fqgz.flowbb.cn:6001/sp/upload/uploadFaceImage",params.toString(),"utf-8");
  273. JSONObject result = JSONObject.parseObject(xmlData);
  274. String code = result.getString("code");
  275. if ("100".equals(code)){
  276. log.info("上传成功");
  277. }
  278. }
  279. }