suntianwu 3 vuotta sitten
vanhempi
commit
9c0c36cac8

+ 68 - 7
src/main/java/com/iden/bms/face/FaceIdenService.java

@@ -8,6 +8,8 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.face.monitor.FaceMonitor;
 import com.face.monitor.model.FaceModel;
 import com.iden.bms.service.PersonService;
+import com.iden.common.cache.RedisKeyConstant;
+import com.iden.common.cache.RedisUtil;
 import com.iden.common.entity.IdenCamera;
 import com.iden.common.entity.IdenCommunity;
 import com.iden.common.entity.IdenFaceImage;
@@ -50,6 +52,8 @@ public class FaceIdenService {
     @Resource
     private PersonService personService;
 
+    @Resource
+    private RedisUtil redisUtil;
 
     @Value("${iden.root:#{null}}")
     private String idenRoot;
@@ -59,7 +63,7 @@ public class FaceIdenService {
     private static final Logger logger = LogManager.getLogger(FaceIdenService.class);
 
     /**
-     *  处理各摄像头上传的图像,去除模糊的、没有人脸的、连拍的图像
+     *  处理各摄像头上传的图像,去除没有人脸的、不是正面的、不符合标准的、连拍的图像
      * @throws Exception
      */
     public void handleCameraImage() throws Exception {
@@ -96,7 +100,27 @@ public class FaceIdenService {
                             List<IdenFaceImage> idenFaceImageList = new ArrayList<>();
                             for(int i = 0; i < imgFiles.length; i++) {
                                 File imgFile  = imgFiles[i];
+                                String imgFileName = imgFile.getName();
                                 IdenFaceImage idenFaceImage = new IdenFaceImage();
+                                //识别特征码
+                                if (faceModels[i] != null) {
+                                    String featPtr = ByteUtil.byte2Hex(faceModels[i].getFeatValue());
+                                    //没有人脸的、不是正面的、不符合标准的,连拍的图片
+                                    if(isBad(featPtr) || isContinuation(cameraCode,imgFileName,featPtr)) {
+                                        File discardDir = new File(imgFile.getParentFile().getAbsolutePath().replace("origin","discardDir"));
+                                        if(!discardDir.exists()){
+                                            discardDir.mkdirs();
+                                        }
+                                        File finalImgFile = new File(discardDir, imgFileName);
+                                        imgFile.renameTo(finalImgFile);//移动到废弃目录
+                                        continue;
+                                    } else {
+                                        idenFaceImage.setFeatPtr(featPtr);
+                                        //存到redis
+                                        redisUtil.hset(RedisKeyConstant.HANDLE_CAMERA_IMAGE_FIRST + "_" + cameraCode, imgFileName, featPtr, RedisKeyConstant.HANDLE_CAMERA_IMAGE_FIRST_TIME);
+                                    }
+
+                                }
                                 idenFaceImage.setCameraId(idenCamera.getId());
                                 idenFaceImage.setCommunityId(idenCamera.getCommunityId());
                                 String photographPlace = idenCamera.getPlace();
@@ -109,15 +133,10 @@ public class FaceIdenService {
                                 idenFaceImage.setPhotographPlace(photographPlace);
                                 idenFaceImage.setLongitude(idenCamera.getLongitude());
                                 idenFaceImage.setLatitude(idenCamera.getLatitude());
-                                String imgFileName = imgFile.getName();
+
                                 String photographTime = imgFileName.substring(0, imgFileName.indexOf("_"));
                                 idenFaceImage.setPhotographTime(DateUtils.strToDate(photographTime,"yyyyMMddHHmmss"));
 
-                                //识别特征码
-                                if(faceModels[i] != null){
-                                    idenFaceImage.setFeatPtr(ByteUtil.byte2Hex(faceModels[i].getFeatValue()));
-                                }
-
                                 File finalDir = new File(imgFile.getParentFile().getAbsolutePath().replace("origin","final"));
                                 if(!finalDir.exists()){
                                     finalDir.mkdirs();
@@ -175,6 +194,48 @@ public class FaceIdenService {
     }
 
 
+    private boolean isBad(String featPtr){
+        if (StringUtils.isEmpty(featPtr)) {
+            return true;
+        }
+        char[] chars = featPtr.toCharArray();
+
+        for (char c : chars){
+            if(!String.valueOf(c).equals("0")){
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private boolean isContinuation(String cameraCode,String imgFileName, String featPtr) {
+        String photographTime = imgFileName.substring(0, imgFileName.indexOf("_"));
+        Long photographTimeLong = DateUtils.strToDate(photographTime,"yyyyMMddHHmmss").getTime();
+        //获取cameraCode/final下图片
+        File originImageDirFile = new File(idenRoot + "data/final/camera/image");
+        File[] imgFiles = originImageDirFile.listFiles();
+         List<String> featPtrList = new ArrayList<>();
+        if (imgFiles != null && imgFiles.length > 0) {
+            for(File imgFile : imgFiles) {
+                String photographTimeTmp = imgFileName.substring(0, imgFile.getName().indexOf("_"));
+                Long photographTimeTmpLong = DateUtils.strToDate(photographTimeTmp,"yyyyMMddHHmmss").getTime();
+
+                //目标图片和以前图片拍照时间相差2分钟内
+                if (photographTimeLong <= photographTimeTmpLong + 2 * 60 * 1000) {
+                    String featPtrTmp = (String)redisUtil.hget(RedisKeyConstant.HANDLE_CAMERA_IMAGE_FIRST + "_" + cameraCode, imgFile.getName());
+                    featPtrList.add(featPtrTmp);
+                }
+            }
+            return FaceIdenTool.isHit(idenRoot,featPtr,featPtrList);
+
+        } else {
+            return false;
+        }
+
+
+
+
+    }
     /**
      *
      * @throws Exception

+ 26 - 0
src/main/java/com/iden/bms/face/FaceIdenTool.java

@@ -110,11 +110,37 @@ public class FaceIdenTool {
                 FaceRetrieveResultVO faceRetrieveResultVO = new FaceRetrieveResultVO();
                 faceRetrieveResultVO.setIndex(index);
                 faceRetrieveResultVO.setScore(score);
+                return faceRetrieveResultVO;
             }
         }
         return null;
     }
 
+    public static boolean isHit(String idenRoot, String featPtrVisitor, List<String> featPtrList){
+        //初始化引擎
+        FaceMonitor faceMonitor = new FaceMonitor();
+        faceMonitor.init(idenRoot + "face/model", 0);
+        FaceModel[] dataset = new FaceModel[featPtrList.size()];
+        for (int i = 0; i < featPtrList.size(); i++) {
+            String featPtr = featPtrList.get(i);
+            FaceModel faceModel = new FaceModel();
+            faceModel.setName(String.valueOf(i));
+            faceModel.setPersonId(i);
+            faceModel.setFeatValue(ByteUtil.hex2Byte(featPtr));
+        }
+        faceMonitor.loadFaceDataset(dataset);
+        FaceModel faceModelPtrVisitor = new FaceModel();
+        faceModelPtrVisitor.setName(String.valueOf(0));
+        faceModelPtrVisitor.setPersonId(0);
+        faceModelPtrVisitor.setFeatValue(ByteUtil.hex2Byte(featPtrVisitor));
+        FaceRetrieveResultVO vo = getHitResult(faceMonitor,faceModelPtrVisitor);
+        if(vo != null) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
     /**
      * 使用dataPath的图片去库里查找,返回命中结果
      * @param idenRoot

+ 2 - 2
src/main/java/com/iden/bms/schedule/FaceIdenSchedule.java

@@ -30,11 +30,11 @@ public class FaceIdenSchedule {
      * 处理摄像头上传的图像
      */
     @Async
-    @Scheduled(cron = "0 0/5 * * * ?")
+    @Scheduled(cron = "0 0/1 * * * ?")
     public void handleCameraImage() {
         String key = RedisKeyConstant.HANDLE_CAMERA_IMAGE;
         String requestId = UUID.randomUUID().toString();
-        boolean result = redisUtil.tryLock(key,requestId,5 * 60);
+        boolean result = redisUtil.tryLock(key,requestId,10 * 60);
         try {
             if (result) {
                 faceIdenService.handleCameraImage();

+ 4 - 0
src/main/java/com/iden/common/cache/RedisKeyConstant.java

@@ -23,4 +23,8 @@ public class RedisKeyConstant {
     public static final String LOGIN_VALIDATE_CODE = "LOGIN:VALIDATE_CODE";
     public static final int LOGIN_VALIDATE_CODE_TIME = 1800;
 
+    //10分钟
+    public static final String HANDLE_CAMERA_IMAGE_FIRST = "HANDLE:CAMERA_IMAGE_FIRST";
+    public static final int HANDLE_CAMERA_IMAGE_FIRST_TIME = 60 * 10;
+
 }

+ 45 - 0
src/test/java/com/face/monitor/ByteUtil.java

@@ -0,0 +1,45 @@
+package com.face.monitor;
+
+public class ByteUtil {
+    /**
+     *  将byte[]数组转换成16进制字符。一个byte生成两个字符,长度对应1:2
+     * @param bytes,输入byte[]数组
+     * @return 16进制字符
+     */
+    public static String byte2Hex(byte[] bytes) {
+        if (bytes == null) {
+            return null;
+        }
+        StringBuilder builder = new StringBuilder();
+        // 遍历byte[]数组,将每个byte数字转换成16进制字符,再拼接起来成字符串
+        for (int i = 0; i < bytes.length; i++) {
+            // 每个byte转换成16进制字符时,bytes[i] & 0xff如果高位是0,输出将会去掉,所以+0x100(在更高位加1),再截取后两位字符
+            builder.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
+        }
+        return builder.toString();
+    }
+
+    /**
+     *  将16进制字符转换成byte[]数组。与byte2Hex功能相反。
+     * @param string 16进制字符串
+     * @return byte[]数组
+     */
+    public static byte[] hex2Byte(String string) {
+        if (string == null || string.length() < 1) {
+            return null;
+        }
+        // 因为一个byte生成两个字符,长度对应1:2,所以byte[]数组长度是字符串长度一半
+        byte[] bytes = new byte[string.length() / 2];
+        // 遍历byte[]数组,遍历次数是字符串长度一半
+        for (int i = 0; i < string.length() / 2; i++) {
+            // 截取没两个字符的前一个,将其转为int数值
+            int high = Integer.parseInt(string.substring(i * 2, i * 2 + 1), 16);
+            // 截取没两个字符的后一个,将其转为int数值
+            int low = Integer.parseInt(string.substring(i * 2 + 1, i * 2 + 2), 16);
+            // 高位字符对应的int值*16+低位的int值,强转成byte数值即可
+            // 如dd,高位13*16+低位13=221(强转成byte二进制11011101,对应十进制-35)
+            bytes[i] = (byte) (high * 16 + low);
+        }
+        return bytes;
+    }
+}

+ 6 - 4
src/test/java/com/face/monitor/FaceTest.java

@@ -24,7 +24,7 @@ public class FaceTest {
         //提取人脸特征,并保存为注册人员库demo-test.cpp
         FaceModel[] dataset = extractFeature(faceMonitor);
         for(int i = 0; i < dataset.length; i++) {
-            System.out.println("getFeatValue==" + dataset[i].getFeatValue());
+            System.out.println("getFeatValue==" + ByteUtil.byte2Hex(dataset[i].getFeatValue()));
             System.out.println("getPersonId==" + dataset[i].getPersonId());
             System.out.println("getName==" + dataset[i].getName());
         }
@@ -44,10 +44,10 @@ public class FaceTest {
         System.out.printf(Locale.CHINA, "new data num: :%d\n", databaseSize);
         //监控视频帧,这里为了简单演示,传入静态图片
         //target
-        String registerData = "./data/0.jpg";
+        String registerData = "./data/10.jpg";
         watchFrame(faceMonitor, registerData);
         //vistor
-        registerData = "./data/5.jpg";
+        registerData = "./data/15.jpg";
         watchFrame(faceMonitor, registerData);
         //获取目标人识别结果
         RecogResult recogResult = faceMonitor.finishMonitorWithRes(1);
@@ -71,14 +71,16 @@ public class FaceTest {
                 faceRecogRetrieveResult.getOnePredictIds()[0], faceRecogRetrieveResult.getOnePredictScores()[0]);
         System.out.printf(Locale.CHINA, "55query hit top person id: : %d score: %f\n",
                 faceRecogRetrieveResult.getOnePredictIds()[1], faceRecogRetrieveResult.getOnePredictScores()[1]);
+      faceMonitor.releaseEngine();
     }
 
     public static FaceModel[] extractFeature(FaceMonitor faceMonitor) {
         //简单演示,提取5张人脸
         String faceTestDir = "./data/";
         List<byte[]> faceTestImageList = new ArrayList<>();
-        for (int i = 0; i < 5; i++) {
+        for (int i = 12; i < 13; i++) {
             String faceFilePath = String.format(Locale.CHINA, "%s%d.jpg", faceTestDir, i);
+            System.out.println("faceFilePath==" + faceFilePath);
             faceTestImageList.add(readFileBytes(faceFilePath));
         }
         return faceMonitor.extractFeature(faceTestImageList);