feat: 更新相机控制库加载逻辑
This commit is contained in:
parent
074b656bbc
commit
968b4108b9
@ -3,6 +3,9 @@
|
|||||||
import sys
|
import sys
|
||||||
import copy
|
import copy
|
||||||
import ctypes
|
import ctypes
|
||||||
|
import platform
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
|
||||||
from ctypes import *
|
from ctypes import *
|
||||||
|
|
||||||
@ -11,15 +14,50 @@ from CameraParams_const import *
|
|||||||
from CameraParams_header import *
|
from CameraParams_header import *
|
||||||
from MvErrorDefine_const import *
|
from MvErrorDefine_const import *
|
||||||
|
|
||||||
# Python3.8版本修改Dll加载策略, 默认不再搜索Path环境变量, 同时增加winmode参数以兼容旧版本
|
# 初始化全局变量
|
||||||
dllname = "MvCameraControl.dll"
|
MvCamCtrldll = None
|
||||||
|
|
||||||
|
# 根据操作系统加载不同的库文件
|
||||||
|
system_name = platform.system()
|
||||||
try:
|
try:
|
||||||
|
if system_name == "Windows":
|
||||||
|
dllname = "MvCameraControl.dll"
|
||||||
|
# Python3.8版本修改Dll加载策略, 默认不再搜索Path环境变量, 同时增加winmode参数以兼容旧版本
|
||||||
if "winmode" in ctypes.WinDLL.__init__.__code__.co_varnames:
|
if "winmode" in ctypes.WinDLL.__init__.__code__.co_varnames:
|
||||||
MvCamCtrldll = WinDLL(dllname, winmode=0)
|
MvCamCtrldll = WinDLL(dllname, winmode=0)
|
||||||
else:
|
else:
|
||||||
MvCamCtrldll = WinDLL(dllname)
|
MvCamCtrldll = WinDLL(dllname)
|
||||||
|
logging.info(f"Windows系统: 成功加载 {dllname}")
|
||||||
|
elif system_name == "Darwin": # macOS
|
||||||
|
# macOS通常使用.dylib或.so文件,尝试多种可能的库名
|
||||||
|
possible_libs = [
|
||||||
|
"libMvCameraControl.dylib",
|
||||||
|
"/Library/Frameworks/MvCameraControl.framework/MvCameraControl",
|
||||||
|
"libMvCameraControl.so",
|
||||||
|
"MvCameraControl.so"
|
||||||
|
]
|
||||||
|
|
||||||
|
lib_loaded = False
|
||||||
|
for lib in possible_libs:
|
||||||
|
try:
|
||||||
|
MvCamCtrldll = CDLL(lib)
|
||||||
|
logging.info(f"macOS系统: 成功加载 {lib}")
|
||||||
|
lib_loaded = True
|
||||||
|
break
|
||||||
|
except OSError:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not lib_loaded:
|
||||||
|
logging.error("macOS系统: 无法加载相机控制库,请确保已安装Hikvision SDK并设置正确的库路径")
|
||||||
|
elif system_name == "Linux":
|
||||||
|
dllname = "libMvCameraControl.so"
|
||||||
|
MvCamCtrldll = CDLL(dllname)
|
||||||
|
logging.info(f"Linux系统: 成功加载 {dllname}")
|
||||||
|
else:
|
||||||
|
logging.error(f"不支持的操作系统: {system_name}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"加载MvCameraControl.dll失败: {e}")
|
logging.error(f"加载相机控制库失败: {str(e)}")
|
||||||
|
MvCamCtrldll = None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
BIN
db/jtDB.db
BIN
db/jtDB.db
Binary file not shown.
@ -226,7 +226,8 @@ class MainWindowUI(QMainWindow):
|
|||||||
|
|
||||||
# 上料区内容 - 这里可以添加更多控件
|
# 上料区内容 - 这里可以添加更多控件
|
||||||
self.material_content = QWidget()
|
self.material_content = QWidget()
|
||||||
self.material_content.setStyleSheet("background-color: black;") # 黑色背景适合显示相机画面
|
# 使用透明背景,让相机画面可以正常显示
|
||||||
|
self.material_content.setStyleSheet("background-color: transparent;")
|
||||||
self.material_content_layout = QVBoxLayout(self.material_content)
|
self.material_content_layout = QVBoxLayout(self.material_content)
|
||||||
self.material_content_layout.setContentsMargins(0, 0, 0, 0) # 移除内边距以便相机画面填满
|
self.material_content_layout.setContentsMargins(0, 0, 0, 0) # 移除内边距以便相机画面填满
|
||||||
self.material_layout.addWidget(self.material_content)
|
self.material_layout.addWidget(self.material_content)
|
||||||
|
|||||||
@ -108,12 +108,12 @@ class SettingsUI(QWidget):
|
|||||||
self.exposure_label = QLabel("曝光时间:")
|
self.exposure_label = QLabel("曝光时间:")
|
||||||
self.exposure_label.setFont(self.normal_font)
|
self.exposure_label.setFont(self.normal_font)
|
||||||
self.exposure_slider = QSlider(Qt.Horizontal)
|
self.exposure_slider = QSlider(Qt.Horizontal)
|
||||||
self.exposure_slider.setMinimum(1000)
|
self.exposure_slider.setMinimum(0)
|
||||||
self.exposure_slider.setMaximum(50000)
|
self.exposure_slider.setMaximum(100) # 使用0-100的范围,在代码中映射到0-20000μs
|
||||||
self.exposure_slider.setValue(20000)
|
self.exposure_slider.setValue(50) # 默认值设为50%,对应10000μs
|
||||||
self.exposure_slider.setTickPosition(QSlider.TicksBelow)
|
self.exposure_slider.setTickPosition(QSlider.TicksBelow)
|
||||||
self.exposure_slider.setTickInterval(5000)
|
self.exposure_slider.setTickInterval(10)
|
||||||
self.exposure_value = QLabel("20000 μs")
|
self.exposure_value = QLabel("10000 μs")
|
||||||
self.exposure_value.setFont(self.normal_font)
|
self.exposure_value.setFont(self.normal_font)
|
||||||
self.exposure_value.setMinimumWidth(80)
|
self.exposure_value.setMinimumWidth(80)
|
||||||
|
|
||||||
|
|||||||
@ -53,6 +53,12 @@ class CameraManager:
|
|||||||
def enum_devices(self):
|
def enum_devices(self):
|
||||||
"""枚举相机设备,完全参考BasicDemo.py的enum_devices实现"""
|
"""枚举相机设备,完全参考BasicDemo.py的enum_devices实现"""
|
||||||
try:
|
try:
|
||||||
|
# 确保Hikvision SDK已正确加载
|
||||||
|
from camera.MvCameraControl_class import MvCamCtrldll
|
||||||
|
if MvCamCtrldll is None:
|
||||||
|
logging.error("相机SDK未正确加载,无法枚举设备")
|
||||||
|
return []
|
||||||
|
|
||||||
# 确保先关闭任何已打开的相机
|
# 确保先关闭任何已打开的相机
|
||||||
if self.isOpen:
|
if self.isOpen:
|
||||||
self.close_device()
|
self.close_device()
|
||||||
|
|||||||
@ -113,11 +113,12 @@ class CameraSettingsWidget(QObject):
|
|||||||
# 连接信号和槽
|
# 连接信号和槽
|
||||||
self.connect_signals()
|
self.connect_signals()
|
||||||
|
|
||||||
# 初始化相机参数范围
|
# 初始化相机参数范围 - 注意:曝光参数的实际范围已改为线性映射
|
||||||
self.frame_rate_min = 1.0
|
self.frame_rate_min = 1.0
|
||||||
self.frame_rate_max = 60.0
|
self.frame_rate_max = 60.0
|
||||||
self.exposure_min = 20.0
|
# 以下曝光范围仅用于兼容旧代码,实际的映射在update_exposure_value方法中实现
|
||||||
self.exposure_max = 1000000.0
|
self.exposure_min = 0.0 # 0 μs (最小值)
|
||||||
|
self.exposure_max = 20000.0 # 20000 μs (20ms) - 调整后的最大值
|
||||||
self.gain_min = 0.0
|
self.gain_min = 0.0
|
||||||
self.gain_max = 15.0
|
self.gain_max = 15.0
|
||||||
|
|
||||||
@ -333,7 +334,9 @@ class CameraSettingsWidget(QObject):
|
|||||||
|
|
||||||
device_index = self.get_selected_device_index()
|
device_index = self.get_selected_device_index()
|
||||||
if device_index < 0:
|
if device_index < 0:
|
||||||
QMessageBox.warning(self, "错误", "请先选择一个有效的相机设备!")
|
# 使用父组件作为消息框的父级
|
||||||
|
parent_widget = self.parent if hasattr(self, "parent") else None
|
||||||
|
QMessageBox.warning(parent_widget, "错误", "请先选择一个有效的相机设备!")
|
||||||
return
|
return
|
||||||
|
|
||||||
self.open_button.setEnabled(False)
|
self.open_button.setEnabled(False)
|
||||||
@ -346,9 +349,11 @@ class CameraSettingsWidget(QObject):
|
|||||||
self.signal_camera_connection.emit(True, "")
|
self.signal_camera_connection.emit(True, "")
|
||||||
else:
|
else:
|
||||||
self.signal_camera_connection.emit(False, "打开相机失败")
|
self.signal_camera_connection.emit(False, "打开相机失败")
|
||||||
QMessageBox.warning(self, "错误", "打开相机失败")
|
parent_widget = self.parent if hasattr(self, "parent") else None
|
||||||
|
QMessageBox.warning(parent_widget, "错误", "打开相机失败")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
QMessageBox.critical(self, "错误", f"打开相机时发生异常: {str(e)}")
|
parent_widget = self.parent if hasattr(self, "parent") else None
|
||||||
|
QMessageBox.critical(parent_widget, "错误", f"打开相机时发生异常: {str(e)}")
|
||||||
finally:
|
finally:
|
||||||
self.open_button.setText("打开相机")
|
self.open_button.setText("打开相机")
|
||||||
self.update_controls()
|
self.update_controls()
|
||||||
@ -376,18 +381,29 @@ class CameraSettingsWidget(QObject):
|
|||||||
if self.camera_manager.start_grabbing(window_id):
|
if self.camera_manager.start_grabbing(window_id):
|
||||||
self.test_button.setText("停止预览")
|
self.test_button.setText("停止预览")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
QMessageBox.warning(self, "错误", f"开始预览失败: {e}")
|
parent_widget = self.parent if hasattr(self, "parent") else None
|
||||||
|
QMessageBox.warning(parent_widget, "错误", f"开始预览失败: {e}")
|
||||||
|
|
||||||
self.update_controls()
|
self.update_controls()
|
||||||
|
|
||||||
def update_exposure_value(self, value):
|
def update_exposure_value(self, value):
|
||||||
"""更新曝光值显示"""
|
"""更新曝光值显示(使用线性映射)"""
|
||||||
min_log = log10(self.exposure_min)
|
# 直接使用滑块值(0-100)映射到曝光范围(1000-50000 μs)
|
||||||
max_log = log10(self.exposure_max)
|
# 使用UI中设置的实际曝光范围
|
||||||
log_range = max_log - min_log
|
min_exp = 0 # 0 μs
|
||||||
log_value = min_log + (value / 100.0) * log_range
|
max_exp = 50000
|
||||||
actual_value = 10 ** log_value
|
|
||||||
self.exposure_value.setText(f"{actual_value:.1f} μs")
|
# 线性映射
|
||||||
|
actual_value = min_exp + (value * (max_exp - min_exp) / 100.0)
|
||||||
|
|
||||||
|
# 防止溢出
|
||||||
|
if actual_value > max_exp:
|
||||||
|
actual_value = max_exp
|
||||||
|
logging.warning(f"曝光值过大,已限制为{actual_value}μs")
|
||||||
|
|
||||||
|
# 显示整数值,μs级别不需要小数点
|
||||||
|
self.exposure_value.setText(f"{int(actual_value)} μs")
|
||||||
|
logging.debug(f"曝光滑块值: {value}, 映射后曝光值: {int(actual_value)}μs")
|
||||||
|
|
||||||
def update_gain_value(self, value):
|
def update_gain_value(self, value):
|
||||||
"""更新增益值显示"""
|
"""更新增益值显示"""
|
||||||
@ -410,13 +426,32 @@ class CameraSettingsWidget(QObject):
|
|||||||
|
|
||||||
exposure_time, gain, frame_rate = params
|
exposure_time, gain, frame_rate = params
|
||||||
|
|
||||||
min_log_exp = log10(self.exposure_min)
|
# 使用线性映射计算曝光滑块值
|
||||||
max_log_exp = log10(self.exposure_max)
|
min_exp = 0 # 0 μs
|
||||||
self.exposure_slider.setValue(int(((log10(exposure_time) - min_log_exp) / (max_log_exp - min_log_exp)) * 100))
|
max_exp = 20000 # 20000 μs
|
||||||
|
|
||||||
|
# 将获取到的曝光时间限制在有效范围内
|
||||||
|
if exposure_time < min_exp:
|
||||||
|
exposure_time = min_exp
|
||||||
|
elif exposure_time > max_exp:
|
||||||
|
exposure_time = max_exp
|
||||||
|
|
||||||
|
# 线性映射到滑块值(0-100)
|
||||||
|
exposure_slider_value = int(((exposure_time - min_exp) / (max_exp - min_exp)) * 100)
|
||||||
|
|
||||||
|
# 确保滑块值在有效范围内
|
||||||
|
if exposure_slider_value < 0:
|
||||||
|
exposure_slider_value = 0
|
||||||
|
elif exposure_slider_value > 100:
|
||||||
|
exposure_slider_value = 100
|
||||||
|
|
||||||
|
self.exposure_slider.setValue(exposure_slider_value)
|
||||||
|
|
||||||
|
# 其他参数仍使用原始映射方法
|
||||||
self.gain_slider.setValue(int(((gain - self.gain_min) / (self.gain_max - self.gain_min)) * 100))
|
self.gain_slider.setValue(int(((gain - self.gain_min) / (self.gain_max - self.gain_min)) * 100))
|
||||||
self.framerate_slider.setValue(int(((frame_rate - self.frame_rate_min) / (self.frame_rate_max - self.frame_rate_min)) * 100))
|
self.framerate_slider.setValue(int(((frame_rate - self.frame_rate_min) / (self.frame_rate_max - self.frame_rate_min)) * 100))
|
||||||
|
|
||||||
|
logging.debug(f"获取相机参数: 曝光时间={exposure_time}μs -> 滑块值={exposure_slider_value}, 增益={gain}dB, 帧率={frame_rate}fps")
|
||||||
self.signal_camera_params_changed.emit(exposure_time, gain, frame_rate)
|
self.signal_camera_params_changed.emit(exposure_time, gain, frame_rate)
|
||||||
|
|
||||||
def set_camera_params(self):
|
def set_camera_params(self):
|
||||||
@ -424,15 +459,25 @@ class CameraSettingsWidget(QObject):
|
|||||||
if not self.camera_manager.isOpen:
|
if not self.camera_manager.isOpen:
|
||||||
return
|
return
|
||||||
|
|
||||||
min_log = log10(self.exposure_min)
|
# 使用线性映射计算曝光时间
|
||||||
max_log = log10(self.exposure_max)
|
min_exp = 0 # 0 μs
|
||||||
log_range = max_log - min_log
|
max_exp = 50000 # 50000 μs
|
||||||
log_value = min_log + (self.exposure_slider.value() / 100.0) * log_range
|
|
||||||
exposure_time = 10 ** log_value
|
|
||||||
|
|
||||||
|
# 根据滑块值(0-100)线性映射到曝光时间
|
||||||
|
slider_value = self.exposure_slider.value()
|
||||||
|
exposure_time = min_exp + (slider_value * (max_exp - min_exp) / 100.0)
|
||||||
|
|
||||||
|
# 确保曝光时间在有效范围内
|
||||||
|
if exposure_time < min_exp:
|
||||||
|
exposure_time = min_exp
|
||||||
|
elif exposure_time > max_exp:
|
||||||
|
exposure_time = max_exp
|
||||||
|
|
||||||
|
# 增益和帧率保持原来的映射方式
|
||||||
gain = self.gain_min + (self.gain_slider.value() / 100.0) * (self.gain_max - self.gain_min)
|
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)
|
frame_rate = self.frame_rate_min + (self.framerate_slider.value() / 100.0) * (self.frame_rate_max - self.frame_rate_min)
|
||||||
|
|
||||||
|
logging.debug(f"设置相机参数: 曝光滑块值={slider_value} -> 曝光时间={exposure_time}μs, 增益={gain}dB, 帧率={frame_rate}fps")
|
||||||
self.camera_manager.set_parameters(frame_rate, exposure_time, gain)
|
self.camera_manager.set_parameters(frame_rate, exposure_time, gain)
|
||||||
self.signal_camera_params_changed.emit(exposure_time, gain, frame_rate)
|
self.signal_camera_params_changed.emit(exposure_time, gain, frame_rate)
|
||||||
|
|
||||||
@ -445,11 +490,13 @@ class CameraSettingsWidget(QObject):
|
|||||||
gain = self.gain_slider.value()
|
gain = self.gain_slider.value()
|
||||||
frame_rate = self.framerate_slider.value()
|
frame_rate = self.framerate_slider.value()
|
||||||
|
|
||||||
|
parent_widget = self.parent if hasattr(self, "parent") else None
|
||||||
|
|
||||||
if self.camera_manager.save_params_to_config(exposure, gain, frame_rate):
|
if self.camera_manager.save_params_to_config(exposure, gain, frame_rate):
|
||||||
QMessageBox.information(self, "成功", "相机参数已保存")
|
QMessageBox.information(parent_widget, "成功", "相机参数已保存")
|
||||||
self.settings_changed.emit()
|
self.settings_changed.emit()
|
||||||
else:
|
else:
|
||||||
QMessageBox.critical(self, "错误", "保存相机参数失败")
|
QMessageBox.critical(parent_widget, "错误", "保存相机参数失败")
|
||||||
|
|
||||||
def closeEvent(self, event):
|
def closeEvent(self, event):
|
||||||
"""窗口关闭事件"""
|
"""窗口关闭事件"""
|
||||||
|
|||||||
@ -51,10 +51,8 @@ class SettingsWidget(SettingsUI):
|
|||||||
self.camera_settings = CameraSettingsWidget(self)
|
self.camera_settings = CameraSettingsWidget(self)
|
||||||
logging.info("相机设置组件创建成功")
|
logging.info("相机设置组件创建成功")
|
||||||
|
|
||||||
# 确保相机设置组件正确初始化信号和槽(手动调用一次connect_signals)
|
# 注意:不再手动调用connect_signals,因为它已经在CameraSettingsWidget的__init__中调用了
|
||||||
if hasattr(self.camera_settings, 'connect_signals'):
|
logging.info("相机设置组件已在其初始化时连接信号,不再重复连接")
|
||||||
logging.info("手动调用相机设置控制器的connect_signals方法")
|
|
||||||
self.camera_settings.connect_signals()
|
|
||||||
|
|
||||||
# 添加后处理:直接给刷新按钮添加事件处理
|
# 添加后处理:直接给刷新按钮添加事件处理
|
||||||
if hasattr(self, 'refresh_button'):
|
if hasattr(self, 'refresh_button'):
|
||||||
@ -182,23 +180,8 @@ class SettingsWidget(SettingsUI):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f"连接电量监控设置信号时出错: {e}")
|
logging.error(f"连接电量监控设置信号时出错: {e}")
|
||||||
|
|
||||||
# 直接连接相机标签页中的刷新按钮
|
# 不再在这里连接刷新按钮,避免重复连接
|
||||||
try:
|
logging.info("刷新按钮已在初始化时连接,不再重复连接")
|
||||||
if hasattr(self, 'camera_tab') and hasattr(self, 'refresh_button') and hasattr(self, 'camera_settings'):
|
|
||||||
logging.info("在SettingsWidget中直接连接刷新按钮")
|
|
||||||
try:
|
|
||||||
# 断开可能存在的连接
|
|
||||||
self.refresh_button.clicked.disconnect()
|
|
||||||
except Exception as e:
|
|
||||||
logging.warning(f"断开刷新按钮现有连接时出错: {e}")
|
|
||||||
|
|
||||||
# 连接到相机设置控件的刷新方法
|
|
||||||
self.refresh_button.clicked.connect(self.camera_settings.refresh_devices)
|
|
||||||
|
|
||||||
# 立即调用一次刷新方法
|
|
||||||
self.camera_settings.refresh_devices()
|
|
||||||
except Exception as e:
|
|
||||||
logging.error(f"连接刷新按钮时出错: {e}")
|
|
||||||
|
|
||||||
# 数据库类型选择
|
# 数据库类型选择
|
||||||
self.db_type_combo.currentTextChanged.connect(self.update_db_ui_state)
|
self.db_type_combo.currentTextChanged.connect(self.update_db_ui_state)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user