From c1803c16f17161b17dd5bd9e86cd7b79e08fcbc6 Mon Sep 17 00:00:00 2001 From: Tian jianyong <11429339@qq.com> Date: Fri, 26 Dec 2025 15:34:25 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=80=A7=E8=83=BD=EF=BC=9B?= =?UTF-8?q?=E8=A7=A3=E5=86=B3=E5=9B=BE=E5=83=8F=E5=8F=8D=E8=BD=AC=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- face_rec.py | 104 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 64 insertions(+), 40 deletions(-) diff --git a/face_rec.py b/face_rec.py index 8ee3f54..c559f9e 100644 --- a/face_rec.py +++ b/face_rec.py @@ -57,6 +57,10 @@ class FaceRecognitionSystem: # 识别记录(防止重复识别) self.recognition_history = {} # {person_id: last_recognition_time} + # 定期清理机制 + self.last_cleanup_time = time.time() + self.cleanup_interval = 60 # 清理间隔(秒) + # 显示相关变量 self.current_display_frame = None self.last_detection_result = None # 最后的检测结果 @@ -107,7 +111,7 @@ class FaceRecognitionSystem: self.stream_retry_cooldown = 10 # 重试冷却时间(秒) # 添加异步推流队列和线程 - self.stream_frame_queue = queue.Queue(maxsize=10) # 限制队列大小防止内存溢出 + self.stream_frame_queue = queue.Queue(maxsize=30) # 增加到30帧缓冲 self.stream_thread = None self.stream_thread_running = False @@ -119,6 +123,9 @@ class FaceRecognitionSystem: self.camera_retry_cooldown = 3 # 重试冷却时间(秒) self.camera_max_failures = 5 # 触发重新初始化的失败次数阈值 + # 缓存屏幕尺寸,避免每帧重新获取 + self._cache_screen_size() + # 二维码显示相关 self.qrcode_image_path = self.config.get('qrcode', {}).get('image_path', 'qrcode.png') self.qrcode_display_duration = self.config.get('qrcode', {}).get('display_duration', 10) @@ -139,6 +146,22 @@ class FaceRecognitionSystem: self.stderr_thread = None self.stderr_thread_running = False + # 缓存屏幕尺寸,避免每帧重新获取 + self._cache_screen_size() + + def _cache_screen_size(self): + """缓存屏幕尺寸,提高性能""" + self.screen_width = 1920 + self.screen_height = 1080 + try: + import screeninfo + screen = screeninfo.get_monitors()[0] + self.screen_width = screen.width + self.screen_height = screen.height + self.logger.info(f"屏幕尺寸已缓存: {self.screen_width}x{self.screen_height}") + except Exception as e: + self.logger.debug(f"无法获取屏幕尺寸,使用默认尺寸: {e}") + def _force_cleanup_ffmpeg(self): """强制清理所有FFmpeg相关资源 - 防止多进程推流""" self.logger.info("=== 开始清理FFmpeg资源 ===") @@ -361,17 +384,8 @@ class FaceRecognitionSystem: # 在视频帧上绘制机器人状态 frame_with_status = self._draw_robot_status_on_video(frame) - # 获取屏幕尺寸并拉伸视频帧到全屏 - try: - import screeninfo - screen = screeninfo.get_monitors()[0] - screen_width, screen_height = screen.width, screen.height - - # 拉伸视频帧到屏幕尺寸 - frame_with_status = cv2.resize(frame_with_status, (screen_width, screen_height), interpolation=cv2.INTER_LINEAR) - except: - # 如果获取屏幕信息失败,使用默认尺寸 - frame_with_status = cv2.resize(frame_with_status, (1920, 1080), interpolation=cv2.INTER_LINEAR) + # 使用缓存的屏幕尺寸拉伸视频帧到全屏 + frame_with_status = cv2.resize(frame_with_status, (self.screen_width, self.screen_height), interpolation=cv2.INTER_LINEAR) # 显示视频帧 cv2.imshow(self.video_window_name, frame_with_status) @@ -678,20 +692,11 @@ class FaceRecognitionSystem: # 创建二维码窗口 cv2.namedWindow(self.qrcode_window_name, cv2.WINDOW_NORMAL | cv2.WINDOW_GUI_NORMAL) - qr_height, qr_width = qr_image.shape[:2] - try: - import screeninfo - screen = screeninfo.get_monitors()[0] - canvas_width = int(screen.width) - canvas_height = int(screen.height) - x_pos = 0 - y_pos = 0 - except Exception as e: - self.logger.warning(f"无法获取屏幕信息,使用默认尺寸: {e}") - canvas_width = max(qr_width * 2, 1920) - canvas_height = max(qr_height, 1080) - x_pos = 0 - y_pos = 0 + # 使用缓存的屏幕尺寸 + canvas_width = self.screen_width + canvas_height = self.screen_height + x_pos = 0 + y_pos = 0 rendered = self._build_qrcode_instruction_canvas(qr_image, (canvas_width, canvas_height)) if rendered is None: @@ -1098,8 +1103,8 @@ class FaceRecognitionSystem: if self.ffmpeg_process.stdin and not self.ffmpeg_process.stdin.closed: # 简单的写入,依赖较小的缓冲区和flush_packets self.ffmpeg_process.stdin.write(frame_bytes) - # 关键:定期flush避免缓冲区堆积 - if total_frames % 30 == 0: # 每30帧flush一次 + # 每5帧flush一次,避免缓冲区堆积 + if total_frames % 5 == 0: self.ffmpeg_process.stdin.flush() consecutive_failures = 0 @@ -1372,6 +1377,28 @@ class FaceRecognitionSystem: return elapsed >= cooldown + def cleanup_expired_records(self): + """清理过期的识别记录,防止内存无限增长""" + current_time = time.time() + if current_time - self.last_cleanup_time < self.cleanup_interval: + return + + self.last_cleanup_time = current_time + + # 清理超过1小时的记录 + expiry_seconds = 3600 + expired_keys = [] + for person_id, last_time in self.recognition_history.items(): + if isinstance(last_time, datetime): + elapsed = (datetime.now() - last_time).total_seconds() + if elapsed > expiry_seconds: + expired_keys.append(person_id) + + if expired_keys: + for key in expired_keys: + del self.recognition_history[key] + self.logger.debug(f"清理了 {len(expired_keys)} 条过期识别记录") + def cv2_add_chinese_text(self, img: np.ndarray, text: str, position: Tuple[int, int], font: ImageFont.FreeTypeFont, text_color: Tuple[int, int, int]) -> np.ndarray: """在OpenCV图像上添加中文文本""" @@ -1698,6 +1725,9 @@ class FaceRecognitionSystem: try: while True: + # 定期清理过期记录,防止内存无限增长 + self.cleanup_expired_records() + # 检查机器人角色并显示/隐藏视频 self._check_role_and_display_video() @@ -1879,19 +1909,13 @@ class FaceRecognitionSystem: # 绘制信息 display_frame = self.draw_info_on_frame(frame) + + # 使用缓存的屏幕尺寸拉伸视频帧到全屏 + display_frame = cv2.resize(display_frame, (self.screen_width, self.screen_height), interpolation=cv2.INTER_LINEAR) - # 获取屏幕尺寸并拉伸视频帧到全屏 - try: - import screeninfo - screen = screeninfo.get_monitors()[0] - screen_width, screen_height = screen.width, screen.height - - # 拉伸视频帧到屏幕尺寸 - display_frame = cv2.resize(display_frame, (screen_width, screen_height), interpolation=cv2.INTER_LINEAR) - except: - # 如果获取屏幕信息失败,使用默认尺寸 - display_frame = cv2.resize(display_frame, (1920, 1080), interpolation=cv2.INTER_LINEAR) - + # 镜像翻转:使画面与实际场景一致(取消默认的左右镜像) + display_frame = cv2.flip(display_frame, 1) + cv2.imshow(window_name, display_frame) # 检查二维码显示是否超时