223 lines
7.8 KiB
Python
223 lines
7.8 KiB
Python
|
|
# 自动作业内嵌页面子类
|
|||
|
|
from PySide6.QtCore import Slot, Qt, QTimer
|
|||
|
|
from PySide6.QtWidgets import QWidget, QMessageBox, QLabel
|
|||
|
|
from PySide6.QtGui import QImage, QPixmap
|
|||
|
|
from wndCtrl.stateCtrl.clsSysState_autoproc import CStateAutoProc
|
|||
|
|
from .uiSub_AutoPage import Ui_pageAutoProc
|
|||
|
|
from msg_dict import g_uiCtrlScript, g_uiGeometrySize, g_errMsgText
|
|||
|
|
from ..camera_img_get import Camera
|
|||
|
|
import cv2 # 确保导入OpenCV
|
|||
|
|
|
|||
|
|
|
|||
|
|
class CSubPageAutoProc(QWidget):
|
|||
|
|
# public:
|
|||
|
|
def __init__(self, widgetSize: tuple[int, int], parent=None):
|
|||
|
|
super().__init__(parent)
|
|||
|
|
# 挂载UI界面:将当前业务类实例传入setupUi,UI组件成为实例属性
|
|||
|
|
self.ui = Ui_pageAutoProc()
|
|||
|
|
self.ui.setupUi(self)
|
|||
|
|
# 按需声明对应的成员变量
|
|||
|
|
self.szStack = widgetSize
|
|||
|
|
|
|||
|
|
# 摄像头相关变量
|
|||
|
|
self.cam0 = None # 第一个摄像头
|
|||
|
|
self.cam1 = None # 第二个摄像头
|
|||
|
|
self.timer = None # 定时器
|
|||
|
|
self.camera_label = None # 专门用于显示摄像头的Label,避免重复创建
|
|||
|
|
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
# 界面初始化
|
|||
|
|
def uiInit(self) -> None:
|
|||
|
|
self._editCtrlTitle()
|
|||
|
|
self._screenAdapter() # 界面自适应
|
|||
|
|
# 添加其他和界面或控件初始化相关的操作
|
|||
|
|
self._changeWndStyle() # 设置成无框架边框
|
|||
|
|
self._centerWidget() # 居中显示
|
|||
|
|
# ---------------------------------------------------------------
|
|||
|
|
self._setupSignalSlotMapping()
|
|||
|
|
|
|||
|
|
# 添加摄像头实时图片
|
|||
|
|
self._camera_show()
|
|||
|
|
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
# -----------------------------------------
|
|||
|
|
# private:
|
|||
|
|
# 初始化修改页面控件文字
|
|||
|
|
def _editCtrlTitle(self) -> None:
|
|||
|
|
# 修改tab页面文字
|
|||
|
|
self.ui.tabProc.setTabText(0, g_uiCtrlScript['PAGE_AUTOPROC_TAB_0'])
|
|||
|
|
self.ui.tabProc.setTabText(1, g_uiCtrlScript['PAGE_AUTOPROC_TAB_1'])
|
|||
|
|
|
|||
|
|
# 界面自适应
|
|||
|
|
def _screenAdapter(self) -> None:
|
|||
|
|
self.resize(self.szStack[0], self.szStack[1])
|
|||
|
|
self.ui.tabProc.setGeometry(g_uiGeometrySize['WND_MARGIN_HORI'], g_uiGeometrySize['WND_MARGIN_VERT'],
|
|||
|
|
self.szStack[0] - g_uiGeometrySize['WND_MARGIN_HORI'] * 2,
|
|||
|
|
self.szStack[1] - g_uiGeometrySize['WND_MARGIN_VERT'] * 2)
|
|||
|
|
self._adjustTabCtrls() # 调整tab页内控件的位置及大小
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
# 窗口居中显示
|
|||
|
|
def _centerWidget(self) -> None:
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
# 修改窗体属性
|
|||
|
|
def _changeWndStyle(self) -> None:
|
|||
|
|
self.setWindowFlags(Qt.WindowType.FramelessWindowHint)
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
# 调整tab页面控件
|
|||
|
|
def _adjustTabCtrls(self):
|
|||
|
|
rctTemp = self.ui.grpCamera0.geometry()
|
|||
|
|
nSize = (rctTemp.width(), rctTemp.height())
|
|||
|
|
self.ui.grpCamera0.setGeometry(g_uiGeometrySize['WND_MARGIN_HORI'], 0, nSize[0], nSize[1])
|
|||
|
|
|
|||
|
|
# -------------------------------------------
|
|||
|
|
# 建立信号槽连接
|
|||
|
|
def _setupSignalSlotMapping(self) -> None:
|
|||
|
|
# self.ui.btnProcStart.clicked.connect(self._onBtnProcStart)
|
|||
|
|
self.ui.btnProcStop.clicked.connect(self._onBtnProcStop)
|
|||
|
|
self.ui.btnReset.clicked.connect(self._onBtnReset)
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
# ----------槽函数----------
|
|||
|
|
# @Slot()
|
|||
|
|
# def _onBtnProcStart(self):
|
|||
|
|
# # 启动自动作业
|
|||
|
|
# if g_warnState.checkSysWarning():
|
|||
|
|
# QMessageBox.information(self, g_uiCtrlScript['MSG_TITLE_TIPS'], g_errMsgText['ERR_SYS_WARNING'])
|
|||
|
|
# else:
|
|||
|
|
#
|
|||
|
|
# tProcJob = CProcThread()
|
|||
|
|
# CStateAutoProc.setProcState(True)
|
|||
|
|
# tProcJob.runProc()
|
|||
|
|
# # 更新作业按钮的使能状态
|
|||
|
|
# self.ui.btnProcStart.setEnabled(False)
|
|||
|
|
# self.ui.btnProcStop.setEnabled(True)
|
|||
|
|
# pass
|
|||
|
|
|
|||
|
|
@Slot()
|
|||
|
|
def _onBtnProcStop(self):
|
|||
|
|
# 停止自动作业
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
@Slot()
|
|||
|
|
def _onBtnReset(self):
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
def _camera_show(self):
|
|||
|
|
"""
|
|||
|
|
初始化摄像头并启动实时显示
|
|||
|
|
"""
|
|||
|
|
try:
|
|||
|
|
# 1. 初始化摄像头(保持打开状态)
|
|||
|
|
self.cam0 = Camera()
|
|||
|
|
if not self.cam0._open():
|
|||
|
|
print("[Error] Failed to open camera")
|
|||
|
|
QMessageBox.warning(self, "摄像头错误", "无法打开摄像头,请检查设备连接!")
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
# 2. 初始化显示用的Label
|
|||
|
|
self._init_camera_label()
|
|||
|
|
|
|||
|
|
# 3. 创建定时器,每50毫秒更新一次图像
|
|||
|
|
self.timer = QTimer(self)
|
|||
|
|
self.timer.timeout.connect(self._update_camera_image)
|
|||
|
|
self.timer.start(10) # 50ms,约20fps
|
|||
|
|
print("[Info] Camera started successfully")
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
error_msg = f"摄像头初始化失败: {str(e)}"
|
|||
|
|
print(f"[Error] {error_msg}")
|
|||
|
|
QMessageBox.critical(self, "摄像头错误", error_msg)
|
|||
|
|
|
|||
|
|
def _init_camera_label(self):
|
|||
|
|
"""
|
|||
|
|
初始化摄像头显示用的Label(只创建一次)
|
|||
|
|
"""
|
|||
|
|
# 如果Label已存在,直接返回
|
|||
|
|
if self.camera_label is not None:
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
# 创建Label并设置属性
|
|||
|
|
self.camera_label = QLabel(self.ui.fraCamera0)
|
|||
|
|
# 设置Label充满父容器fraCamera0
|
|||
|
|
self.camera_label.setGeometry(0, 0, self.ui.fraCamera0.width(), self.ui.fraCamera0.height())
|
|||
|
|
# 设置图像自适应缩放
|
|||
|
|
self.camera_label.setScaledContents(True)
|
|||
|
|
# 设置对齐方式
|
|||
|
|
self.camera_label.setAlignment(Qt.AlignCenter)
|
|||
|
|
# 确保Label在最上层显示
|
|||
|
|
self.camera_label.raise_()
|
|||
|
|
|
|||
|
|
def _update_camera_image(self):
|
|||
|
|
"""
|
|||
|
|
定时更新摄像头图像(修复版)
|
|||
|
|
"""
|
|||
|
|
try:
|
|||
|
|
if self.cam0 is None or self.camera_label is None:
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
# 1. 获取摄像头图像
|
|||
|
|
img = self.cam0.get_img()
|
|||
|
|
if img is None or img.size == 0:
|
|||
|
|
print("[Warning] 获取到空图像")
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
# 2. OpenCV图像是BGR格式,需要转换为RGB
|
|||
|
|
# 先检查图像通道数
|
|||
|
|
if len(img.shape) == 3 and img.shape[2] == 3:
|
|||
|
|
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
|
|||
|
|
else:
|
|||
|
|
# 灰度图像处理
|
|||
|
|
img_rgb = img
|
|||
|
|
|
|||
|
|
# 3. 转换为QImage
|
|||
|
|
h, w = img_rgb.shape[:2]
|
|||
|
|
ch = 3 if len(img_rgb.shape) == 3 else 1
|
|||
|
|
bytes_per_line = ch * w
|
|||
|
|
|
|||
|
|
if ch == 3:
|
|||
|
|
q_img = QImage(img_rgb.data, w, h, bytes_per_line, QImage.Format_RGB888)
|
|||
|
|
else:
|
|||
|
|
q_img = QImage(img_rgb.data, w, h, bytes_per_line, QImage.Format_Grayscale8)
|
|||
|
|
|
|||
|
|
# 4. 转换为QPixmap并显示
|
|||
|
|
pixmap = QPixmap.fromImage(q_img)
|
|||
|
|
if not pixmap.isNull():
|
|||
|
|
self.camera_label.setPixmap(pixmap)
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"[Error] 更新摄像头图像失败: {e}")
|
|||
|
|
# 不中断程序,继续尝试
|
|||
|
|
|
|||
|
|
def resizeEvent(self, event):
|
|||
|
|
"""
|
|||
|
|
窗口大小变化时,同步调整摄像头显示Label的大小
|
|||
|
|
"""
|
|||
|
|
super().resizeEvent(event)
|
|||
|
|
if self.camera_label is not None and self.ui.fraCamera0 is not None:
|
|||
|
|
self.camera_label.setGeometry(0, 0, self.ui.fraCamera0.width(), self.ui.fraCamera0.height())
|
|||
|
|
|
|||
|
|
def closeEvent(self, event):
|
|||
|
|
"""
|
|||
|
|
关闭窗口时释放摄像头资源(增强版)
|
|||
|
|
"""
|
|||
|
|
# 停止定时器
|
|||
|
|
if self.timer is not None and self.timer.isActive():
|
|||
|
|
self.timer.stop()
|
|||
|
|
self.timer.deleteLater()
|
|||
|
|
self.timer = None
|
|||
|
|
|
|||
|
|
# 释放摄像头资源
|
|||
|
|
if self.cam0 is not None:
|
|||
|
|
self.cam0._close()
|
|||
|
|
self.cam0 = None
|
|||
|
|
|
|||
|
|
if self.cam1 is not None:
|
|||
|
|
self.cam1._close()
|
|||
|
|
self.cam1 = None
|
|||
|
|
|
|||
|
|
event.accept()
|