feat(face): 添加低阈值检测功能

- 在 FaceConstant 中添加 FACE_LOW_THRESHOLD_PFX 常量
- 在 SearchFaceRespVo 中添加 lowThreshold 字段
- 在 FaceServiceImpl 中实现记录低阈值检测人脸的逻辑
- 在 TaskFaceServiceImpl 中添加低阈值检测的判断和结果设置
This commit is contained in:
2025-09-13 15:04:06 +08:00
parent 91e68c3272
commit bf672a8af7
4 changed files with 44 additions and 0 deletions

View File

@@ -5,4 +5,5 @@ public class FaceConstant {
public static final String USER_FACE_DB_NAME="userFace";
public static final String FACE_USER_URL_PFX="face:user:url:";
public static final String FACE_RECOGNITION_COUNT_PFX="face:recognition:count:";
public static final String FACE_LOW_THRESHOLD_PFX="face:low:threshold:";
}

View File

@@ -10,4 +10,5 @@ public class SearchFaceRespVo {
private List<Long> sampleListIds;
private String searchResultJson;
private Float firstMatchRate;
private boolean lowThreshold;
}

View File

@@ -69,6 +69,7 @@ import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import static com.ycwl.basic.constant.FaceConstant.FACE_LOW_THRESHOLD_PFX;
import static com.ycwl.basic.constant.FaceConstant.FACE_RECOGNITION_COUNT_PFX;
import static com.ycwl.basic.constant.FaceConstant.USER_FACE_DB_NAME;
import static com.ycwl.basic.constant.StorageConstant.USER_FACE;
@@ -333,6 +334,12 @@ public class FaceServiceImpl implements FaceService {
}
} else {
log.warn("人脸匹配无结果:faceId={}", faceId);
// 检查低阈值检测结果,如果为true则记录该人脸ID到Redis
if (scenicDbSearchResult != null && scenicDbSearchResult.isLowThreshold()) {
recordLowThresholdFace(faceId);
log.debug("触发低阈值检测,记录faceId: {}", faceId);
}
}
return scenicDbSearchResult;
@@ -835,4 +842,28 @@ public class FaceServiceImpl implements FaceService {
log.error("记录人脸识别次数失败:faceId={}", faceId, e);
}
}
/**
* 记录低阈值检测的人脸ID到Redis
*
* @param faceId 人脸ID
*/
private void recordLowThresholdFace(Long faceId) {
if (faceId == null) {
return;
}
try {
String redisKey = FACE_LOW_THRESHOLD_PFX + faceId;
// 设置标记,表示该人脸ID触发了低阈值检测
redisTemplate.opsForValue().set(redisKey, "1", 2, TimeUnit.DAYS);
log.debug("记录低阈值检测人脸:faceId={}", faceId);
} catch (Exception e) {
// 记录失败不应影响主要业务逻辑,只记录错误日志
log.error("记录低阈值检测人脸失败:faceId={}", faceId, e);
}
}
}

View File

@@ -171,6 +171,7 @@ public class TaskFaceServiceImpl implements TaskFaceService {
request.setLimit(200);
FaceDetectLog logEntity = FaceDetectLog.quickCreate(reason, request);
float threshold = 0;
float lowThreshold = 100;
ScenicConfigManager scenicConfig = null;
if (StringUtils.isNumeric(dbName)) {
scenicConfig = scenicRepository.getScenicConfigManager(Long.valueOf(dbName));
@@ -178,6 +179,9 @@ public class TaskFaceServiceImpl implements TaskFaceService {
if (scenicConfig.getFloat("face_score_threshold") != null) {
threshold = scenicConfig.getFloat("face_score_threshold") / 100F;
}
if (scenicConfig.getFloat("face_score_low_threshold") != null) {
lowThreshold = scenicConfig.getFloat("face_score_low_threshold") / 100F;
}
}
} else if (StringUtils.isNumeric(dbName.replace(USER_FACE_DB_NAME, ""))) {
Long scenicId = Long.valueOf(dbName.replace(USER_FACE_DB_NAME, ""));
@@ -186,6 +190,9 @@ public class TaskFaceServiceImpl implements TaskFaceService {
if (scenicConfig.getFloat("face_score_threshold") != null) {
threshold = scenicConfig.getFloat("face_score_threshold") / 100F;
}
if (scenicConfig.getFloat("face_score_low_threshold") != null) {
lowThreshold = scenicConfig.getFloat("face_score_low_threshold") / 100F;
}
}
}
final float _threshold = threshold;
@@ -212,6 +219,10 @@ public class TaskFaceServiceImpl implements TaskFaceService {
.filter(StringUtils::isNumeric)
.map(Long::valueOf)
.collect(Collectors.toList());
float _lowThreshold = lowThreshold;
boolean isLowThreshold = records.stream()
.anyMatch(record -> record.getScore() > _lowThreshold);
respVo.setLowThreshold(isLowThreshold);
allFaceSampleIds = records.stream()
.map(SearchFaceResultItem::getExtData)
.filter(StringUtils::isNumeric)