324 lines
11 KiB
Python
324 lines
11 KiB
Python
import sys
|
|
import os
|
|
import logging
|
|
from ctypes import *
|
|
from math import log10
|
|
from camera.CameraParams_const import *
|
|
# 添加相机模块路径
|
|
sys.path.append(os.path.join(os.path.dirname(os.path.dirname(__file__)), "camera"))
|
|
|
|
try:
|
|
from PySide6.QtWidgets import QWidget, QMessageBox
|
|
from PySide6.QtCore import Qt, Signal
|
|
USE_PYSIDE6 = True
|
|
except ImportError:
|
|
from PyQt5.QtWidgets import QWidget, QMessageBox
|
|
from PyQt5.QtCore import Qt
|
|
from PyQt5.QtCore import pyqtSignal as Signal
|
|
USE_PYSIDE6 = False
|
|
|
|
# 导入相机相关模块
|
|
from camera.MvCameraControl_class import MvCamera
|
|
from camera.CamOperation_class import CameraOperation
|
|
from camera.MvErrorDefine_const import *
|
|
from camera.CameraParams_header import *
|
|
from ui.settings_ui import SettingsUI
|
|
|
|
# 导入相机管理器
|
|
from widgets.camera_manager import CameraManager
|
|
|
|
|
|
class CameraSettingsWidget(SettingsUI):
|
|
"""相机设置控制器,管理相机设置并提供与主窗口相机显示部分的通信"""
|
|
|
|
# 定义信号
|
|
signal_camera_connection = Signal(bool, str) # 相机连接状态信号 (是否连接, 错误消息)
|
|
signal_camera_params_changed = Signal(float, float, float) # 相机参数变化信号 (曝光, 增益, 帧率)
|
|
signal_camera_error = Signal(str) # 相机错误信号
|
|
|
|
def __init__(self, parent=None):
|
|
super().__init__(parent)
|
|
|
|
# 获取相机管理器实例
|
|
self.camera_manager = CameraManager.get_instance()
|
|
|
|
# 初始化UI控件状态
|
|
self.update_controls()
|
|
|
|
# 连接信号和槽
|
|
self.connect_signals()
|
|
|
|
# 初始化相机参数范围
|
|
self.frame_rate_min = 1.0
|
|
self.frame_rate_max = 60.0
|
|
self.exposure_min = 20.0
|
|
self.exposure_max = 1000000.0
|
|
self.gain_min = 0.0
|
|
self.gain_max = 15.0
|
|
|
|
# 枚举设备
|
|
self.refresh_devices()
|
|
|
|
def connect_signals(self):
|
|
"""连接信号和槽"""
|
|
# 设备选择和刷新
|
|
self.refresh_button.clicked.connect(self.refresh_devices)
|
|
|
|
# 相机控制按钮
|
|
self.open_button.clicked.connect(self.open_camera)
|
|
self.close_button.clicked.connect(self.close_camera)
|
|
self.test_button.clicked.connect(self.test_camera)
|
|
|
|
# 参数滑块
|
|
self.exposure_slider.valueChanged.connect(self.update_exposure_value)
|
|
self.gain_slider.valueChanged.connect(self.update_gain_value)
|
|
self.framerate_slider.valueChanged.connect(self.update_frame_rate_value)
|
|
|
|
# 参数操作按钮
|
|
self.get_params_button.clicked.connect(self.get_camera_params)
|
|
self.set_params_button.clicked.connect(self.set_camera_params)
|
|
self.save_camera_button.clicked.connect(self.save_camera_params)
|
|
|
|
def refresh_devices(self):
|
|
"""刷新设备列表"""
|
|
self.camera_combo.clear()
|
|
|
|
# 枚举设备
|
|
devices_info = self.camera_manager.enum_devices()
|
|
|
|
if not devices_info:
|
|
self.camera_combo.addItem("未发现相机设备")
|
|
self.camera_combo.setEnabled(False)
|
|
self.open_button.setEnabled(False)
|
|
return
|
|
|
|
# 添加设备到下拉框
|
|
for device in devices_info:
|
|
self.camera_combo.addItem(device["display"], device["index"])
|
|
|
|
self.camera_combo.setEnabled(True)
|
|
self.open_button.setEnabled(True)
|
|
|
|
# 更新控件状态
|
|
self.update_controls()
|
|
|
|
def get_selected_device_index(self):
|
|
"""获取当前选中的设备索引"""
|
|
if self.camera_combo.count() == 0:
|
|
return -1
|
|
|
|
return self.camera_combo.currentData()
|
|
|
|
def update_controls(self):
|
|
"""更新控件状态"""
|
|
is_open = self.camera_manager.isOpen
|
|
is_grabbing = self.camera_manager.isGrabbing
|
|
|
|
# 设备选择和刷新
|
|
self.camera_combo.setEnabled(not is_open)
|
|
self.refresh_button.setEnabled(not is_open)
|
|
|
|
# 相机控制按钮
|
|
self.open_button.setEnabled(not is_open and self.camera_combo.count() > 0 and self.camera_combo.currentData() is not None)
|
|
self.close_button.setEnabled(is_open)
|
|
self.test_button.setEnabled(is_open and not is_grabbing)
|
|
|
|
# 参数滑块
|
|
self.exposure_slider.setEnabled(is_open)
|
|
self.gain_slider.setEnabled(is_open)
|
|
self.framerate_slider.setEnabled(is_open)
|
|
|
|
# 参数操作按钮
|
|
self.get_params_button.setEnabled(is_open)
|
|
self.set_params_button.setEnabled(is_open)
|
|
self.save_camera_button.setEnabled(is_open)
|
|
|
|
def open_camera(self):
|
|
"""打开相机"""
|
|
if self.camera_manager.isOpen:
|
|
QMessageBox.warning(self, "错误", "相机已经打开!")
|
|
return
|
|
|
|
device_index = self.get_selected_device_index()
|
|
if device_index < 0:
|
|
QMessageBox.warning(self, "错误", "请先选择一个相机设备!")
|
|
return
|
|
|
|
success = self.camera_manager.open_device(device_index)
|
|
|
|
if success:
|
|
# 获取相机参数并更新UI
|
|
self.get_camera_params()
|
|
|
|
# 更新控件状态
|
|
self.update_controls()
|
|
|
|
# 发送连接信号
|
|
self.signal_camera_connection.emit(True, "")
|
|
else:
|
|
# 发送连接失败信号
|
|
self.signal_camera_connection.emit(False, "打开相机失败")
|
|
|
|
def close_camera(self):
|
|
"""关闭相机"""
|
|
if not self.camera_manager.isOpen:
|
|
return
|
|
|
|
success = self.camera_manager.close_device()
|
|
|
|
# 更新控件状态
|
|
self.update_controls()
|
|
|
|
# 发送连接信号
|
|
if success:
|
|
self.signal_camera_connection.emit(False, "")
|
|
else:
|
|
self.signal_camera_connection.emit(False, "关闭相机出错")
|
|
|
|
def test_camera(self):
|
|
"""测试相机(在预览窗口显示图像)"""
|
|
if not self.camera_manager.isOpen:
|
|
QMessageBox.warning(self, "错误", "请先打开相机!")
|
|
return
|
|
|
|
if self.camera_manager.isGrabbing:
|
|
# 停止预览
|
|
self.camera_manager.stop_grabbing()
|
|
self.test_button.setText("开始预览")
|
|
self.update_controls()
|
|
else:
|
|
# 获取预览窗口句柄
|
|
try:
|
|
# 尝试使用PySide6方式获取窗口句柄
|
|
window_id = int(self.preview_frame.winId())
|
|
except:
|
|
try:
|
|
# 尝试使用PyQt5方式获取窗口句柄
|
|
window_id = self.preview_frame.winId().__int__()
|
|
except:
|
|
# 其他情况
|
|
window_id = int(self.preview_frame.winId())
|
|
|
|
# 开始预览
|
|
success = self.camera_manager.start_grabbing(window_id)
|
|
|
|
if success:
|
|
self.test_button.setText("停止预览")
|
|
else:
|
|
QMessageBox.warning(self, "错误", "开始预览失败!")
|
|
|
|
# 更新控件状态
|
|
self.update_controls()
|
|
|
|
def update_exposure_value(self, value):
|
|
"""更新曝光值显示"""
|
|
# 将滑块值转换为实际曝光值(对数映射)
|
|
min_log = log10(self.exposure_min)
|
|
max_log = log10(self.exposure_max)
|
|
log_range = max_log - min_log
|
|
|
|
log_value = min_log + (value / 100.0) * log_range
|
|
actual_value = 10 ** log_value
|
|
|
|
# 更新显示
|
|
self.exposure_value.setText(f"{actual_value:.1f} μs")
|
|
|
|
def update_gain_value(self, value):
|
|
"""更新增益值显示"""
|
|
# 将滑块值转换为实际增益值
|
|
actual_value = self.gain_min + (value / 100.0) * (self.gain_max - self.gain_min)
|
|
|
|
# 更新显示
|
|
self.gain_value.setText(f"{actual_value:.1f} dB")
|
|
|
|
def update_frame_rate_value(self, value):
|
|
"""更新帧率值显示"""
|
|
# 将滑块值转换为实际帧率值
|
|
actual_value = self.frame_rate_min + (value / 100.0) * (self.frame_rate_max - self.frame_rate_min)
|
|
|
|
# 更新显示
|
|
self.framerate_value.setText(f"{actual_value:.1f} fps")
|
|
|
|
def get_camera_params(self):
|
|
"""获取相机参数"""
|
|
if not self.camera_manager.isOpen:
|
|
QMessageBox.warning(self, "错误", "请先打开相机!")
|
|
return
|
|
|
|
# 获取参数
|
|
params = self.camera_manager.get_parameters()
|
|
if not params:
|
|
QMessageBox.warning(self, "错误", "获取相机参数失败!")
|
|
return
|
|
|
|
exposure_time, gain, frame_rate = params
|
|
|
|
# 更新滑块值
|
|
# 曝光时间(对数映射)
|
|
min_log = log10(self.exposure_min)
|
|
max_log = log10(self.exposure_max)
|
|
log_range = max_log - min_log
|
|
log_value = log10(exposure_time)
|
|
slider_value = int(((log_value - min_log) / log_range) * 100)
|
|
self.exposure_slider.setValue(slider_value)
|
|
|
|
# 增益
|
|
slider_value = int(((gain - self.gain_min) / (self.gain_max - self.gain_min)) * 100)
|
|
self.gain_slider.setValue(slider_value)
|
|
|
|
# 帧率
|
|
slider_value = int(((frame_rate - self.frame_rate_min) / (self.frame_rate_max - self.frame_rate_min)) * 100)
|
|
self.framerate_slider.setValue(slider_value)
|
|
|
|
# 发送参数变化信号
|
|
self.signal_camera_params_changed.emit(exposure_time, gain, frame_rate)
|
|
|
|
def set_camera_params(self):
|
|
"""设置相机参数"""
|
|
if not self.camera_manager.isOpen:
|
|
QMessageBox.warning(self, "错误", "请先打开相机!")
|
|
return
|
|
|
|
# 从滑块获取参数值
|
|
# 曝光时间(对数映射)
|
|
min_log = log10(self.exposure_min)
|
|
max_log = log10(self.exposure_max)
|
|
log_range = max_log - min_log
|
|
log_value = min_log + (self.exposure_slider.value() / 100.0) * log_range
|
|
exposure_time = 10 ** log_value
|
|
|
|
# 增益
|
|
gain = self.gain_min + (self.gain_slider.value() / 100.0) * (self.gain_max - self.gain_min)
|
|
|
|
# 帧率
|
|
frame_rate = self.frame_rate_min + (self.framerate_slider.value() / 100.0) * (self.frame_rate_max - self.frame_rate_min)
|
|
|
|
# 设置参数
|
|
success = self.camera_manager.set_parameters(frame_rate, exposure_time, gain)
|
|
|
|
if success:
|
|
QMessageBox.information(self, "成功", "相机参数设置成功!")
|
|
|
|
# 发送参数变化信号
|
|
self.signal_camera_params_changed.emit(exposure_time, gain, frame_rate)
|
|
else:
|
|
QMessageBox.warning(self, "错误", "相机参数设置失败!")
|
|
|
|
def save_camera_params(self):
|
|
"""保存相机参数"""
|
|
if not self.camera_manager.isOpen:
|
|
QMessageBox.warning(self, "错误", "请先打开相机!")
|
|
return
|
|
|
|
# 实现保存参数到配置文件的功能
|
|
# TODO: 待实现
|
|
QMessageBox.information(self, "提示", "参数保存功能尚未实现")
|
|
|
|
def closeEvent(self, event):
|
|
"""窗口关闭事件"""
|
|
# 确保关闭相机
|
|
if self.camera_manager.isOpen:
|
|
self.camera_manager.close_device()
|
|
|
|
# 处理事件
|
|
super().closeEvent(event) |