FaceIdenService.java 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  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. List<File> imgPersonFileList = new ArrayList<>();
  71. imgPersonFileList = FileUtil.getFiles(new File(personImageDir),imgPersonFileList);
  72. File[] imgPersonFiles = new File[imgPersonFileList.size()];
  73. imgPersonFiles = imgPersonFileList.toArray(imgPersonFiles);
  74. logger.info("FaceIdenService.handleCameraImage 2...");
  75. FaceMonitor faceMonitorPerson = null;
  76. if(imgPersonFiles.length > 0){
  77. faceMonitorPerson = FaceIdenTool.initFaceMonitor(idenRoot,imgPersonFiles);
  78. }
  79. try {
  80. for (File cameraCodedir : cameraCodeDirs) {
  81. if (cameraCodedir.isDirectory()) {
  82. File[] imgFiles = FileUtil.sortByName(cameraCodedir.listFiles());
  83. if (imgFiles != null && imgFiles.length > 0) {
  84. String cameraCode = cameraCodedir.getName();
  85. QueryWrapper<IdenCamera> queryWrapper = new QueryWrapper<>();
  86. queryWrapper.lambda().eq(IdenCamera::getCode, cameraCode);
  87. IdenCamera idenCamera = idenCameraService.getOne(queryWrapper);
  88. if (idenCamera == null) {
  89. continue;
  90. }
  91. logger.info("FaceIdenService.handleCameraImage 3...");
  92. //获取特征码
  93. FaceModel[] faceModels = FaceIdenTool.extractFeature(idenRoot, imgFiles);
  94. logger.info("FaceIdenService.handleCameraImage 4...");
  95. List<IdenFaceImage> idenFaceImageList = new ArrayList<>();
  96. for (int i = 0; i < imgFiles.length; i++) {
  97. File imgFile = imgFiles[i];
  98. String imgFileName = imgFile.getName();
  99. IdenFaceImage idenFaceImage = new IdenFaceImage();
  100. //识别特征码
  101. if (faceModels[i] != null) {
  102. String featPtr = ByteUtil.byte2Hex(faceModels[i].getFeatValue());
  103. //没有人脸的、不是正面的、不符合标准的,连拍的图片
  104. if (FaceIdenTool.isBad(featPtr) || isContinuation(cameraCode, imgFileName, featPtr)) {
  105. File discardDir = new File(imgFile.getParentFile().getAbsolutePath().replace("origin", "discard"));
  106. if (!discardDir.exists()) {
  107. discardDir.mkdirs();
  108. }
  109. File finalImgFile = new File(discardDir, imgFileName);
  110. imgFile.renameTo(finalImgFile);//移动到废弃目录
  111. continue;
  112. } else {
  113. idenFaceImage.setFeatPtr(featPtr);
  114. //存到redis
  115. redisUtil.hset(RedisKeyConstant.HANDLE_CAMERA_IMAGE_FIRST + "_" + cameraCode, imgFileName, featPtr, RedisKeyConstant.HANDLE_CAMERA_IMAGE_FIRST_TIME);
  116. }
  117. }
  118. logger.info("FaceIdenService.handleCameraImage 5...");
  119. idenFaceImage.setCameraId(idenCamera.getId());
  120. idenFaceImage.setCommunityId(idenCamera.getCommunityId());
  121. String photographPlace = idenCamera.getPlace();
  122. if (StringUtils.isEmpty(photographPlace)) {
  123. IdenCommunity idenCommunity = idenCommunityService.getById(idenCamera.getCommunityId());
  124. if (idenCommunity != null) {
  125. photographPlace = idenCommunity.getName() + "(" + idenCamera.getLongitude() + ":" + idenCamera.getLatitude() + ")";
  126. } else {
  127. photographPlace = "(" + idenCamera.getLongitude() + ":" + idenCamera.getLatitude() + ")";
  128. }
  129. }
  130. idenFaceImage.setPhotographPlace(photographPlace);
  131. idenFaceImage.setLongitude(idenCamera.getLongitude());
  132. idenFaceImage.setLatitude(idenCamera.getLatitude());
  133. String photographTime = imgFileName.substring(0, imgFileName.indexOf("_"));
  134. idenFaceImage.setPhotographTime(DateUtils.strToDate(photographTime, "yyyyMMddHHmmss"));
  135. idenFaceImage.setDataDate(photographTime.substring(0, 8));
  136. File finalDir = new File(imgFile.getParentFile().getAbsolutePath().replace("origin", "final"));
  137. if (!finalDir.exists()) {
  138. finalDir.mkdirs();
  139. }
  140. logger.info("FaceIdenService.handleCameraImage ...finalDir == " + finalDir.getAbsolutePath());
  141. logger.info("FaceIdenService.handleCameraImage ...imgFile.getName() == " + imgFileName);
  142. File finalImgFile = new File(finalDir, imgFileName);
  143. logger.info("FaceIdenService.handleCameraImage ...finalImgFile == " + finalImgFile.getAbsolutePath());
  144. imgFile.renameTo(finalImgFile);//移动到最终目录
  145. idenFaceImage.setImage(fileUrl + "camera/image/" + cameraCode + "/" + finalImgFile.getName());
  146. //和人员图像库比对特征码,关联personId
  147. if (faceModels[i] != null && faceMonitorPerson != null) {
  148. FaceRetrieveResultVO faceRetrieveResultVO = FaceIdenTool.getHitResult(faceMonitorPerson, faceModels[i]);
  149. if (faceRetrieveResultVO != null) {
  150. int hitIndex = faceRetrieveResultVO.getIndex();
  151. IdenPerson idenPerson = personService.getPersonIdByImageFileName(imgPersonFiles[hitIndex].getName());
  152. if (idenPerson != null) {
  153. idenFaceImage.setPersonId(idenPerson.getId());
  154. idenFaceImage.setUid(idenPerson.getUid());
  155. idenFaceImage.setType(idenPerson.getType());
  156. idenFaceImage.setGender(idenPerson.getGender());
  157. float score = faceRetrieveResultVO.getScore();
  158. BigDecimal b = new BigDecimal(score);
  159. double similarity = b.divide(new BigDecimal(100)).setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue();
  160. idenFaceImage.setSimilarity(similarity);
  161. }
  162. }
  163. }
  164. logger.info("FaceIdenService.handleCameraImage 6...");
  165. if (idenFaceImage.getPersonId() == null) { //没有关联上,是陌生人
  166. idenFaceImage.setType(PersonTypeEnum.STRANGER.getValue());
  167. //查询以前的陌生人图库,进行人脸识别,若是同一个人,得到uid, 设置为一样
  168. String uid = relevanceBeforeFace(idenFaceImage.getFeatPtr());
  169. if (StringUtils.isEmpty(uid)) {
  170. uid = UUID.randomUUID().toString();
  171. }
  172. idenFaceImage.setUid(uid);
  173. }
  174. idenFaceImage.setCreateTime(new Date());
  175. idenFaceImageList.add(idenFaceImage);
  176. }
  177. logger.info("FaceIdenService.handleCameraImage 7...");
  178. //把图像存到图库中
  179. if (CollUtil.isNotEmpty(idenFaceImageList)) {
  180. idenFaceImageService.saveBatch(idenFaceImageList);
  181. }
  182. }
  183. }
  184. }
  185. } finally {
  186. //释放人脸引擎
  187. FaceIdenTool.releaseEngine(faceMonitorPerson);
  188. }
  189. }
  190. }
  191. logger.info("FaceIdenService.handleCameraImage end");
  192. }
  193. //查询以前的陌生人图库,进行人脸识别,若是同一个人,得到uid
  194. private String relevanceBeforeFace(String featPtrVisitor){
  195. QueryWrapper<IdenFaceImage> queryWrapper = new QueryWrapper<>();
  196. queryWrapper.lambda().eq(IdenFaceImage::getType, PersonTypeEnum.STRANGER.getValue())
  197. .eq(IdenFaceImage::getHandleWarningStatus,HandleWarningStatusEnum.HANDLED.getValue());
  198. //queryWrapper.last("limit 500"); //TODO 数据量大了需要分批处理 优化,以及是否区分小区
  199. List<IdenFaceImage> list = this.idenFaceImageService.list(queryWrapper);
  200. if (CollUtil.isNotEmpty(list)) {
  201. List<String> featPtrList = new ArrayList<>();
  202. for(IdenFaceImage idenFaceImage : list) {
  203. String featPtr = idenFaceImage.getFeatPtr();
  204. featPtrList.add(featPtr);
  205. }
  206. FaceRetrieveResultVO vo = FaceIdenTool.isHit(idenRoot,featPtrVisitor,featPtrList);
  207. if(vo != null) {
  208. return list.get(vo.getIndex()).getUid();
  209. }
  210. }
  211. return null;
  212. }
  213. //是否连拍
  214. private boolean isContinuation(String cameraCode,String imgFileName, String featPtr) {
  215. String photographTime = imgFileName.substring(0, imgFileName.indexOf("_"));
  216. Long photographTimeLong = DateUtils.strToDate(photographTime,"yyyyMMddHHmmss").getTime();
  217. //获取data/final/camera/image下图片
  218. File originImageDirFile = new File(idenRoot + "data/final/camera/image");
  219. File[] imgFiles = originImageDirFile.listFiles();
  220. List<String> featPtrList = new ArrayList<>();
  221. if (imgFiles != null && imgFiles.length > 0) {
  222. for(File imgFile : imgFiles) {
  223. String photographTimeTmp = imgFileName.substring(0, imgFile.getName().indexOf("_"));
  224. Long photographTimeTmpLong = DateUtils.strToDate(photographTimeTmp,"yyyyMMddHHmmss").getTime();
  225. //目标图片和以前图片拍照时间相差2分钟内
  226. if (photographTimeLong <= photographTimeTmpLong + 2 * 60 * 1000) {
  227. String featPtrTmp = (String)redisUtil.hget(RedisKeyConstant.HANDLE_CAMERA_IMAGE_FIRST + "_" + cameraCode, imgFile.getName());
  228. if(StringUtils.isNotEmpty(featPtrTmp)){
  229. featPtrList.add(featPtrTmp);
  230. }
  231. }
  232. }
  233. FaceRetrieveResultVO vo = FaceIdenTool.isHit(idenRoot,featPtr,featPtrList);
  234. logger.info("FaceIdenService.isContinuation ... ==" + vo);
  235. return vo != null;
  236. } else {
  237. return false;
  238. }
  239. }
  240. /**
  241. * 把摄像头上传的图像解开为一帧帧图片,放到图像目录下,等待识别引擎处理
  242. * @throws Exception
  243. */
  244. public void handleCameraVideo() throws Exception {
  245. logger.info("FaceIdenService.handleCameraVideo start...");
  246. File originVideoDirFile = new File(idenRoot + "data/origin/camera/video");
  247. //使用摄像头编码做目录名,里面存放视频,名称里包含拍摄结束时间
  248. // 比如 20211217123343_76639ced-6409-11ec-b8f9-fa883e4e1e9f.mp4
  249. if (originVideoDirFile.isDirectory()) {
  250. File[] cameraCodeDirs = originVideoDirFile.listFiles();
  251. if (cameraCodeDirs != null && cameraCodeDirs.length > 0) {
  252. for(File cameraCodedir : cameraCodeDirs) {
  253. if (cameraCodedir.isDirectory()) {
  254. File[] videoFiles = FileUtil.sortByName(cameraCodedir.listFiles());
  255. if (videoFiles != null && videoFiles.length > 0) {
  256. String cameraCode = cameraCodedir.getName();
  257. QueryWrapper<IdenCamera> queryWrapper = new QueryWrapper<>();
  258. queryWrapper.lambda().eq(IdenCamera::getCode,cameraCode);
  259. IdenCamera idenCamera = idenCameraService.getOne(queryWrapper);
  260. if(idenCamera == null){
  261. continue;
  262. }
  263. for(File videoFile : videoFiles){
  264. String videoFileName = videoFile.getName();
  265. String shootEndTimeStr = videoFileName.substring(0, videoFileName.indexOf("_"));
  266. Date shootEndTime = DateUtils.strToDate(shootEndTimeStr,"yyyyMMddHHmmss");
  267. Long duration = VideoUtil.fetchAllPic(videoFile,idenRoot + "data/origin/camera/image/" + cameraCode, shootEndTime);
  268. File finalDir = new File(videoFile.getParentFile().getAbsolutePath().replace("origin","final"));
  269. if(!finalDir.exists()){
  270. finalDir.mkdirs();
  271. }
  272. logger.info("FaceIdenService.handleCameraVideo ...finalDir == " + finalDir.getAbsolutePath());
  273. logger.info("FaceIdenService.handleCameraVideo ...videoFile.getName() == " + videoFileName);
  274. File finalvideoFile = new File(finalDir, videoFileName);
  275. logger.info("FaceIdenService.handleCameraVideo ...finalvideoFile == " + finalvideoFile.getAbsolutePath());
  276. videoFile.renameTo(finalvideoFile);//移动到最终目录
  277. IdenCameraVideo idenCameraVideo = new IdenCameraVideo();
  278. idenCameraVideo.setVideoUrl(fileUrl + "camera/video/" + cameraCode + "/" + videoFileName);
  279. idenCameraVideo.setCameraId(idenCamera.getId());
  280. idenCameraVideo.setCommunityId(idenCamera.getCommunityId());
  281. idenCameraVideo.setName(videoFileName.substring(0,videoFileName.lastIndexOf(".mp4")));
  282. Long begin = shootEndTime.getTime() - duration;
  283. idenCameraVideo.setPhotographBeginTime(new Date(begin));
  284. idenCameraVideo.setPhotographEndTime(shootEndTime);
  285. idenCameraVideo.setDuration(duration);
  286. idenCameraVideo.setCreateTime(new Date());
  287. idenCameraVideoService.save(idenCameraVideo);
  288. }
  289. }
  290. }
  291. }
  292. }
  293. }
  294. logger.info("FaceIdenService.handleCameraImage end");
  295. }
  296. }