You've already forked FrameTour-BE
refactor(face): 移除样本筛选轨迹功能及相关枚举
- 删除 FaceRecognitionFilterReason 枚举类 - 移除 SampleFilterTrace 类及其相关逻辑 - 简化样本筛选方法,去除轨迹记录功能- 更新 FaceServiceImpl 和 TaskFaceServiceImpl 中的调用逻辑 - 移除 SearchFaceRespVo 中的 filterTrace 字段- 清理无用的 import语句和相关代码引用
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
package com.ycwl.basic.model.mobile.face;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.ycwl.basic.model.pc.face.enums.FaceRecognitionFilterReason;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@@ -19,10 +19,7 @@ public class FaceRecognitionUpdateReq {
|
||||
*/
|
||||
private List<Long> manualAcceptedSampleIds;
|
||||
|
||||
/**
|
||||
* 用户主动排除的样本ID列表。
|
||||
*/
|
||||
private List<Long> manualRejectedSampleIds;
|
||||
|
||||
|
||||
/**
|
||||
* 是否强制重新走一次识别流程。
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
package com.ycwl.basic.model.pc.face.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 标识系统在过滤识别样本时的原因,便于前端渲染提示。
|
||||
*/
|
||||
@Getter
|
||||
public enum FaceRecognitionFilterReason {
|
||||
SCORE_BELOW_THRESHOLD("score_below_threshold", "置信度低于阈值"),
|
||||
OUT_OF_TIME_RANGE("out_of_time_range", "超出景区时间范围限制"),
|
||||
DEVICE_PHOTO_LIMIT("device_photo_limit", "超过设备照片数量限制"),
|
||||
MANUAL_REJECTED("manual_rejected", "已被手动排除");
|
||||
|
||||
private final String code;
|
||||
private final String description;
|
||||
|
||||
FaceRecognitionFilterReason(String code, String description) {
|
||||
this.code = code;
|
||||
this.description = description;
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package com.ycwl.basic.model.task.resp;
|
||||
|
||||
import com.ycwl.basic.model.pc.face.enums.FaceRecognitionFilterReason;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 样本筛选的轨迹信息,记录最终样本集合及各过滤原因。
|
||||
*/
|
||||
@Data
|
||||
public class SampleFilterTrace {
|
||||
private List<Long> acceptedSampleIds;
|
||||
private Map<Long, EnumSet<FaceRecognitionFilterReason>> filteredReasonMap = new HashMap<>();
|
||||
|
||||
public void addReason(Long sampleId, FaceRecognitionFilterReason reason) {
|
||||
if (sampleId == null || reason == null) {
|
||||
return;
|
||||
}
|
||||
filteredReasonMap.computeIfAbsent(sampleId, key -> EnumSet.noneOf(FaceRecognitionFilterReason.class))
|
||||
.add(reason);
|
||||
}
|
||||
|
||||
public Map<Long, EnumSet<FaceRecognitionFilterReason>> getFilteredReasonMap() {
|
||||
if (filteredReasonMap == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
return filteredReasonMap;
|
||||
}
|
||||
}
|
||||
@@ -11,5 +11,4 @@ public class SearchFaceRespVo {
|
||||
private String searchResultJson;
|
||||
private Float firstMatchRate;
|
||||
private boolean lowThreshold;
|
||||
private SampleFilterTrace filterTrace;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ import com.ycwl.basic.model.pc.template.resp.TemplateRespVO;
|
||||
import com.ycwl.basic.model.pc.video.entity.MemberVideoEntity;
|
||||
import com.ycwl.basic.model.pc.video.entity.VideoEntity;
|
||||
import com.ycwl.basic.model.repository.TaskUpdateResult;
|
||||
import com.ycwl.basic.model.task.resp.SampleFilterTrace;
|
||||
|
||||
import com.ycwl.basic.model.task.resp.SearchFaceRespVo;
|
||||
import com.ycwl.basic.repository.DeviceRepository;
|
||||
import com.ycwl.basic.repository.FaceRepository;
|
||||
@@ -1196,13 +1196,9 @@ public class FaceServiceImpl implements FaceService {
|
||||
// 3. 应用后置筛选逻辑
|
||||
if (mergedResult.getSampleListIds() != null && !mergedResult.getSampleListIds().isEmpty()) {
|
||||
List<FaceSampleEntity> allFaceSampleList = faceSampleMapper.listByIds(mergedResult.getSampleListIds());
|
||||
SampleFilterTrace filterTrace = faceService.applySampleFiltersWithTrace(
|
||||
List<Long> filteredSampleIds = faceService.applySampleFilters(
|
||||
mergedResult.getSampleListIds(), allFaceSampleList, scenicConfig);
|
||||
List<Long> filteredSampleIds = filterTrace.getAcceptedSampleIds() == null
|
||||
? Collections.emptyList()
|
||||
: filterTrace.getAcceptedSampleIds();
|
||||
mergedResult.setSampleListIds(filteredSampleIds);
|
||||
mergedResult.setFilterTrace(filterTrace);
|
||||
log.debug("应用后置筛选:原始样本数={}, 筛选后样本数={}",
|
||||
allFaceSampleList.size(), filteredSampleIds.size());
|
||||
}
|
||||
@@ -1280,8 +1276,6 @@ public class FaceServiceImpl implements FaceService {
|
||||
|
||||
List<Long> currentAccepted = parseMatchSampleIds(face.getMatchSampleIds());
|
||||
List<Long> manualAccepted = Optional.ofNullable(req.getManualAcceptedSampleIds()).orElse(Collections.emptyList());
|
||||
List<Long> manualRejected = Optional.ofNullable(req.getManualRejectedSampleIds()).orElse(Collections.emptyList());
|
||||
Set<Long> manualRejectedSet = new HashSet<>(manualRejected);
|
||||
|
||||
LinkedHashSet<Long> finalSampleSet = new LinkedHashSet<>();
|
||||
manualAccepted.stream()
|
||||
@@ -1289,10 +1283,9 @@ public class FaceServiceImpl implements FaceService {
|
||||
.forEach(finalSampleSet::add);
|
||||
currentAccepted.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.filter(id -> !manualRejectedSet.contains(id))
|
||||
.forEach(finalSampleSet::add);
|
||||
|
||||
boolean hasManualChange = !manualAccepted.isEmpty() || !manualRejectedSet.isEmpty();
|
||||
boolean hasManualChange = !manualAccepted.isEmpty();
|
||||
List<Long> finalSampleList = new ArrayList<>(finalSampleSet);
|
||||
boolean needsUpdate = hasManualChange && !finalSampleList.equals(currentAccepted);
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package com.ycwl.basic.service.task;
|
||||
import com.ycwl.basic.facebody.adapter.IFaceBodyAdapter;
|
||||
import com.ycwl.basic.integration.common.manager.ScenicConfigManager;
|
||||
import com.ycwl.basic.model.pc.faceSample.entity.FaceSampleEntity;
|
||||
import com.ycwl.basic.model.task.resp.SampleFilterTrace;
|
||||
import com.ycwl.basic.model.task.resp.SearchFaceRespVo;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
@@ -29,16 +28,4 @@ public interface TaskFaceService {
|
||||
List<Long> applySampleFilters(List<Long> acceptedSampleIds,
|
||||
List<FaceSampleEntity> allFaceSampleList,
|
||||
ScenicConfigManager scenicConfig);
|
||||
|
||||
/**
|
||||
* 带过滤轨迹的样本筛选逻辑。
|
||||
*
|
||||
* @param acceptedSampleIds 已接受的样本ID列表
|
||||
* @param allFaceSampleList 所有人脸样本实体列表
|
||||
* @param scenicConfig 景区配置
|
||||
* @return 包含最终样本及过滤原因的轨迹对象
|
||||
*/
|
||||
SampleFilterTrace applySampleFiltersWithTrace(List<Long> acceptedSampleIds,
|
||||
List<FaceSampleEntity> allFaceSampleList,
|
||||
ScenicConfigManager scenicConfig);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import com.ycwl.basic.model.pc.device.entity.DeviceConfigEntity;
|
||||
import com.ycwl.basic.model.pc.device.entity.DeviceEntity;
|
||||
import com.ycwl.basic.model.pc.face.entity.FaceEntity;
|
||||
import com.ycwl.basic.model.pc.face.resp.FaceRespVO;
|
||||
import com.ycwl.basic.model.pc.face.enums.FaceRecognitionFilterReason;
|
||||
|
||||
import com.ycwl.basic.model.pc.faceDetectLog.entity.FaceDetectLog;
|
||||
import com.ycwl.basic.model.pc.faceDetectLog.resp.MatchLocalRecord;
|
||||
import com.ycwl.basic.model.pc.faceSample.entity.FaceSampleEntity;
|
||||
@@ -31,7 +31,7 @@ import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
|
||||
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;
|
||||
import com.ycwl.basic.model.task.resp.SampleFilterTrace;
|
||||
|
||||
import com.ycwl.basic.repository.DeviceRepository;
|
||||
import com.ycwl.basic.repository.FaceRepository;
|
||||
import com.ycwl.basic.repository.ScenicRepository;
|
||||
@@ -271,18 +271,8 @@ public class TaskFaceServiceImpl implements TaskFaceService {
|
||||
idIndexMap.put(allFaceSampleIds.get(i), i);
|
||||
}
|
||||
allFaceSampleList.sort(Comparator.comparing(sample -> idIndexMap.get(sample.getId())));
|
||||
SampleFilterTrace filterTrace = applySampleFiltersWithTrace(acceptFaceSampleIds, allFaceSampleList, scenicConfig);
|
||||
List<Long> finalAcceptedSampleIds = filterTrace.getAcceptedSampleIds() == null
|
||||
? Collections.emptyList()
|
||||
: filterTrace.getAcceptedSampleIds();
|
||||
Set<Long> initialAcceptedSet = acceptFaceSampleIds == null
|
||||
? Collections.emptySet()
|
||||
: new HashSet<>(acceptFaceSampleIds);
|
||||
for (Long sampleId : allFaceSampleIds) {
|
||||
if (!finalAcceptedSampleIds.contains(sampleId) && !initialAcceptedSet.contains(sampleId)) {
|
||||
filterTrace.addReason(sampleId, FaceRecognitionFilterReason.SCORE_BELOW_THRESHOLD);
|
||||
}
|
||||
}
|
||||
List<Long> finalAcceptedSampleIds = applySampleFilters(acceptFaceSampleIds, allFaceSampleList, scenicConfig);
|
||||
|
||||
List<MatchLocalRecord> collect = new ArrayList<>();
|
||||
for (SearchFaceResultItem item : records) {
|
||||
MatchLocalRecord record = new MatchLocalRecord();
|
||||
@@ -314,7 +304,6 @@ public class TaskFaceServiceImpl implements TaskFaceService {
|
||||
}
|
||||
respVo.setFirstMatchRate(response.getFirstMatchRate());
|
||||
respVo.setSampleListIds(finalAcceptedSampleIds);
|
||||
respVo.setFilterTrace(filterTrace);
|
||||
return respVo;
|
||||
} catch (Exception e) {
|
||||
logEntity.setMatchRawResult("识别错误,错误为:["+e.getLocalizedMessage()+"]");
|
||||
@@ -410,23 +399,11 @@ public class TaskFaceServiceImpl implements TaskFaceService {
|
||||
public List<Long> applySampleFilters(List<Long> acceptedSampleIds,
|
||||
List<FaceSampleEntity> allFaceSampleList,
|
||||
ScenicConfigManager scenicConfig) {
|
||||
SampleFilterTrace trace = applySampleFiltersWithTrace(acceptedSampleIds, allFaceSampleList, scenicConfig);
|
||||
List<Long> result = trace.getAcceptedSampleIds();
|
||||
return result == null ? Collections.emptyList() : result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SampleFilterTrace applySampleFiltersWithTrace(List<Long> acceptedSampleIds,
|
||||
List<FaceSampleEntity> allFaceSampleList,
|
||||
ScenicConfigManager scenicConfig) {
|
||||
SampleFilterTrace trace = new SampleFilterTrace();
|
||||
if (acceptedSampleIds == null || acceptedSampleIds.isEmpty()) {
|
||||
trace.setAcceptedSampleIds(acceptedSampleIds == null ? Collections.emptyList() : new ArrayList<>(acceptedSampleIds));
|
||||
return trace;
|
||||
return acceptedSampleIds == null ? Collections.emptyList() : new ArrayList<>(acceptedSampleIds);
|
||||
}
|
||||
if (allFaceSampleList == null || allFaceSampleList.isEmpty()) {
|
||||
trace.setAcceptedSampleIds(new ArrayList<>(acceptedSampleIds));
|
||||
return trace;
|
||||
return new ArrayList<>(acceptedSampleIds);
|
||||
}
|
||||
|
||||
Map<Long, FaceSampleEntity> sampleMap = allFaceSampleList.stream()
|
||||
@@ -437,29 +414,26 @@ public class TaskFaceServiceImpl implements TaskFaceService {
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
|
||||
if (workingList.isEmpty()) {
|
||||
trace.setAcceptedSampleIds(Collections.emptyList());
|
||||
return trace;
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
Integer tourMinutes = scenicConfig != null ? scenicConfig.getInteger("tour_time") : null;
|
||||
if (tourMinutes != null && tourMinutes > 0) {
|
||||
workingList = filterSampleIdsByTimeRangeWithTrace(workingList, sampleMap, tourMinutes, trace);
|
||||
workingList = filterSampleIdsByTimeRange(workingList, sampleMap, tourMinutes);
|
||||
log.debug("应用时间范围筛选:游览时间限制={}分钟,过滤后数量={}", tourMinutes, workingList.size());
|
||||
} else {
|
||||
log.debug("时间范围逻辑:景区未设置游览时间限制");
|
||||
}
|
||||
|
||||
workingList = applyDevicePhotoLimitWithTrace(workingList, sampleMap, trace);
|
||||
trace.setAcceptedSampleIds(new ArrayList<>(workingList));
|
||||
workingList = applyDevicePhotoLimit(workingList, sampleMap);
|
||||
|
||||
log.debug("样本筛选完成:原始数量={}, 最终数量={}", acceptedSampleIds.size(), workingList.size());
|
||||
return trace;
|
||||
return new ArrayList<>(workingList);
|
||||
}
|
||||
|
||||
private List<Long> filterSampleIdsByTimeRangeWithTrace(List<Long> acceptedSampleIds,
|
||||
Map<Long, FaceSampleEntity> sampleMap,
|
||||
int tourMinutes,
|
||||
SampleFilterTrace trace) {
|
||||
private List<Long> filterSampleIdsByTimeRange(List<Long> acceptedSampleIds,
|
||||
Map<Long, FaceSampleEntity> sampleMap,
|
||||
int tourMinutes) {
|
||||
if (acceptedSampleIds == null || acceptedSampleIds.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
@@ -486,8 +460,6 @@ public class TaskFaceServiceImpl implements TaskFaceService {
|
||||
Date createAt = sample.getCreateAt();
|
||||
if (createAt.after(startDate) && createAt.before(endDate)) {
|
||||
result.add(sampleId);
|
||||
} else {
|
||||
trace.addReason(sampleId, FaceRecognitionFilterReason.OUT_OF_TIME_RANGE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -496,9 +468,8 @@ public class TaskFaceServiceImpl implements TaskFaceService {
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<Long> applyDevicePhotoLimitWithTrace(List<Long> acceptedSampleIds,
|
||||
Map<Long, FaceSampleEntity> sampleMap,
|
||||
SampleFilterTrace trace) {
|
||||
private List<Long> applyDevicePhotoLimit(List<Long> acceptedSampleIds,
|
||||
Map<Long, FaceSampleEntity> sampleMap) {
|
||||
if (acceptedSampleIds == null || acceptedSampleIds.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
@@ -557,15 +528,6 @@ public class TaskFaceServiceImpl implements TaskFaceService {
|
||||
}
|
||||
|
||||
retainedSampleIds.addAll(retainedForDevice);
|
||||
|
||||
if (trace != null) {
|
||||
Set<Long> retainedSet = new HashSet<>(retainedForDevice);
|
||||
for (Long sampleId : deviceSampleIds) {
|
||||
if (!retainedSet.contains(sampleId)) {
|
||||
trace.addReason(sampleId, FaceRecognitionFilterReason.DEVICE_PHOTO_LIMIT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<Long> resultIds = new ArrayList<>(acceptedSampleIds.size());
|
||||
|
||||
Reference in New Issue
Block a user