FaceIdenService.java 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. package com.iden.bms.face;
  2. import cn.hutool.core.collection.CollUtil;
  3. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  4. import com.face.monitor.FaceMonitor;
  5. import com.face.monitor.model.FaceModel;
  6. import com.iden.bms.service.PersonService;
  7. import com.iden.common.cache.RedisKeyConstant;
  8. import com.iden.common.cache.RedisUtil;
  9. import com.iden.common.entity.*;
  10. import com.iden.common.enums.HandleWarningStatusEnum;
  11. import com.iden.common.enums.PersonTypeEnum;
  12. import com.iden.common.service.IdenCameraService;
  13. import com.iden.common.service.IdenCameraVideoService;
  14. import com.iden.common.service.IdenCommunityService;
  15. import com.iden.common.service.IdenFaceImageService;
  16. import com.iden.common.util.ByteUtil;
  17. import com.iden.common.util.DateUtils;
  18. import com.iden.common.util.FileUtil;
  19. import com.iden.common.util.VideoUtil;
  20. import com.iden.common.vo.FaceRetrieveResultVO;
  21. import org.apache.commons.lang3.StringUtils;
  22. import org.apache.logging.log4j.LogManager;
  23. import org.apache.logging.log4j.Logger;
  24. import org.springframework.beans.factory.annotation.Value;
  25. import org.springframework.stereotype.Service;
  26. import javax.annotation.Resource;
  27. import java.io.File;
  28. import java.math.BigDecimal;
  29. import java.util.*;
  30. /**
  31. * @Author: stw
  32. * @Date: 2021/7/14
  33. * @Desc:
  34. */
  35. @Service
  36. public class FaceIdenService {
  37. @Resource
  38. private IdenFaceImageService idenFaceImageService;
  39. @Resource
  40. private IdenCameraService idenCameraService;
  41. @Resource
  42. private IdenCommunityService idenCommunityService;
  43. @Resource
  44. private PersonService personService;
  45. @Resource
  46. private IdenCameraVideoService idenCameraVideoService;
  47. @Resource
  48. private RedisUtil redisUtil;
  49. @Value("${iden.root:#{null}}")
  50. private String idenRoot;
  51. @Value("${file.url:#{null}}")
  52. private String fileUrl;
  53. private static final Logger logger = LogManager.getLogger(FaceIdenService.class);
  54. /**
  55. * 处理各摄像头上传的图像,去除没有人脸的、不是正面的、不符合标准的、连拍的图像
  56. * @throws Exception
  57. */
  58. public void handleCameraImage() throws Exception {
  59. logger.info("FaceIdenService.handleCameraImage start...");
  60. File originImageDirFile = new File(idenRoot + "data/origin/camera/image");
  61. //使用摄像头编码做目录名,里面图像的名称上加上拍照时间,
  62. // 比如 20211222123223_76639ced-6409-11ec-b8f9-fa163e4e1e9f.jpg
  63. if (originImageDirFile.isDirectory()) {
  64. File[] cameraCodeDirs = originImageDirFile.listFiles();
  65. if(cameraCodeDirs != null && cameraCodeDirs.length > 0){
  66. logger.info("FaceIdenService.handleCameraImage 1...");
  67. //初始化引擎,加载人员图像人脸特征库
  68. String personImageDir = idenRoot + "data/final/person/image";
  69. //递归获取人员图像目录下的图像文件
  70. File[] imgPersonFiles = FileUtil.getFiles(personImageDir);
  71. logger.info("FaceIdenService.handleCameraImage 2...");
  72. FaceMonitor faceMonitorPerson = null;
  73. if(imgPersonFiles.length > 0){
  74. faceMonitorPerson = FaceIdenTool.initFaceMonitor(idenRoot,imgPersonFiles);
  75. }
  76. try {
  77. for (File cameraCodedir : cameraCodeDirs) {
  78. if (cameraCodedir.isDirectory()) {
  79. File[] imgFiles = FileUtil.sortByName(cameraCodedir.listFiles());
  80. if (imgFiles != null && imgFiles.length > 0) {
  81. String cameraCode = cameraCodedir.getName();
  82. QueryWrapper<IdenCamera> queryWrapper = new QueryWrapper<>();
  83. queryWrapper.lambda().eq(IdenCamera::getCode, cameraCode);
  84. IdenCamera idenCamera = idenCameraService.getOne(queryWrapper);
  85. if (idenCamera == null) {
  86. continue;
  87. }
  88. logger.info("FaceIdenService.handleCameraImage 3...");
  89. //获取特征码
  90. FaceModel[] faceModels = FaceIdenTool.extractFeature(idenRoot, imgFiles);
  91. logger.info("FaceIdenService.handleCameraImage 4...");
  92. List<IdenFaceImage> idenFaceImageList = new ArrayList<>();
  93. for (int i = 0; i < imgFiles.length; i++) {
  94. logger.info("FaceIdenService.handleCameraImage 41...");
  95. File imgFile = imgFiles[i];
  96. String imgFileName = imgFile.getName();
  97. IdenFaceImage idenFaceImage = new IdenFaceImage();
  98. //识别特征码
  99. if (faceModels[i] != null) {
  100. logger.info("FaceIdenService.handleCameraImage 42...");
  101. String featPtr = ByteUtil.byte2Hex(faceModels[i].getFeatValue());
  102. logger.info("FaceIdenService.handleCameraImage 42...featPtr=="+featPtr);
  103. //没有人脸的、不是正面的、不符合标准的,连拍的图片
  104. if (FaceIdenTool.isBad(featPtr) || isContinuation(cameraCode, imgFileName, featPtr)) {
  105. logger.info("FaceIdenService.handleCameraImage 43...");
  106. File discardDir = new File(imgFile.getParentFile().getAbsolutePath().replace("origin", "discard"));
  107. if (!discardDir.exists()) {
  108. discardDir.mkdirs();
  109. }
  110. File finalImgFile = new File(discardDir, imgFileName);
  111. imgFile.renameTo(finalImgFile);//移动到废弃目录
  112. continue;
  113. } else {
  114. logger.info("FaceIdenService.handleCameraImage 44...");
  115. idenFaceImage.setFeatPtr(featPtr);
  116. //存到redis
  117. redisUtil.hset(RedisKeyConstant.HANDLE_CAMERA_IMAGE_FIRST + "_" + cameraCode, imgFileName, featPtr, RedisKeyConstant.HANDLE_CAMERA_IMAGE_FIRST_TIME);
  118. }
  119. }
  120. logger.info("FaceIdenService.handleCameraImage 5...");
  121. idenFaceImage.setCameraId(idenCamera.getId());
  122. idenFaceImage.setCommunityId(idenCamera.getCommunityId());
  123. String photographPlace = idenCamera.getPlace();
  124. if (StringUtils.isEmpty(photographPlace)) {
  125. IdenCommunity idenCommunity = idenCommunityService.getById(idenCamera.getCommunityId());
  126. if (idenCommunity != null) {
  127. photographPlace = idenCommunity.getName() + "(" + idenCamera.getLongitude() + ":" + idenCamera.getLatitude() + ")";
  128. } else {
  129. photographPlace = "(" + idenCamera.getLongitude() + ":" + idenCamera.getLatitude() + ")";
  130. }
  131. }
  132. idenFaceImage.setPhotographPlace(photographPlace);
  133. idenFaceImage.setLongitude(idenCamera.getLongitude());
  134. idenFaceImage.setLatitude(idenCamera.getLatitude());
  135. String photographTime = imgFileName.substring(0, imgFileName.indexOf("_"));
  136. idenFaceImage.setPhotographTime(DateUtils.strToDate(photographTime, "yyyyMMddHHmmss"));
  137. idenFaceImage.setDataDate(photographTime.substring(0, 8));
  138. File finalDir = new File(imgFile.getParentFile().getAbsolutePath().replace("origin", "final"));
  139. if (!finalDir.exists()) {
  140. finalDir.mkdirs();
  141. }
  142. logger.info("FaceIdenService.handleCameraImage ...finalDir == " + finalDir.getAbsolutePath());
  143. logger.info("FaceIdenService.handleCameraImage ...imgFile.getName() == " + imgFileName);
  144. File finalImgFile = new File(finalDir, imgFileName);
  145. logger.info("FaceIdenService.handleCameraImage ...finalImgFile == " + finalImgFile.getAbsolutePath());
  146. imgFile.renameTo(finalImgFile);//移动到最终目录
  147. idenFaceImage.setImage(fileUrl + "camera/image/" + cameraCode + "/" + finalImgFile.getName());
  148. //和人员图像库比对特征码,关联personId
  149. if (faceModels[i] != null && faceMonitorPerson != null) {
  150. FaceRetrieveResultVO faceRetrieveResultVO = FaceIdenTool.getHitResult(faceMonitorPerson, faceModels[i]);
  151. if (faceRetrieveResultVO != null) {
  152. int hitIndex = faceRetrieveResultVO.getIndex();
  153. IdenPerson idenPerson = personService.getPersonIdByImageFileName(imgPersonFiles[hitIndex].getName());
  154. if (idenPerson != null) {
  155. idenFaceImage.setPersonId(idenPerson.getId());
  156. idenFaceImage.setUid(idenPerson.getUid());
  157. idenFaceImage.setType(idenPerson.getType());
  158. idenFaceImage.setGender(idenPerson.getGender());
  159. float score = faceRetrieveResultVO.getScore();
  160. BigDecimal b = new BigDecimal(score);
  161. double similarity = b.divide(new BigDecimal(100)).setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue();
  162. idenFaceImage.setSimilarity(similarity);
  163. }
  164. }
  165. }
  166. logger.info("FaceIdenService.handleCameraImage 6...");
  167. if (idenFaceImage.getPersonId() == null) { //没有关联上,是陌生人
  168. idenFaceImage.setType(PersonTypeEnum.STRANGER.getValue());
  169. //查询以前的陌生人图库,进行人脸识别,若是同一个人,得到uid, 设置为一样
  170. String uid = relevanceBeforeFace(idenFaceImage.getFeatPtr());
  171. if (StringUtils.isEmpty(uid)) {
  172. uid = UUID.randomUUID().toString();
  173. }
  174. idenFaceImage.setUid(uid);
  175. }
  176. idenFaceImage.setCreateTime(new Date());
  177. idenFaceImageList.add(idenFaceImage);
  178. }
  179. logger.info("FaceIdenService.handleCameraImage 7...");
  180. //把图像存到图库中
  181. if (CollUtil.isNotEmpty(idenFaceImageList)) {
  182. idenFaceImageService.saveBatch(idenFaceImageList);
  183. }
  184. }
  185. }
  186. }
  187. } finally {
  188. //释放人脸引擎
  189. FaceIdenTool.releaseEngine(faceMonitorPerson);
  190. }
  191. }
  192. }
  193. logger.info("FaceIdenService.handleCameraImage end");
  194. }
  195. //查询以前的陌生人图库,进行人脸识别,若是同一个人,得到uid
  196. private String relevanceBeforeFace(String featPtrVisitor){
  197. QueryWrapper<IdenFaceImage> queryWrapper = new QueryWrapper<>();
  198. queryWrapper.lambda().eq(IdenFaceImage::getType, PersonTypeEnum.STRANGER.getValue())
  199. .eq(IdenFaceImage::getHandleWarningStatus,HandleWarningStatusEnum.HANDLED.getValue());
  200. //queryWrapper.last("limit 500"); //TODO 数据量大了需要分批处理 优化,以及是否区分小区
  201. List<IdenFaceImage> list = this.idenFaceImageService.list(queryWrapper);
  202. if (CollUtil.isNotEmpty(list)) {
  203. List<String> featPtrList = new ArrayList<>();
  204. for(IdenFaceImage idenFaceImage : list) {
  205. String featPtr = idenFaceImage.getFeatPtr();
  206. featPtrList.add(featPtr);
  207. }
  208. FaceRetrieveResultVO vo = FaceIdenTool.isHit(idenRoot,featPtrVisitor,featPtrList);
  209. if(vo != null) {
  210. return list.get(vo.getIndex()).getUid();
  211. }
  212. }
  213. return null;
  214. }
  215. //是否连拍
  216. private boolean isContinuation(String cameraCode,String imgFileName, String featPtr) {
  217. logger.info("FaceIdenService.isContinuation ...1");
  218. String photographTime = imgFileName.substring(0, imgFileName.indexOf("_"));
  219. Long photographTimeLong = DateUtils.strToDate(photographTime,"yyyyMMddHHmmss").getTime();
  220. //获取data/final/camera/image下图片
  221. String originImageDir= idenRoot + "data/final/camera/image";
  222. logger.info("FaceIdenService.isContinuation ...2");
  223. File[] imgFiles = FileUtil.getFiles(originImageDir);
  224. List<String> featPtrList = new ArrayList<>();
  225. if (imgFiles != null && imgFiles.length > 0) {
  226. for(File imgFile : imgFiles) {
  227. String photographTimeTmp = imgFileName.substring(0, imgFile.getName().indexOf("_"));
  228. Long photographTimeTmpLong = DateUtils.strToDate(photographTimeTmp,"yyyyMMddHHmmss").getTime();
  229. logger.info("FaceIdenService.isContinuation ...3");
  230. //目标图片和以前图片拍照时间相差2分钟内
  231. if (photographTimeLong <= photographTimeTmpLong + 2 * 60 * 1000) {
  232. String featPtrTmp = (String)redisUtil.hget(RedisKeyConstant.HANDLE_CAMERA_IMAGE_FIRST + "_" + cameraCode, imgFile.getName());
  233. if(StringUtils.isNotEmpty(featPtrTmp)){
  234. featPtrList.add(featPtrTmp);
  235. }
  236. }
  237. }
  238. logger.info("FaceIdenService.isContinuation ...4");
  239. FaceRetrieveResultVO vo = FaceIdenTool.isHit(idenRoot,featPtr,featPtrList);
  240. logger.info("FaceIdenService.isContinuation ... 5==" + vo);
  241. return vo != null;
  242. } else {
  243. return false;
  244. }
  245. }
  246. /**
  247. * 把摄像头上传的图像解开为一帧帧图片,放到图像目录下,等待识别引擎处理
  248. * @throws Exception
  249. */
  250. public void handleCameraVideo() throws Exception {
  251. logger.info("FaceIdenService.handleCameraVideo start...");
  252. File originVideoDirFile = new File(idenRoot + "data/origin/camera/video");
  253. //使用摄像头编码做目录名,里面存放视频,名称里包含拍摄结束时间
  254. // 比如 20211217123343_76639ced-6409-11ec-b8f9-fa883e4e1e9f.mp4
  255. if (originVideoDirFile.isDirectory()) {
  256. File[] cameraCodeDirs = originVideoDirFile.listFiles();
  257. if (cameraCodeDirs != null && cameraCodeDirs.length > 0) {
  258. for(File cameraCodedir : cameraCodeDirs) {
  259. if (cameraCodedir.isDirectory()) {
  260. File[] videoFiles = FileUtil.sortByName(cameraCodedir.listFiles());
  261. if (videoFiles != null && videoFiles.length > 0) {
  262. String cameraCode = cameraCodedir.getName();
  263. QueryWrapper<IdenCamera> queryWrapper = new QueryWrapper<>();
  264. queryWrapper.lambda().eq(IdenCamera::getCode,cameraCode);
  265. IdenCamera idenCamera = idenCameraService.getOne(queryWrapper);
  266. if(idenCamera == null){
  267. continue;
  268. }
  269. for(File videoFile : videoFiles){
  270. String videoFileName = videoFile.getName();
  271. String shootEndTimeStr = videoFileName.substring(0, videoFileName.indexOf("_"));
  272. Date shootEndTime = DateUtils.strToDate(shootEndTimeStr,"yyyyMMddHHmmss");
  273. Long duration = VideoUtil.fetchAllPic(videoFile,idenRoot + "data/origin/camera/image/" + cameraCode, shootEndTime);
  274. File finalDir = new File(videoFile.getParentFile().getAbsolutePath().replace("origin","final"));
  275. if(!finalDir.exists()){
  276. finalDir.mkdirs();
  277. }
  278. logger.info("FaceIdenService.handleCameraVideo ...finalDir == " + finalDir.getAbsolutePath());
  279. logger.info("FaceIdenService.handleCameraVideo ...videoFile.getName() == " + videoFileName);
  280. File finalvideoFile = new File(finalDir, videoFileName);
  281. logger.info("FaceIdenService.handleCameraVideo ...finalvideoFile == " + finalvideoFile.getAbsolutePath());
  282. videoFile.renameTo(finalvideoFile);//移动到最终目录
  283. IdenCameraVideo idenCameraVideo = new IdenCameraVideo();
  284. idenCameraVideo.setVideoUrl(fileUrl + "camera/video/" + cameraCode + "/" + videoFileName);
  285. idenCameraVideo.setCameraId(idenCamera.getId());
  286. idenCameraVideo.setCommunityId(idenCamera.getCommunityId());
  287. idenCameraVideo.setName(videoFileName.substring(0,videoFileName.lastIndexOf(".mp4")));
  288. Long begin = shootEndTime.getTime() - duration;
  289. idenCameraVideo.setPhotographBeginTime(new Date(begin));
  290. idenCameraVideo.setPhotographEndTime(shootEndTime);
  291. idenCameraVideo.setDuration(duration);
  292. idenCameraVideo.setCreateTime(new Date());
  293. idenCameraVideoService.save(idenCameraVideo);
  294. }
  295. }
  296. }
  297. }
  298. }
  299. }
  300. logger.info("FaceIdenService.handleCameraVideo end");
  301. }
  302. }