diff --git a/src/main/java/com/ycwl/basic/model/pc/faceDetectLog/resp/MatchLocalRecord.java b/src/main/java/com/ycwl/basic/model/pc/faceDetectLog/resp/MatchLocalRecord.java index afd520f..0c305eb 100644 --- a/src/main/java/com/ycwl/basic/model/pc/faceDetectLog/resp/MatchLocalRecord.java +++ b/src/main/java/com/ycwl/basic/model/pc/faceDetectLog/resp/MatchLocalRecord.java @@ -13,4 +13,5 @@ public class MatchLocalRecord { private Float confidence; private String idStr; private Date shotDate; + private Boolean matched; } diff --git a/src/main/java/com/ycwl/basic/model/pc/scenic/entity/ScenicConfigEntity.java b/src/main/java/com/ycwl/basic/model/pc/scenic/entity/ScenicConfigEntity.java index 6ee8857..7051797 100644 --- a/src/main/java/com/ycwl/basic/model/pc/scenic/entity/ScenicConfigEntity.java +++ b/src/main/java/com/ycwl/basic/model/pc/scenic/entity/ScenicConfigEntity.java @@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableName; import com.fasterxml.jackson.annotation.JsonFormat; import lombok.Data; +import java.math.BigDecimal; import java.util.Date; /** @@ -60,4 +61,8 @@ public class ScenicConfigEntity { private Integer videoSourceStoreDay; private Integer imageSourceStoreDay; private Integer userSourceExpireDay; + /** + * 人脸识别阈值,是0~100的数值 + */ + private Float faceScoreThreshold; } diff --git a/src/main/java/com/ycwl/basic/service/impl/pc/FaceServiceImpl.java b/src/main/java/com/ycwl/basic/service/impl/pc/FaceServiceImpl.java index 68e2ba6..3d68e45 100644 --- a/src/main/java/com/ycwl/basic/service/impl/pc/FaceServiceImpl.java +++ b/src/main/java/com/ycwl/basic/service/impl/pc/FaceServiceImpl.java @@ -15,6 +15,7 @@ import com.ycwl.basic.model.mobile.statistic.req.StatisticsRecordAddReq; import com.ycwl.basic.model.pc.face.entity.FaceEntity; import com.ycwl.basic.model.pc.face.req.FaceReqQuery; import com.ycwl.basic.model.pc.face.resp.FaceRespVO; +import com.ycwl.basic.model.pc.faceSample.entity.FaceSampleEntity; import com.ycwl.basic.model.pc.source.entity.MemberSourceEntity; import com.ycwl.basic.model.pc.source.entity.SourceEntity; import com.ycwl.basic.model.task.resp.SearchFaceRespVo; @@ -129,7 +130,7 @@ public class FaceServiceImpl implements FaceService { String faceUrl = adapter.uploadFile(file, filePath, fileName); Long newFaceId = SnowFlakeUtil.getLongId(); Long oldFaceId = null; - SearchFaceRespVo userDbSearchResult = faceService.searchFace(USER_FACE_DB_NAME+scenicId, faceUrl); + SearchFaceRespVo userDbSearchResult = faceService.searchFace(USER_FACE_DB_NAME+scenicId, faceUrl, "判断是否为用户上传过的人脸"); float strictScore = 0.6F; if (userDbSearchResult == null) { // 都是null了,那得是新的 @@ -203,6 +204,27 @@ public class FaceServiceImpl implements FaceService { return null; } SearchFaceRespVo scenicDbSearchResult = faceService.searchFace(face.getScenicId(), face.getFaceUrl()); + // 写死逻辑 + if (scenicDbSearchResult.getSampleListIds() != null && scenicDbSearchResult.getFirstMatchRate() != null && !scenicDbSearchResult.getSampleListIds().isEmpty()) { + if (scenicDbSearchResult.getSampleListIds().size() < 2) { + // 补救逻辑 + Long faceSampleId = scenicDbSearchResult.getSampleListIds().get(0); + FaceSampleEntity faceSample = faceRepository.getFaceSample(faceSampleId); + if (faceSample != null) { + // 以这个结果为人脸库的匹配结果 + scenicDbSearchResult = faceService.searchFace(face.getScenicId().toString(), faceSample.getFaceUrl(), "补救措施1:人脸数太少只有一张"); + } + } else if (scenicDbSearchResult.getFirstMatchRate() > 0.75 && scenicDbSearchResult.getSampleListIds().size() < 2) { + // 如果匹配度高于阈值,则使用景区第一张人脸去匹配景区库 + // 找第一张人脸 + Long faceSampleId = scenicDbSearchResult.getSampleListIds().get(0); + FaceSampleEntity faceSample = faceRepository.getFaceSample(faceSampleId); + if (faceSample != null) { + // 以这个结果为人脸库的匹配结果 + scenicDbSearchResult = faceService.searchFace(face.getScenicId().toString(), faceSample.getFaceUrl(), "补救措施2:存在得分够高但是结果少"); + } + } + } FaceEntity faceEntity = new FaceEntity(); faceEntity.setId(faceId); faceEntity.setScore(scenicDbSearchResult.getScore()); diff --git a/src/main/java/com/ycwl/basic/service/task/TaskFaceService.java b/src/main/java/com/ycwl/basic/service/task/TaskFaceService.java index 37b9c57..b34a975 100644 --- a/src/main/java/com/ycwl/basic/service/task/TaskFaceService.java +++ b/src/main/java/com/ycwl/basic/service/task/TaskFaceService.java @@ -13,6 +13,8 @@ public interface TaskFaceService { SearchFaceRespVo searchFace(String dbName, String faceUrl); + SearchFaceRespVo searchFace(String dbName, String faceUrl, String reason); + AddFaceSampleRespVo addFaceSample(Long faceSampleId); AddFaceSampleRespVo addFaceSample(String dbName, String entityId, String faceUrl, String extData); diff --git a/src/main/java/com/ycwl/basic/service/task/impl/TaskFaceServiceImpl.java b/src/main/java/com/ycwl/basic/service/task/impl/TaskFaceServiceImpl.java index 8d6714a..0c76f30 100644 --- a/src/main/java/com/ycwl/basic/service/task/impl/TaskFaceServiceImpl.java +++ b/src/main/java/com/ycwl/basic/service/task/impl/TaskFaceServiceImpl.java @@ -117,7 +117,7 @@ public class TaskFaceServiceImpl implements TaskFaceService { return vo; } Long scenicId = faceRespVO.getScenicId(); - SearchFaceRespVo respVo = searchFace(scenicId.toString(), faceRespVO.getFaceUrl()); + SearchFaceRespVo respVo = searchFace(scenicId.toString(), faceRespVO.getFaceUrl(), "系统定时任务检索"); if (respVo != null) { FaceEntity faceEntity = new FaceEntity(); faceEntity.setId(faceId); @@ -162,11 +162,16 @@ public class TaskFaceServiceImpl implements TaskFaceService { @Override public SearchFaceRespVo searchFace(Long scenicId, String faceUrl) { - return searchFace(scenicId.toString(), faceUrl); + return searchFace(scenicId.toString(), faceUrl, "预留字段"); } @Override public SearchFaceRespVo searchFace(String dbName, String faceUrl) { + return searchFace(dbName, faceUrl, "预留字段"); + } + + @Override + public SearchFaceRespVo searchFace(String dbName, String faceUrl, String reason) { assureFaceDB(dbName); IAcsClient client = getClient(); SearchFaceRequest request = new SearchFaceRequest(); @@ -174,11 +179,21 @@ public class TaskFaceServiceImpl implements TaskFaceService { request.setImageUrl(faceUrl); request.setLimit(100); // request.setQualityScoreThreshold(60f); - FaceDetectLog log = FaceDetectLog.quickCreate("预留字段", request); + FaceDetectLog log = FaceDetectLog.quickCreate(reason, request); try { searchFaceLimiter.acquire(); } catch (InterruptedException ignored) { } + float threshold = 0.525F; + if (StringUtils.isNumeric(dbName)) { + ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(Long.valueOf(dbName)); + if (scenicConfig != null) { + if (scenicConfig.getFaceScoreThreshold() != null) { + threshold = scenicConfig.getFaceScoreThreshold() / 100F; + } + } + } + final float _threshold = threshold; try { SearchFaceResponse response = client.getAcsResponse(request); log.fillResponse(response); @@ -195,7 +210,7 @@ public class TaskFaceServiceImpl implements TaskFaceService { List records = matchList.get(0).getFaceItems(); log.setMatchRawRecord(records); List faceSampleIds = records.stream() - .filter(record -> record.getScore() > 0.525F) + .filter(record -> record.getScore() > _threshold) .map(SearchFaceResponse.Data.MatchListItem.FaceItemsItem::getExtraData) .filter(StringUtils::isNumeric) .map(Long::valueOf) @@ -205,7 +220,6 @@ public class TaskFaceServiceImpl implements TaskFaceService { return respVo; } catch (Exception e) { log.setMatchRawResult("识别错误,错误为:["+e.getLocalizedMessage()+"]"); - e.printStackTrace(); throw new BaseException(e.getMessage()); } finally { new Thread(() -> { @@ -221,6 +235,7 @@ public class TaskFaceServiceImpl implements TaskFaceService { if (device != null) { record.setDeviceName(device.getName()); } + record.setMatched(item.getScore() > _threshold); record.setFaceUrl(faceSample.getFaceUrl()); record.setShotDate(faceSample.getCreateAt()); } diff --git a/src/main/java/com/ycwl/basic/task/DownloadNotificationTasker.java b/src/main/java/com/ycwl/basic/task/DownloadNotificationTasker.java index 2d2b9b4..c5da82e 100644 --- a/src/main/java/com/ycwl/basic/task/DownloadNotificationTasker.java +++ b/src/main/java/com/ycwl/basic/task/DownloadNotificationTasker.java @@ -17,6 +17,7 @@ import com.ycwl.basic.repository.TemplateRepository; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Profile; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @@ -28,6 +29,7 @@ import java.util.Map; @Component @EnableScheduling @Slf4j +@Profile("prod") public class DownloadNotificationTasker { @Autowired private ScenicRepository scenicRepository; diff --git a/src/main/java/com/ycwl/basic/task/DynamicTaskGenerator.java b/src/main/java/com/ycwl/basic/task/DynamicTaskGenerator.java index 424e84c..72d2ba3 100644 --- a/src/main/java/com/ycwl/basic/task/DynamicTaskGenerator.java +++ b/src/main/java/com/ycwl/basic/task/DynamicTaskGenerator.java @@ -116,7 +116,7 @@ public class DynamicTaskGenerator { return; } log.info("开始执行任务:{}", task); - SearchFaceRespVo userDbSearchResult = faceService.searchFace(USER_FACE_DB_NAME+faceSample.getScenicId(), faceSample.getFaceUrl()); + SearchFaceRespVo userDbSearchResult = faceService.searchFace(USER_FACE_DB_NAME+faceSample.getScenicId(), faceSample.getFaceUrl(), "预约流程检索"); // 如果人脸样本ID在人脸样本库中,则创建任务 if (!userDbSearchResult.getSampleListIds().isEmpty()) { log.info("人脸样本ID在人脸样本库中,创建任务:{}", task); diff --git a/src/main/resources/mapper/ScenicMapper.xml b/src/main/resources/mapper/ScenicMapper.xml index c031849..aa132a4 100644 --- a/src/main/resources/mapper/ScenicMapper.xml +++ b/src/main/resources/mapper/ScenicMapper.xml @@ -96,6 +96,7 @@ video_source_store_day=#{videoSourceStoreDay}, image_source_store_day=#{imageSourceStoreDay}, user_source_expire_day=#{userSourceExpireDay}, + face_score_threshold=#{faceScoreThreshold}, force_finish_time=#{forceFinishTime} where id = #{id}