jiateng_ws/widgets/camera_manager.py
2025-06-07 10:45:09 +08:00

354 lines
12 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import sys
import os
import logging
from ctypes import *
# 添加相机模块路径
sys.path.append(os.path.join(os.path.dirname(os.path.dirname(__file__)), "camera"))
# 导入相机相关模块
from camera.MvCameraControl_class import MvCamera
from camera.CamOperation_class import CameraOperation
from camera.MvErrorDefine_const import *
from camera.CameraParams_header import *
from camera.CameraParams_const import *
class CameraManager:
"""相机管理器单例类,确保整个应用中只有一个相机实例"""
_instance = None
_initialized = False
@staticmethod
def get_instance():
"""获取相机管理器实例"""
if CameraManager._instance is None:
CameraManager._instance = CameraManager()
return CameraManager._instance
def __init__(self):
"""初始化相机管理器"""
if CameraManager._instance is not None:
raise Exception("相机管理器是单例类请使用get_instance()方法获取实例")
else:
CameraManager._instance = self
# 初始化变量
self.deviceList = None
self.cam = MvCamera()
self.nSelCamIndex = -1
self.obj_cam_operation = None
self.isOpen = False
self.isGrabbing = False
# 初始化SDK (只在第一次时初始化)
if not CameraManager._initialized:
MvCamera.MV_CC_Initialize()
CameraManager._initialized = True
logging.info("相机SDK已初始化")
def enum_devices(self):
"""枚举相机设备"""
try:
# 确保先关闭任何已打开的相机
if self.isOpen:
self.close_device()
# 枚举设备
self.deviceList = MV_CC_DEVICE_INFO_LIST()
n_layer_type = (MV_GIGE_DEVICE | MV_USB_DEVICE | MV_GENTL_CAMERALINK_DEVICE
| MV_GENTL_CXP_DEVICE | MV_GENTL_XOF_DEVICE)
ret = MvCamera.MV_CC_EnumDevices(n_layer_type, self.deviceList)
if ret != 0:
error_msg = f"枚举设备失败! 错误码: 0x{ret:x}"
logging.error(error_msg)
return None
if self.deviceList.nDeviceNum == 0:
logging.info("未找到相机设备")
return []
logging.info(f"找到 {self.deviceList.nDeviceNum} 个相机设备")
# 构造设备信息列表
devices_info = []
for i in range(0, self.deviceList.nDeviceNum):
mvcc_dev_info = cast(self.deviceList.pDeviceInfo[i], POINTER(MV_CC_DEVICE_INFO)).contents
if mvcc_dev_info.nTLayerType == MV_GIGE_DEVICE:
# GigE相机
user_defined_name = ""
for per in mvcc_dev_info.SpecialInfo.stGigEInfo.chUserDefinedName:
if per == 0:
break
user_defined_name = user_defined_name + chr(per)
model_name = ""
for per in mvcc_dev_info.SpecialInfo.stGigEInfo.chModelName:
if per == 0:
break
model_name = model_name + chr(per)
nip1 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0xff000000) >> 24)
nip2 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0x00ff0000) >> 16)
nip3 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0x0000ff00) >> 8)
nip4 = (mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0x000000ff)
ip = f"{nip1}.{nip2}.{nip3}.{nip4}"
device_info = {
"index": i,
"type": "GigE",
"name": user_defined_name,
"model": model_name,
"ip": ip,
"display": f"[{i}]GigE: {user_defined_name} {model_name} ({ip})"
}
devices_info.append(device_info)
elif mvcc_dev_info.nTLayerType == MV_USB_DEVICE:
# USB相机
user_defined_name = ""
for per in mvcc_dev_info.SpecialInfo.stUsb3VInfo.chUserDefinedName:
if per == 0:
break
user_defined_name = user_defined_name + chr(per)
model_name = ""
for per in mvcc_dev_info.SpecialInfo.stUsb3VInfo.chModelName:
if per == 0:
break
model_name = model_name + chr(per)
device_info = {
"index": i,
"type": "USB",
"name": user_defined_name,
"model": model_name,
"display": f"[{i}]USB: {user_defined_name} {model_name}"
}
devices_info.append(device_info)
else:
# 其他类型相机
device_info = {
"index": i,
"type": "Other",
"display": f"[{i}]Other"
}
devices_info.append(device_info)
return devices_info
except Exception as e:
error_msg = f"枚举设备时发生异常: {str(e)}"
logging.error(error_msg)
return None
def open_device(self, device_index):
"""打开相机设备
Args:
device_index: 设备索引
Returns:
bool: 是否成功打开设备
"""
# 检查是否已经打开
if self.isOpen:
logging.warning("相机已经打开!")
return False
# 检查设备索引是否有效
if device_index < 0 or (self.deviceList and device_index >= self.deviceList.nDeviceNum):
logging.error(f"无效的设备索引: {device_index}")
return False
try:
logging.debug(f"准备打开相机,设备索引: {device_index}")
self.nSelCamIndex = device_index
# 创建相机操作对象
self.obj_cam_operation = CameraOperation(self.cam, self.deviceList, self.nSelCamIndex)
ret = self.obj_cam_operation.Open_device()
if ret != 0:
error_msg = f"打开相机失败! 错误码: 0x{ret:x}"
logging.error(error_msg)
self.isOpen = False
return False
# 设置连续模式
self.obj_cam_operation.Set_trigger_mode(False)
# 获取参数
self.obj_cam_operation.Get_parameter()
self.isOpen = True
logging.info(f"相机已打开,设备索引: {device_index}")
return True
except Exception as e:
error_msg = f"打开相机时发生异常: {str(e)}"
logging.error(error_msg)
self.isOpen = False
return False
def close_device(self):
"""关闭相机设备
Returns:
bool: 是否成功关闭设备
"""
if not self.isOpen:
return True
try:
# 确保停止取图
if self.isGrabbing:
self.stop_grabbing()
# 关闭设备
ret = self.obj_cam_operation.Close_device()
if ret != 0:
error_msg = f"关闭相机失败! 错误码: 0x{ret:x}"
logging.error(error_msg)
return False
self.isOpen = False
logging.info("相机已关闭")
return True
except Exception as e:
error_msg = f"关闭相机时发生异常: {str(e)}"
logging.error(error_msg)
self.isOpen = False # 强制设置为关闭状态
return False
def start_grabbing(self, window_id):
"""开始取图
Args:
window_id: 显示窗口句柄
Returns:
bool: 是否成功开始取图
"""
if not self.isOpen:
logging.error("相机未打开,无法开始取图")
return False
if self.isGrabbing:
logging.warning("相机已经在取图")
return True
try:
ret = self.obj_cam_operation.Start_grabbing(window_id)
if ret != 0:
error_msg = f"开始取图失败! 错误码: 0x{ret:x}"
logging.error(error_msg)
return False
self.isGrabbing = True
logging.info("开始图像采集")
return True
except Exception as e:
error_msg = f"开始取图时发生异常: {str(e)}"
logging.error(error_msg)
return False
def stop_grabbing(self):
"""停止取图
Returns:
bool: 是否成功停止取图
"""
if not self.isOpen:
return True
if not self.isGrabbing:
return True
try:
ret = self.obj_cam_operation.Stop_grabbing()
if ret != 0:
error_msg = f"停止取图失败! 错误码: 0x{ret:x}"
logging.error(error_msg)
return False
self.isGrabbing = False
logging.info("停止图像采集")
return True
except Exception as e:
error_msg = f"停止取图时发生异常: {str(e)}"
logging.error(error_msg)
self.isGrabbing = False # 强制设置为非取图状态
return False
def get_parameters(self):
"""获取相机参数
Returns:
tuple: (曝光时间, 增益, 帧率) 或 None (如果失败)
"""
if not self.isOpen:
logging.error("相机未打开,无法获取参数")
return None
try:
ret = self.obj_cam_operation.Get_parameter()
if ret != 0:
error_msg = f"获取相机参数失败! 错误码: 0x{ret:x}"
logging.error(error_msg)
return None
exposure_time = self.obj_cam_operation.exposure_time
gain = self.obj_cam_operation.gain
frame_rate = self.obj_cam_operation.frame_rate
logging.info(f"获取相机参数: 曝光={exposure_time}, 增益={gain}, 帧率={frame_rate}")
return (exposure_time, gain, frame_rate)
except Exception as e:
error_msg = f"获取相机参数时发生异常: {str(e)}"
logging.error(error_msg)
return None
def set_parameters(self, frame_rate, exposure_time, gain):
"""设置相机参数
Args:
frame_rate: 帧率
exposure_time: 曝光时间
gain: 增益
Returns:
bool: 是否成功设置参数
"""
if not self.isOpen:
logging.error("相机未打开,无法设置参数")
return False
try:
# 设置参数
ret = self.obj_cam_operation.Set_parameter(str(frame_rate), str(exposure_time), str(gain))
if ret != 0:
error_msg = f"设置相机参数失败! 错误码: 0x{ret:x}"
logging.error(error_msg)
return False
logging.info(f"设置相机参数: 曝光={exposure_time}, 增益={gain}, 帧率={frame_rate}")
return True
except Exception as e:
error_msg = f"设置相机参数时发生异常: {str(e)}"
logging.error(error_msg)
return False