diff --git a/config.py b/config.py index d4d340e..7775000 100644 --- a/config.py +++ b/config.py @@ -25,22 +25,26 @@ DEFAULT_CONFIG = { "camera_index": 0, "capture_interval": 60, "auto_analyze": True, - "refresh_interval": 5, # 页面刷新间隔(秒) - "display_limit": 20, # 显示最近多少条 + "refresh_interval": 5, + "display_limit": 20, - # 检测算法开关 - "use_yolo": True, # YOLO 检测(最准确) - "use_haar_cascade": False, # Haar Cascade 人体检测(备用) - "use_mediapipe_face": True, # MediaPipe 人脸检测 - "use_face_recognition": True, # face_recognition 人脸识别 + # 人体检测设置(YOLO) + "use_yolo": True, + "yolo_min_confidence": 0.3, - # 连续性判断配置 - "confirm_frames": 3, # 连续几帧确认 - "min_detection_confidence": 0.3, # 检测置信度阈值 + # 人员识别设置 + "use_face_recognition": True, + "use_mediapipe_face": True, + "use_color_histogram": True, + "face_match_threshold": 0.6, - # AI大模型分析开关 - "use_vision_api": False, # 是否使用大模型分析(默认关闭) - "vision_api_trigger": "person_change", # 触发条件:person_change/motion/brightness/always + # 连续判断设置 + "confirm_frames": 3, + "leave_frames": 2, + + # AI大模型分析 + "use_vision_api": False, + "vision_api_trigger": "person_change", # Vision API 配置 "vision_api_url": os.environ.get("VISION_API_URL", "https://dashscope.aliyuncs.com/compatible-mode/v1"), diff --git a/person_manager.py b/person_manager.py index 7fd42ff..5ddca43 100644 --- a/person_manager.py +++ b/person_manager.py @@ -61,25 +61,30 @@ class PersonManager: # 配置 self.config = { - 'face_match_threshold': 0.6, # 人脸匹配阈值 - 'unknown_person_id': 'unknown', # 未知人员ID - 'max_persons': 100, # 最大人员数量 + 'face_match_threshold': 0.6, + 'unknown_person_id': 'unknown', + 'max_persons': 100, - # 方案1: 参数调整 - 'mediapipe_min_confidence': 0.3, # 降低阈值,更容易检测 - 'mediapipe_model_selection': 1, # 1: 远距离模型 - 'haar_scale_factor': 1.05, # Haar更细粒度 - 'haar_min_neighbors': 2, # 降低邻居要求 - - # 方案2: 连续性判断 - 'confirm_frames': 3, # 连续几帧确认 - 'leave_frames': 2, # 连续几帧消失才算离开 + # YOLO 检测参数 + 'yolo_min_confidence': 0.3, + 'confirm_frames': 3, + 'leave_frames': 2, } - # 方案2: 追踪状态(连续判断) - self.tracked_persons = {} # {person_id: {'frames': count, 'confirmed': bool}} - self.prev_persons = [] # 前一帧检测到的人 - self.confirmation_buffer = {} # 确认缓冲区 + # 从配置文件读取参数 + try: + from config import config_mgr + self.config['yolo_min_confidence'] = config_mgr.get('yolo_min_confidence', 0.3) + self.config['face_match_threshold'] = config_mgr.get('face_match_threshold', 0.6) + self.config['confirm_frames'] = config_mgr.get('confirm_frames', 3) + self.config['leave_frames'] = config_mgr.get('leave_frames', 2) + except: + pass + + # 追踪状态(连续判断) + self.tracked_persons = {} + self.prev_persons = [] + self.confirmation_buffer = {} # 统计 self.total_detections = 0 @@ -151,6 +156,8 @@ class PersonManager: if self.yolo_detector is None: return persons + min_conf = self.config.get('yolo_min_confidence', 0.3) + try: results = self.yolo_detector(image, classes=[0], verbose=False) # class 0 = person @@ -160,7 +167,6 @@ class PersonManager: conf = box.conf[0].item() # 置信度过滤 - min_conf = self.config.get('mediapipe_min_confidence', 0.3) if conf < min_conf: continue @@ -370,7 +376,7 @@ class PersonManager: dict: {'person_id': str, 'name': str, 'is_new': bool} """ if threshold is None: - threshold = self.config['face_match_threshold'] + threshold = self.config.get('face_match_threshold', 0.6) if face_encoding is None: return {'person_id': 'unknown', 'name': 'Unknown', 'is_new': False} @@ -621,8 +627,8 @@ class PersonManager: 'person_id': p['person_id'], 'name': p['name'], 'visit_count': p['visit_count'], - 'first_seen': p['first_seen'], - 'last_seen': p['last_seen'] + 'first_seen': p['first_seen'], # 已经精确到秒 + 'last_seen': p['last_seen'], # 已经精确到秒 } for p in self.persons.values() ] diff --git a/web/static/app.js b/web/static/app.js index fdc553c..e38726e 100644 --- a/web/static/app.js +++ b/web/static/app.js @@ -472,8 +472,8 @@ function loadPersonsList() { var item = document.createElement('div'); item.className = 'person-item'; - var firstSeen = new Date(person.first_seen).toLocaleDateString(); - var lastSeen = new Date(person.last_seen).toLocaleDateString(); + var firstSeen = new Date(person.first_seen).toLocaleString(); + var lastSeen = new Date(person.last_seen).toLocaleString(); item.innerHTML = '
' + '' + person.name + '' + @@ -537,15 +537,19 @@ function loadSettingsForm() { document.getElementById('setting-display-limit').value = config.display_limit || 20; document.getElementById('setting-refresh-interval').value = config.refresh_interval || 5; - // Detection algorithm settings + // Person Detection (YOLO) document.getElementById('setting-use-yolo').checked = config.use_yolo !== false; - document.getElementById('setting-use-mediapipe').checked = config.use_mediapipe_face !== false; - document.getElementById('setting-use-haar').checked = config.use_haar_cascade === true; - document.getElementById('setting-use-face-rec').checked = config.use_face_recognition !== false; + document.getElementById('setting-yolo-confidence').value = config.yolo_min_confidence || 0.3; - // Confirmation settings + // Person Identification + document.getElementById('setting-use-face-rec').checked = config.use_face_recognition !== false; + document.getElementById('setting-use-mediapipe').checked = config.use_mediapipe_face !== false; + document.getElementById('setting-use-color-hist').checked = config.use_color_histogram !== false; + document.getElementById('setting-match-threshold').value = config.face_match_threshold || 0.6; + + // Confirmation Settings document.getElementById('setting-confirm-frames').value = config.confirm_frames || 3; - document.getElementById('setting-min-confidence').value = config.min_detection_confidence || 0.3; + document.getElementById('setting-leave-frames').value = config.leave_frames || 2; // Vision API settings document.getElementById('setting-use-vision-api').checked = config.use_vision_api === true; @@ -568,15 +572,19 @@ function saveSettings() { display_limit: parseInt(document.getElementById('setting-display-limit').value), refresh_interval: parseInt(document.getElementById('setting-refresh-interval').value), - // Detection algorithms + // Person Detection (YOLO) use_yolo: document.getElementById('setting-use-yolo').checked, - use_haar_cascade: document.getElementById('setting-use-haar').checked, - use_mediapipe_face: document.getElementById('setting-use-mediapipe').checked, - use_face_recognition: document.getElementById('setting-use-face-rec').checked, + yolo_min_confidence: parseFloat(document.getElementById('setting-yolo-confidence').value), - // Confirmation settings + // Person Identification + use_face_recognition: document.getElementById('setting-use-face-rec').checked, + use_mediapipe_face: document.getElementById('setting-use-mediapipe').checked, + use_color_histogram: document.getElementById('setting-use-color-hist').checked, + face_match_threshold: parseFloat(document.getElementById('setting-match-threshold').value), + + // Confirmation Settings confirm_frames: parseInt(document.getElementById('setting-confirm-frames').value), - min_detection_confidence: parseFloat(document.getElementById('setting-min-confidence').value), + leave_frames: parseInt(document.getElementById('setting-leave-frames').value), // Vision API use_vision_api: document.getElementById('setting-use-vision-api').checked, diff --git a/web/static/index.html b/web/static/index.html index e31d8ed..11bdd55 100644 --- a/web/static/index.html +++ b/web/static/index.html @@ -138,40 +138,59 @@
-

Detection Algorithms

+

👤 Person Detection (YOLO)

- + - YOLOv8 nano - Best accuracy + Human body detection
- - - High precision face detection -
-
- - - Traditional body detection (backup) -
-
- - - Identify same person + + + Detection threshold (lower = more sensitive)
-

Confirmation Settings

+

🔍 Person Identification

+
+ + + Best accuracy (requires dlib) +
+
+ + + Face landmarks detection +
+
+ + + Backup method +
+
+ + + Lower = stricter matching +
+
+ +
+

✅ Confirmation Settings

- Frames to confirm detection + Frames to confirm change
- - - Detection confidence threshold + + + Frames to confirm leaving +
+
+ +
+

🤖 AI Analysis