足部录像版本优化

This commit is contained in:
zhaozilong12 2025-08-21 12:04:14 +08:00
parent 70cf89501a
commit 97ccc120d7
2 changed files with 78 additions and 78 deletions

View File

@ -12,7 +12,7 @@ import base64
import numpy as np import numpy as np
from typing import Optional, Dict, Any, Tuple from typing import Optional, Dict, Any, Tuple
import logging import logging
from collections import deque import queue
import gc import gc
try: try:
@ -60,7 +60,7 @@ class CameraManager(BaseDevice):
# 流控制 # 流控制
self.streaming_thread = None self.streaming_thread = None
# 减小缓存长度保留最近2帧即可避免累计占用 # 减小缓存长度保留最近2帧即可避免累计占用
self.frame_cache = deque(maxlen=int(config.get('frame_cache_len', 2))) self.frame_cache = queue.Queue(maxsize=int(config.get('frame_cache_len', 2)))
self.last_frame = None self.last_frame = None
self.frame_count = 0 self.frame_count = 0
self.dropped_frames = 0 self.dropped_frames = 0
@ -82,11 +82,8 @@ class CameraManager(BaseDevice):
'dropped_frames': 0 'dropped_frames': 0
} }
# 全局帧缓存(用于录制) # 全局帧队列(用于录制)
self.global_frame_cache = {} self.frame_queue = queue.Queue(maxsize=10) # 最大长度10自动丢弃旧帧
self.frame_cache_lock = threading.Lock()
self.max_cache_size = 10
self.cache_timeout = 5.0 # 5秒超时
# OpenCV优化开关 # OpenCV优化开关
try: try:
@ -334,15 +331,29 @@ class CameraManager(BaseDevice):
# 重置丢帧计数 # 重置丢帧计数
self.dropped_frames = 0 self.dropped_frames = 0
# 保存原始帧到全局缓存(用于录制) # 保存原始帧到队列(用于录制)
self._save_frame_to_cache(frame, 'camera') try:
self.frame_queue.put_nowait({
'frame': frame.copy(),
'timestamp': time.time()
})
except queue.Full:
# 队列满时丢弃最旧的帧,添加新帧
try:
self.frame_queue.get_nowait() # 移除最旧的帧
self.frame_queue.put_nowait({
'frame': frame.copy(),
'timestamp': time.time()
})
except queue.Empty:
pass # 队列为空,忽略
# 处理帧(降采样以优化传输负载) # 处理帧(降采样以优化传输负载)
processed_frame = self._process_frame(frame) processed_frame = self._process_frame(frame)
# 缓存帧(不复制,减少内存占用) # # 缓存帧(不复制,减少内存占用)
self.last_frame = processed_frame # self.last_frame = processed_frame
self.frame_cache.append(processed_frame) # self.frame_cache.append(processed_frame)
# 发送帧数据 # 发送帧数据
self._send_frame_data(processed_frame) self._send_frame_data(processed_frame)
@ -530,15 +541,7 @@ class CameraManager(BaseDevice):
self.logger.error(f"捕获图像异常: {e}") self.logger.error(f"捕获图像异常: {e}")
return None return None
def get_latest_frame(self) -> Optional[np.ndarray]:
"""
获取最新帧
Returns:
Optional[np.ndarray]: 最新帧无帧返回None
"""
# 对外提供拷贝,内部保持原对象,避免重复持有
return self.last_frame.copy() if self.last_frame is not None else None
def disconnect(self): def disconnect(self):
""" """
@ -574,12 +577,20 @@ class CameraManager(BaseDevice):
pass pass
self.cap = None self.cap = None
self.frame_cache.clear() # 清理帧缓存
while not self.frame_cache.empty():
try:
self.frame_cache.get_nowait()
except queue.Empty:
break
self.last_frame = None self.last_frame = None
# 清理全局帧缓存 # 清理帧队列
with self.frame_cache_lock: while not self.frame_queue.empty():
self.global_frame_cache.clear() try:
self.frame_queue.get_nowait()
except queue.Empty:
break
super().cleanup() super().cleanup()
self.logger.info("相机资源清理完成") self.logger.info("相机资源清理完成")
@ -618,48 +629,34 @@ class CameraManager(BaseDevice):
self.logger.error(f'保存帧到缓存失败: {e}') self.logger.error(f'保存帧到缓存失败: {e}')
def _get_latest_frame_from_cache(self, frame_type='camera'): def _get_latest_frame_from_cache(self, frame_type='camera'):
"""缓存获取最新帧""" """队列获取最新帧"""
try: try:
with self.frame_cache_lock: if self.frame_queue.empty():
if frame_type not in self.global_frame_cache: self.logger.debug('帧队列为空')
self.logger.debug(f'缓存中不存在帧类型: {frame_type}, 可用类型: {list(self.global_frame_cache.keys())}') return None, None
return None, None
if not self.global_frame_cache[frame_type]:
self.logger.debug(f'帧类型 {frame_type} 的缓存为空')
return None, None
# 清理过期帧
self._cleanup_expired_frames()
if not self.global_frame_cache[frame_type]:
self.logger.debug(f'清理过期帧后,帧类型 {frame_type} 的缓存为空')
return None, None
# 获取最新帧
latest_timestamp = max(self.global_frame_cache[frame_type].keys())
frame_data = self.global_frame_cache[frame_type][latest_timestamp]
return frame_data['frame'].copy(), frame_data['timestamp']
except Exception as e:
self.logger.error(f'从缓存获取帧失败: {e}')
return None, None
def _cleanup_expired_frames(self):
"""清理过期的缓存帧"""
try:
current_time = time.time()
for frame_type in list(self.global_frame_cache.keys()): # 获取队列中的所有帧,保留最新的一个
expired_keys = [] frames = []
for timestamp in self.global_frame_cache[frame_type].keys(): while not self.frame_queue.empty():
if current_time - timestamp > self.cache_timeout: try:
expired_keys.append(timestamp) frames.append(self.frame_queue.get_nowait())
except queue.Empty:
break
if not frames:
return None, None
# 获取最新帧(最后一个)
latest_frame = frames[-1]
# 将最新帧重新放回队列
try:
self.frame_queue.put_nowait(latest_frame)
except queue.Full:
pass # 队列满时忽略
return latest_frame['frame'].copy(), latest_frame['timestamp']
# 删除过期帧
for key in expired_keys:
del self.global_frame_cache[frame_type][key]
except Exception as e: except Exception as e:
self.logger.error(f'清理过期帧失败: {e}') self.logger.error(f'从队列获取帧失败: {e}')
return None, None

