diff --git a/andor-test/06_gui_viewer.py b/andor-test/06_gui_viewer.py new file mode 100644 index 0000000..35912b6 --- /dev/null +++ b/andor-test/06_gui_viewer.py @@ -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_())