采集卡bug修复
This commit is contained in:
128
gui_config.py
128
gui_config.py
@@ -200,26 +200,37 @@ class ConfigGUI:
|
||||
def scan_cameras(self, max_index: int = 10):
|
||||
"""扫描系统可用的采集卡索引,并填充下拉框"""
|
||||
import warnings
|
||||
import sys
|
||||
import io
|
||||
found = []
|
||||
|
||||
# 临时设置OpenCV日志级别(兼容不同版本)
|
||||
import os
|
||||
old_level = os.environ.get('OPENCV_LOG_LEVEL', '')
|
||||
os.environ['OPENCV_LOG_LEVEL'] = 'ERROR'
|
||||
os.environ['OPENCV_LOG_LEVEL'] = 'SILENT' # 尝试更严格的级别
|
||||
os.environ['OPENCV_IO_ENABLE_OPENEXR'] = '0'
|
||||
|
||||
# 尝试设置日志级别(不同版本的OpenCV API不同)
|
||||
try:
|
||||
if hasattr(cv2, 'setLogLevel'):
|
||||
# OpenCV 4.x
|
||||
if hasattr(cv2, 'LOG_LEVEL_ERROR'):
|
||||
if hasattr(cv2, 'LOG_LEVEL_SILENT'):
|
||||
cv2.setLogLevel(cv2.LOG_LEVEL_SILENT)
|
||||
elif hasattr(cv2, 'LOG_LEVEL_ERROR'):
|
||||
cv2.setLogLevel(cv2.LOG_LEVEL_ERROR)
|
||||
elif hasattr(cv2, 'utils'):
|
||||
# 某些版本的OpenCV
|
||||
cv2.utils.setLogLevel(0) # 0=ERROR级别
|
||||
cv2.utils.setLogLevel(0) # 0=SILENT/ERROR级别
|
||||
except Exception:
|
||||
pass # 如果设置失败,继续执行
|
||||
pass
|
||||
|
||||
# 重定向stderr来捕获OpenCV的错误输出
|
||||
old_stderr = sys.stderr
|
||||
suppressed_output = io.StringIO()
|
||||
|
||||
try:
|
||||
# 暂时重定向stderr以抑制OpenCV的错误消息
|
||||
sys.stderr = suppressed_output
|
||||
|
||||
for idx in range(max_index + 1):
|
||||
cap = None
|
||||
try:
|
||||
@@ -245,11 +256,14 @@ class ConfigGUI:
|
||||
pass
|
||||
continue
|
||||
finally:
|
||||
# 恢复stderr
|
||||
sys.stderr = old_stderr
|
||||
# 恢复原来的日志级别
|
||||
if old_level:
|
||||
os.environ['OPENCV_LOG_LEVEL'] = old_level
|
||||
else:
|
||||
os.environ.pop('OPENCV_LOG_LEVEL', None)
|
||||
os.environ.pop('OPENCV_IO_ENABLE_OPENEXR', None)
|
||||
|
||||
if not found:
|
||||
found = ["0"] # 至少给一个默认项,避免为空
|
||||
@@ -320,29 +334,46 @@ class ConfigGUI:
|
||||
def save_config(self):
|
||||
"""保存当前编辑的配置"""
|
||||
# 检查索引有效性
|
||||
if self.selected_index >= len(config_manager.config['groups']):
|
||||
messagebox.showerror("错误", f"配置组索引 {self.selected_index} 无效")
|
||||
if self.selected_index < 0 or self.selected_index >= len(config_manager.config['groups']):
|
||||
messagebox.showerror("错误", f"请先选择一个有效的配置组")
|
||||
return False
|
||||
|
||||
# 保存当前组的配置
|
||||
group = config_manager.get_group_by_index(self.selected_index)
|
||||
if group:
|
||||
for key, var in self.config_vars.items():
|
||||
if not key.startswith('display_'):
|
||||
try:
|
||||
value_str = var.get().strip()
|
||||
# 特殊处理:某些字段需要转换为整数
|
||||
if key in ['camera_index', 'camera_width', 'camera_height', 'serial_baudrate', 'move_velocity']:
|
||||
try:
|
||||
value = int(value_str) if value_str else group.get(key, 0)
|
||||
except:
|
||||
if not group:
|
||||
messagebox.showerror("错误", f"配置组不存在")
|
||||
return False
|
||||
|
||||
for key, var in self.config_vars.items():
|
||||
if not key.startswith('display_'):
|
||||
try:
|
||||
value_str = var.get().strip() if var.get() else ""
|
||||
|
||||
# 特殊处理:某些字段需要转换为整数
|
||||
if key in ['camera_index', 'camera_width', 'camera_height', 'serial_baudrate', 'move_velocity']:
|
||||
try:
|
||||
# 如果为空,使用当前值或默认值
|
||||
if value_str:
|
||||
value = int(value_str)
|
||||
else:
|
||||
# 如果下拉框为空,尝试从当前配置获取
|
||||
value = group.get(key, 0)
|
||||
else:
|
||||
value = value_str if value_str else group.get(key, '')
|
||||
group[key] = value
|
||||
except Exception as e:
|
||||
print(f"保存字段 {key} 时出错: {e}")
|
||||
pass
|
||||
except ValueError:
|
||||
# 转换失败,使用当前值
|
||||
value = group.get(key, 0)
|
||||
print(f"⚠️ 字段 {key} 的值 '{value_str}' 无效,使用当前值 {value}")
|
||||
else:
|
||||
# 字符串字段
|
||||
value = value_str if value_str else group.get(key, '')
|
||||
|
||||
group[key] = value
|
||||
except Exception as e:
|
||||
print(f"保存字段 {key} 时出错: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
# 保存失败时使用当前值
|
||||
if key in group:
|
||||
pass # 保持原值不变
|
||||
|
||||
# 保存预览配置
|
||||
display = config_manager.config.get('display', {})
|
||||
@@ -384,28 +415,43 @@ class ConfigGUI:
|
||||
def save_config_silent(self):
|
||||
"""静默保存配置(不显示消息框)"""
|
||||
# 保存当前组的配置
|
||||
if self.selected_index >= len(config_manager.config['groups']):
|
||||
print(f"⚠️ 选中索引 {self.selected_index} 超出范围")
|
||||
if self.selected_index < 0 or self.selected_index >= len(config_manager.config['groups']):
|
||||
print(f"⚠️ 选中索引 {self.selected_index} 无效")
|
||||
return False
|
||||
|
||||
group = config_manager.get_group_by_index(self.selected_index)
|
||||
if group:
|
||||
for key, var in self.config_vars.items():
|
||||
if not key.startswith('display_'):
|
||||
try:
|
||||
value_str = var.get().strip()
|
||||
# 特殊处理:某些字段需要转换为整数
|
||||
if key in ['camera_index', 'camera_width', 'camera_height', 'serial_baudrate', 'move_velocity']:
|
||||
try:
|
||||
value = int(value_str) if value_str else group.get(key, 0)
|
||||
except:
|
||||
if not group:
|
||||
print(f"⚠️ 配置组不存在")
|
||||
return False
|
||||
|
||||
for key, var in self.config_vars.items():
|
||||
if not key.startswith('display_'):
|
||||
try:
|
||||
value_str = var.get().strip() if var.get() else ""
|
||||
|
||||
# 特殊处理:某些字段需要转换为整数
|
||||
if key in ['camera_index', 'camera_width', 'camera_height', 'serial_baudrate', 'move_velocity']:
|
||||
try:
|
||||
# 如果为空,使用当前值或默认值
|
||||
if value_str:
|
||||
value = int(value_str)
|
||||
else:
|
||||
# 如果下拉框为空,尝试从当前配置获取
|
||||
value = group.get(key, 0)
|
||||
else:
|
||||
value = value_str if value_str else group.get(key, '')
|
||||
group[key] = value
|
||||
except Exception as e:
|
||||
print(f"保存字段 {key} 时出错: {e}")
|
||||
pass
|
||||
except ValueError:
|
||||
# 转换失败,使用当前值
|
||||
value = group.get(key, 0)
|
||||
print(f"⚠️ 字段 {key} 的值 '{value_str}' 无效,使用当前值 {value}")
|
||||
else:
|
||||
# 字符串字段
|
||||
value = value_str if value_str else group.get(key, '')
|
||||
|
||||
group[key] = value
|
||||
except Exception as e:
|
||||
print(f"保存字段 {key} 时出错: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
# 保存失败时保持原值不变
|
||||
|
||||
# 保存预览配置
|
||||
display = config_manager.config.get('display', {})
|
||||
|
||||
142
preview.py
142
preview.py
@@ -9,16 +9,22 @@ import os
|
||||
from config import config_manager
|
||||
|
||||
# 抑制OpenCV的警告信息(兼容不同版本)
|
||||
os.environ['OPENCV_LOG_LEVEL'] = 'ERROR'
|
||||
import sys
|
||||
import io
|
||||
|
||||
os.environ['OPENCV_LOG_LEVEL'] = 'SILENT'
|
||||
os.environ['OPENCV_IO_ENABLE_OPENEXR'] = '0'
|
||||
|
||||
try:
|
||||
if hasattr(cv2, 'setLogLevel'):
|
||||
# OpenCV 4.x
|
||||
if hasattr(cv2, 'LOG_LEVEL_ERROR'):
|
||||
if hasattr(cv2, 'LOG_LEVEL_SILENT'):
|
||||
cv2.setLogLevel(cv2.LOG_LEVEL_SILENT)
|
||||
elif hasattr(cv2, 'LOG_LEVEL_ERROR'):
|
||||
cv2.setLogLevel(cv2.LOG_LEVEL_ERROR)
|
||||
elif hasattr(cv2, 'utils'):
|
||||
cv2.utils.setLogLevel(0) # 0=ERROR级别
|
||||
cv2.utils.setLogLevel(0)
|
||||
except Exception:
|
||||
pass # 如果设置失败,继续执行
|
||||
pass
|
||||
|
||||
class PreviewWindow:
|
||||
"""采集卡预览窗口"""
|
||||
@@ -40,65 +46,75 @@ class PreviewWindow:
|
||||
print("⚠️ 没有活动的配置组,将尝试加载所有配置组")
|
||||
active_groups = self.config['groups']
|
||||
|
||||
for i, group in enumerate(active_groups):
|
||||
try:
|
||||
cam_idx = group['camera_index']
|
||||
print(f" 尝试打开采集卡 {cam_idx} ({group['name']})...")
|
||||
|
||||
cap = None
|
||||
# 尝试多种后端打开
|
||||
backends_to_try = [
|
||||
(int(cam_idx), cv2.CAP_DSHOW),
|
||||
(int(cam_idx), cv2.CAP_ANY),
|
||||
(int(cam_idx), None),
|
||||
]
|
||||
|
||||
for idx, backend in backends_to_try:
|
||||
try:
|
||||
with warnings.catch_warnings():
|
||||
warnings.filterwarnings('ignore')
|
||||
if backend is not None:
|
||||
cap = cv2.VideoCapture(idx, backend)
|
||||
else:
|
||||
cap = cv2.VideoCapture(idx)
|
||||
|
||||
if cap.isOpened():
|
||||
# 测试读取一帧
|
||||
ret, test_frame = cap.read()
|
||||
if ret and test_frame is not None:
|
||||
break
|
||||
else:
|
||||
cap.release()
|
||||
cap = None
|
||||
except Exception:
|
||||
if cap:
|
||||
try:
|
||||
cap.release()
|
||||
except:
|
||||
pass
|
||||
cap = None
|
||||
continue
|
||||
|
||||
if cap and cap.isOpened():
|
||||
try:
|
||||
cap.set(cv2.CAP_PROP_FRAME_WIDTH, group['camera_width'])
|
||||
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, group['camera_height'])
|
||||
except Exception as e:
|
||||
print(f" ⚠️ 设置分辨率失败: {e}")
|
||||
# 重定向stderr来抑制OpenCV的错误输出
|
||||
old_stderr = sys.stderr
|
||||
suppressed_output = io.StringIO()
|
||||
|
||||
try:
|
||||
sys.stderr = suppressed_output
|
||||
|
||||
for i, group in enumerate(active_groups):
|
||||
try:
|
||||
cam_idx = group['camera_index']
|
||||
print(f" 尝试打开采集卡 {cam_idx} ({group['name']})...")
|
||||
|
||||
self.caps[i] = {
|
||||
'cap': cap,
|
||||
'group': group,
|
||||
'name': group['name']
|
||||
}
|
||||
loaded_count += 1
|
||||
print(f" ✅ 采集卡 {cam_idx} 初始化成功")
|
||||
else:
|
||||
print(f" ❌ 采集卡 {cam_idx} 无法打开")
|
||||
except Exception as e:
|
||||
print(f" ❌ 采集卡 {group.get('camera_index', '?')} 初始化失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
cap = None
|
||||
# 尝试多种后端打开
|
||||
backends_to_try = [
|
||||
(int(cam_idx), cv2.CAP_DSHOW),
|
||||
(int(cam_idx), cv2.CAP_ANY),
|
||||
(int(cam_idx), None),
|
||||
]
|
||||
|
||||
for idx, backend in backends_to_try:
|
||||
try:
|
||||
with warnings.catch_warnings():
|
||||
warnings.filterwarnings('ignore')
|
||||
if backend is not None:
|
||||
cap = cv2.VideoCapture(idx, backend)
|
||||
else:
|
||||
cap = cv2.VideoCapture(idx)
|
||||
|
||||
if cap.isOpened():
|
||||
# 测试读取一帧
|
||||
ret, test_frame = cap.read()
|
||||
if ret and test_frame is not None:
|
||||
break
|
||||
else:
|
||||
cap.release()
|
||||
cap = None
|
||||
except Exception:
|
||||
if cap:
|
||||
try:
|
||||
cap.release()
|
||||
except:
|
||||
pass
|
||||
cap = None
|
||||
continue
|
||||
|
||||
if cap and cap.isOpened():
|
||||
try:
|
||||
cap.set(cv2.CAP_PROP_FRAME_WIDTH, group['camera_width'])
|
||||
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, group['camera_height'])
|
||||
except Exception as e:
|
||||
print(f" ⚠️ 设置分辨率失败: {e}")
|
||||
|
||||
self.caps[i] = {
|
||||
'cap': cap,
|
||||
'group': group,
|
||||
'name': group['name']
|
||||
}
|
||||
loaded_count += 1
|
||||
print(f" ✅ 采集卡 {cam_idx} 初始化成功")
|
||||
else:
|
||||
print(f" ❌ 采集卡 {cam_idx} 无法打开")
|
||||
except Exception as e:
|
||||
print(f" ❌ 采集卡 {group.get('camera_index', '?')} 初始化失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
finally:
|
||||
# 恢复stderr
|
||||
sys.stderr = old_stderr
|
||||
|
||||
if loaded_count == 0:
|
||||
print("⚠️ 警告:没有成功加载任何采集卡!")
|
||||
|
||||
@@ -45,16 +45,21 @@ import warnings
|
||||
|
||||
# 抑制OpenCV的警告信息(兼容不同版本)
|
||||
import os
|
||||
os.environ['OPENCV_LOG_LEVEL'] = 'ERROR'
|
||||
import sys
|
||||
import io
|
||||
os.environ['OPENCV_LOG_LEVEL'] = 'SILENT'
|
||||
os.environ['OPENCV_IO_ENABLE_OPENEXR'] = '0'
|
||||
|
||||
try:
|
||||
if hasattr(cv2, 'setLogLevel'):
|
||||
# OpenCV 4.x
|
||||
if hasattr(cv2, 'LOG_LEVEL_ERROR'):
|
||||
if hasattr(cv2, 'LOG_LEVEL_SILENT'):
|
||||
cv2.setLogLevel(cv2.LOG_LEVEL_SILENT)
|
||||
elif hasattr(cv2, 'LOG_LEVEL_ERROR'):
|
||||
cv2.setLogLevel(cv2.LOG_LEVEL_ERROR)
|
||||
elif hasattr(cv2, 'utils'):
|
||||
cv2.utils.setLogLevel(0) # 0=ERROR级别
|
||||
cv2.utils.setLogLevel(0)
|
||||
except Exception:
|
||||
pass # 如果设置失败,继续执行
|
||||
pass
|
||||
|
||||
class GetImage:
|
||||
def __init__(self, cam_index=0, width=1920, height=1080):
|
||||
@@ -71,32 +76,42 @@ class GetImage:
|
||||
(cam_index, None), # 默认后端
|
||||
]
|
||||
|
||||
for idx, backend in backends_to_try:
|
||||
try:
|
||||
with warnings.catch_warnings():
|
||||
warnings.filterwarnings('ignore', category=UserWarning)
|
||||
if backend is not None:
|
||||
self.cap = cv2.VideoCapture(idx, backend)
|
||||
else:
|
||||
self.cap = cv2.VideoCapture(idx)
|
||||
|
||||
if self.cap.isOpened():
|
||||
# 测试读取一帧
|
||||
ret, test_frame = self.cap.read()
|
||||
if ret and test_frame is not None:
|
||||
print(f"✅ 采集卡 {cam_index} 打开成功")
|
||||
break
|
||||
else:
|
||||
self.cap.release()
|
||||
# 重定向stderr来抑制OpenCV的错误输出
|
||||
old_stderr = sys.stderr
|
||||
suppressed_output = io.StringIO()
|
||||
|
||||
try:
|
||||
sys.stderr = suppressed_output
|
||||
|
||||
for idx, backend in backends_to_try:
|
||||
try:
|
||||
with warnings.catch_warnings():
|
||||
warnings.filterwarnings('ignore', category=UserWarning)
|
||||
if backend is not None:
|
||||
self.cap = cv2.VideoCapture(idx, backend)
|
||||
else:
|
||||
self.cap = cv2.VideoCapture(idx)
|
||||
|
||||
if self.cap.isOpened():
|
||||
# 测试读取一帧
|
||||
ret, test_frame = self.cap.read()
|
||||
if ret and test_frame is not None:
|
||||
print(f"✅ 采集卡 {cam_index} 打开成功")
|
||||
break
|
||||
else:
|
||||
self.cap.release()
|
||||
self.cap = None
|
||||
except Exception as e:
|
||||
if self.cap:
|
||||
try:
|
||||
self.cap.release()
|
||||
except:
|
||||
pass
|
||||
self.cap = None
|
||||
except Exception as e:
|
||||
if self.cap:
|
||||
try:
|
||||
self.cap.release()
|
||||
except:
|
||||
pass
|
||||
self.cap = None
|
||||
continue
|
||||
continue
|
||||
finally:
|
||||
# 恢复stderr
|
||||
sys.stderr = old_stderr
|
||||
|
||||
if self.cap is None or not self.cap.isOpened():
|
||||
print(f"❌ 无法打开采集卡 {cam_index}")
|
||||
|
||||
Reference in New Issue
Block a user