2026-01-20 18:40:54 +08:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
"""
|
|
|
|
|
相机管理器模块
|
|
|
|
|
提供相机和显示的统一管理和线程安全访问
|
|
|
|
|
"""
|
|
|
|
|
import threading
|
|
|
|
|
import config
|
|
|
|
|
from logger_manager import logger_manager
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CameraManager:
|
|
|
|
|
"""相机管理器(单例)"""
|
|
|
|
|
_instance = None
|
|
|
|
|
|
|
|
|
|
def __new__(cls):
|
|
|
|
|
if cls._instance is None:
|
|
|
|
|
cls._instance = super(CameraManager, cls).__new__(cls)
|
|
|
|
|
cls._instance._initialized = False
|
|
|
|
|
return cls._instance
|
|
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
|
if self._initialized:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
# 私有对象
|
|
|
|
|
self._camera = None
|
|
|
|
|
self._display = None
|
|
|
|
|
|
|
|
|
|
# 线程安全锁
|
|
|
|
|
self._camera_lock = threading.Lock()
|
|
|
|
|
self._display_lock = threading.Lock()
|
|
|
|
|
|
|
|
|
|
# 相机配置
|
|
|
|
|
self._camera_width = 640
|
|
|
|
|
self._camera_height = 480
|
|
|
|
|
|
|
|
|
|
self._initialized = True
|
|
|
|
|
|
|
|
|
|
# ==================== 初始化方法 ====================
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def logger(self):
|
|
|
|
|
"""获取 logger 对象"""
|
|
|
|
|
return logger_manager.logger
|
|
|
|
|
|
|
|
|
|
def init_camera(self, width=640, height=480):
|
|
|
|
|
"""初始化相机"""
|
|
|
|
|
if self._camera is not None:
|
|
|
|
|
return self._camera
|
|
|
|
|
|
|
|
|
|
from maix import camera
|
|
|
|
|
|
|
|
|
|
self._camera_width = width
|
|
|
|
|
self._camera_height = height
|
|
|
|
|
|
|
|
|
|
with self._camera_lock:
|
|
|
|
|
if self._camera is None:
|
|
|
|
|
self._camera = camera.Camera(width, height)
|
|
|
|
|
|
|
|
|
|
return self._camera
|
|
|
|
|
|
|
|
|
|
def init_display(self):
|
|
|
|
|
"""初始化显示"""
|
|
|
|
|
if self._display is not None:
|
|
|
|
|
return self._display
|
|
|
|
|
|
|
|
|
|
from maix import display
|
|
|
|
|
|
|
|
|
|
with self._display_lock:
|
|
|
|
|
if self._display is None:
|
|
|
|
|
self._display = display.Display()
|
|
|
|
|
|
|
|
|
|
return self._display
|
|
|
|
|
|
|
|
|
|
# ==================== 访问方法 ====================
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def camera(self):
|
|
|
|
|
"""获取相机实例(懒加载)"""
|
|
|
|
|
if self._camera is None:
|
|
|
|
|
self.init_camera()
|
|
|
|
|
return self._camera
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def display(self):
|
|
|
|
|
"""获取显示实例(懒加载)"""
|
|
|
|
|
if self._display is None:
|
|
|
|
|
self.init_display()
|
|
|
|
|
return self._display
|
|
|
|
|
|
|
|
|
|
# ==================== 业务方法 ====================
|
|
|
|
|
|
|
|
|
|
def read_frame(self):
|
|
|
|
|
"""
|
|
|
|
|
线程安全地读取一帧图像
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
frame: 图像帧对象
|
|
|
|
|
"""
|
|
|
|
|
with self._camera_lock:
|
|
|
|
|
if self._camera is None:
|
|
|
|
|
self.init_camera()
|
|
|
|
|
return self._camera.read()
|
|
|
|
|
|
|
|
|
|
def show(self, image):
|
|
|
|
|
"""
|
|
|
|
|
线程安全地显示图像
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
image: 要显示的图像对象
|
|
|
|
|
"""
|
|
|
|
|
with self._display_lock:
|
|
|
|
|
if self._display is None:
|
|
|
|
|
self.init_display()
|
|
|
|
|
self._display.show(image)
|
|
|
|
|
|
|
|
|
|
def release(self):
|
|
|
|
|
"""释放相机和显示资源(如果需要)"""
|
|
|
|
|
with self._camera_lock:
|
|
|
|
|
if self._camera is not None:
|
|
|
|
|
# MaixPy 的 Camera 可能不需要显式释放,但可以在这里清理
|
|
|
|
|
self._camera = None
|
|
|
|
|
|
|
|
|
|
with self._display_lock:
|
|
|
|
|
if self._display is not None:
|
|
|
|
|
# MaixPy 的 Display 可能不需要显式释放
|
|
|
|
|
self._display = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 创建全局单例实例
|
|
|
|
|
camera_manager = CameraManager()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|