View File

@ -173,14 +173,17 @@ class RecordingManager:
# 初始化屏幕录制写入器 # 初始化屏幕录制写入器
# record_size = self.screen_region[2:4] if self.screen_region else self.screen_size # record_size = self.screen_region[2:4] if self.screen_region else self.screen_size
# print('屏幕写入器的宽高..............',record_size) # print('屏幕写入器的宽高..............',record_size)
self.screen_video_writer = cv2.VideoWriter( # self.screen_video_writer = cv2.VideoWriter(
screen_video_path, fourcc, fps, (self.screen_size[0],self.screen_size[1]) # screen_video_path, fourcc, fps, (self.screen_size[0],self.screen_size[1])
) # )
if self.screen_video_writer.isOpened(): # 检查屏幕视频写入器状态(仅在初始化时)
if self.screen_video_writer and self.screen_video_writer.isOpened():
self.logger.info(f'屏幕视频写入器初始化成功: {screen_video_path}') self.logger.info(f'屏幕视频写入器初始化成功: {screen_video_path}')
else: elif self.screen_video_writer:
self.logger.error(f'屏幕视频写入器初始化失败: {screen_video_path}') self.logger.error(f'屏幕视频写入器初始化失败: {screen_video_path}')
else:
self.logger.info('屏幕录制功能暂时禁用')
# 重置停止事件 # 重置停止事件
self.recording_stop_event.clear() self.recording_stop_event.clear()
@ -195,13 +198,13 @@ class RecordingManager:
) )
self.feet_recording_thread.start() self.feet_recording_thread.start()
if self.screen_video_writer: # if self.screen_video_writer:
self.screen_recording_thread = threading.Thread( # self.screen_recording_thread = threading.Thread(
target=self._screen_recording_thread, # target=self._screen_recording_thread,
daemon=True, # daemon=True,
name='ScreenRecordingThread' # name='ScreenRecordingThread'
) # )
self.screen_recording_thread.start() # self.screen_recording_thread.start()
result['success'] = True result['success'] = True
result['recording_start_time'] = self.recording_start_time.isoformat() result['recording_start_time'] = self.recording_start_time.isoformat()