FaceIdenService.java 18 KB

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