This commit is contained in:
2025-12-04 17:45:44 +08:00
parent 38df71a10d
commit 29217cea2e

231
andor-test/06_gui_viewer.py Normal file
View File

@@ -0,0 +1,231 @@
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout,
QHBoxLayout, QLabel, QPushButton, QDoubleSpinBox,
QSpinBox, QGroupBox, QFormLayout)
from PyQt5.QtCore import QTimer, Qt
from PyQt5.QtGui import QImage, QPixmap
from pylablib.devices.Andor import AndorSDK3Camera
import numpy as np
import sys
class CameraViewer(QMainWindow):
def __init__(self):
super().__init__()
self.cam = None
self.is_acquiring = False
self.init_ui()
self.init_camera()
def init_ui(self):
self.setWindowTitle("Andor Camera Viewer")
self.setGeometry(100, 100, 1200, 800)
central_widget = QWidget()
self.setCentralWidget(central_widget)
main_layout = QHBoxLayout(central_widget)
# 左侧:图像显示
self.image_label = QLabel()
self.image_label.setMinimumSize(800, 600)
self.image_label.setStyleSheet("border: 1px solid black; background-color: black;")
self.image_label.setAlignment(Qt.AlignCenter)
main_layout.addWidget(self.image_label, stretch=3)
# 右侧:控制面板
control_panel = QVBoxLayout()
# 连接控制
conn_group = QGroupBox("相机控制")
conn_layout = QVBoxLayout()
self.btn_connect = QPushButton("连接相机")
self.btn_connect.clicked.connect(self.toggle_connection)
self.btn_start = QPushButton("开始采集")
self.btn_start.clicked.connect(self.toggle_acquisition)
self.btn_start.setEnabled(False)
conn_layout.addWidget(self.btn_connect)
conn_layout.addWidget(self.btn_start)
conn_group.setLayout(conn_layout)
control_panel.addWidget(conn_group)
# 曝光设置
exp_group = QGroupBox("曝光设置")
exp_layout = QFormLayout()
self.spin_exposure = QDoubleSpinBox()
self.spin_exposure.setRange(0.001, 10.0)
self.spin_exposure.setValue(0.05)
self.spin_exposure.setSingleStep(0.01)
self.spin_exposure.setSuffix(" s")
self.spin_exposure.valueChanged.connect(self.update_exposure)
exp_layout.addRow("曝光时间:", self.spin_exposure)
exp_group.setLayout(exp_layout)
control_panel.addWidget(exp_group)
# ROI设置
roi_group = QGroupBox("ROI设置")
roi_layout = QFormLayout()
self.spin_roi_x = QSpinBox()
self.spin_roi_x.setRange(0, 2048)
self.spin_roi_x.setValue(0)
self.spin_roi_y = QSpinBox()
self.spin_roi_y.setRange(0, 2048)
self.spin_roi_y.setValue(0)
self.spin_roi_width = QSpinBox()
self.spin_roi_width.setRange(1, 2048)
self.spin_roi_width.setValue(2048)
self.spin_roi_height = QSpinBox()
self.spin_roi_height.setRange(1, 2048)
self.spin_roi_height.setValue(2048)
self.btn_set_roi = QPushButton("应用ROI")
self.btn_set_roi.clicked.connect(self.update_roi)
self.btn_full_roi = QPushButton("全幅")
self.btn_full_roi.clicked.connect(self.set_full_roi)
roi_layout.addRow("起始X:", self.spin_roi_x)
roi_layout.addRow("起始Y:", self.spin_roi_y)
roi_layout.addRow("宽度:", self.spin_roi_width)
roi_layout.addRow("高度:", self.spin_roi_height)
roi_layout.addRow(self.btn_set_roi)
roi_layout.addRow(self.btn_full_roi)
roi_group.setLayout(roi_layout)
control_panel.addWidget(roi_group)
# 信息显示
info_group = QGroupBox("图像信息")
info_layout = QVBoxLayout()
self.lbl_image_size = QLabel("图像尺寸: --")
self.lbl_min_max = QLabel("Min/Max: --")
self.lbl_fps = QLabel("FPS: --")
info_layout.addWidget(self.lbl_image_size)
info_layout.addWidget(self.lbl_min_max)
info_layout.addWidget(self.lbl_fps)
info_group.setLayout(info_layout)
control_panel.addWidget(info_group)
control_panel.addStretch()
main_layout.addLayout(control_panel, stretch=1)
# 定时器
self.timer = QTimer()
self.timer.timeout.connect(self.update_frame)
def init_camera(self):
pass
def toggle_connection(self):
if self.cam is None:
try:
self.cam = AndorSDK3Camera(idx=0)
self.cam.open()
detector_size = self.cam.get_detector_size()
self.spin_roi_width.setMaximum(detector_size[0])
self.spin_roi_height.setMaximum(detector_size[1])
self.spin_roi_x.setMaximum(detector_size[0])
self.spin_roi_y.setMaximum(detector_size[1])
self.spin_roi_width.setValue(detector_size[0])
self.spin_roi_height.setValue(detector_size[1])
self.btn_connect.setText("断开相机")
self.btn_start.setEnabled(True)
print("相机已连接")
except Exception as e:
print(f"连接失败: {e}")
else:
if self.is_acquiring:
self.toggle_acquisition()
self.cam.close()
self.cam = None
self.btn_connect.setText("连接相机")
self.btn_start.setEnabled(False)
print("相机已断开")
def toggle_acquisition(self):
if not self.is_acquiring:
try:
self.cam.setup_acquisition(mode="sequence", nframes=100)
self.cam.start_acquisition()
self.is_acquiring = True
self.btn_start.setText("停止采集")
self.timer.start(50)
print("开始采集")
except Exception as e:
print(f"启动采集失败: {e}")
else:
self.timer.stop()
self.cam.stop_acquisition()
self.is_acquiring = False
self.btn_start.setText("开始采集")
print("停止采集")
def update_exposure(self):
if self.cam and not self.is_acquiring:
exp = self.spin_exposure.value()
self.cam.set_exposure(exp)
print(f"曝光设置为: {exp}s")
def update_roi(self):
if self.cam and not self.is_acquiring:
x = self.spin_roi_x.value()
y = self.spin_roi_y.value()
w = self.spin_roi_width.value()
h = self.spin_roi_height.value()
try:
self.cam.set_roi(hstart=x, hend=x+w, vstart=y, vend=y+h)
print(f"ROI设置为: ({x},{y}) {w}x{h}")
except Exception as e:
print(f"ROI设置失败: {e}")
def set_full_roi(self):
if self.cam and not self.is_acquiring:
self.cam.set_roi()
detector_size = self.cam.get_detector_size()
self.spin_roi_x.setValue(0)
self.spin_roi_y.setValue(0)
self.spin_roi_width.setValue(detector_size[0])
self.spin_roi_height.setValue(detector_size[1])
print("ROI设置为全幅")
def update_frame(self):
try:
frames = self.cam.read_multiple_images()
if frames and len(frames) > 0:
image = frames[0]
# 归一化到0-255
img_min = image.min()
img_max = image.max()
if img_max > img_min:
image_norm = ((image - img_min) / (img_max - img_min) * 255).astype(np.uint8)
else:
image_norm = np.zeros_like(image, dtype=np.uint8)
# 转换为QImage并显示
height, width = image_norm.shape
bytes_per_line = width
q_image = QImage(image_norm.data, width, height, bytes_per_line, QImage.Format_Grayscale8)
pixmap = QPixmap.fromImage(q_image)
scaled_pixmap = pixmap.scaled(self.image_label.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation)
self.image_label.setPixmap(scaled_pixmap)
# 更新信息
self.lbl_image_size.setText(f"图像尺寸: {width}x{height}")
self.lbl_min_max.setText(f"Min/Max: {img_min}/{img_max}")
except Exception as e:
print(f"读取帧失败: {e}")
def closeEvent(self, event):
if self.is_acquiring:
self.toggle_acquisition()
if self.cam:
self.cam.close()
event.accept()
if __name__ == "__main__":
app = QApplication(sys.argv)
viewer = CameraViewer()
viewer.show()
sys.exit(app.exec_())