import sys from PyQt5 import QtWidgets, QtGui, QtCore from PyQt5.QtCore import QTimer, QThread, pyqtSignal from PyQt5.QtWidgets import QFileDialog from pypylon import pylon import cv2 import numpy as np import os from Main import Ui_MainWindow class CameraThread(QThread): update_image_signal = pyqtSignal(np.ndarray) # 訊號:傳遞影像數據 def __init__(self, camera, exposure_time=5000, continuous=False): super().__init__() self.camera = camera self.exposure_time = exposure_time self.continuous = continuous self.running = True # 控制執行狀態 def run(self): """影像擷取執行緒""" try: if not self.camera.IsOpen(): return # 設定曝光時間 self.camera.ExposureTime.SetValue(float(self.exposure_time)) if not self.continuous: # 單張擷取 self.camera.StartGrabbing(1) else: # 連續擷取 self.camera.StartGrabbing(pylon.GrabStrategy_LatestImageOnly) while self.running and self.camera.IsGrabbing(): grab_result = self.camera.RetrieveResult(5000, pylon.TimeoutHandling_ThrowException) if grab_result.GrabSucceeded(): self.update_image_signal.emit(grab_result.Array) # 發送影像到 GUI grab_result.Release() if not self.continuous: # 若是單張擷取則停止 break except Exception as e: print(f"影像擷取錯誤: {e}") def stop(self): """停止執行緒""" self.running = False if self.camera.IsGrabbing(): self.camera.StopGrabbing() self.quit() self.wait() # 等待執行緒完全停止 class CameraApp(QtWidgets.QMainWindow, Ui_MainWindow): def __init__(self): super(CameraApp, self).__init__() self.setupUi(self) # 連接按鈕事件 self.bt_camera_connect.clicked.connect(self.connect_camera) self.bt_OneShot.clicked.connect(self.one_shot_capture) self.bt_KeetShot.clicked.connect(self.keep_shot_capture) self.bt_camera_close.clicked.connect(self.close_camera) # 初始化變數 self.camera = None self.camera_thread = None self.current_image = None def connect_camera(self): """連接相機""" try: self.camera = pylon.InstantCamera(pylon.TlFactory.GetInstance().CreateFirstDevice()) self.camera.Open() self.statusbar.showMessage("相機連線成功") except Exception as e: self.statusbar.showMessage(f"相機連線失敗: {e}") def get_exposure_time(self): """從 QTextEdit 取得曝光時間,若為空則使用預設值""" exposure_time_text = self.Ex_time.toPlainText().strip() if not exposure_time_text: return 5000 # 預設曝光時間(微秒) if exposure_time_text.isdigit(): return int(exposure_time_text) self.statusbar.showMessage("請輸入有效的曝光時間(整數),使用預設值 5000 微秒") return 5000 def one_shot_capture(self): """單張擷取""" if not (self.camera and self.camera.IsOpen()): self.statusbar.showMessage("請先連接相機") return # 停止連續擷取 self.stop_keep_shot() exposure_time = self.get_exposure_time() self.camera_thread = CameraThread(self.camera, exposure_time, continuous=False) self.camera_thread.update_image_signal.connect(self.process_image) self.camera_thread.start() def keep_shot_capture(self): """連續擷取""" if not (self.camera and self.camera.IsOpen()): self.statusbar.showMessage("請先連接相機") return # 確保 self.camera_thread 存在且正在運行 if self.camera_thread and self.camera_thread.isRunning(): self.stop_keep_shot() self.statusbar.showMessage("停止連續取像") else: exposure_time = self.get_exposure_time() self.camera_thread = CameraThread(self.camera, exposure_time, continuous=True) self.camera_thread.update_image_signal.connect(self.process_image) self.camera_thread.start() self.statusbar.showMessage("開始連續取像") def stop_keep_shot(self): """停止連續擷取""" if self.camera_thread: self.camera_thread.stop() self.camera_thread.wait() # 確保執行緒完全終止 self.camera_thread = None def process_image(self, image): """處理擷取的影像""" self.current_image = image self.display_original_image() def display_original_image(self): """顯示原始影像""" if self.current_image is not None: image_bgr = cv2.cvtColor(self.current_image, cv2.COLOR_BayerBG2BGR) if len(self.current_image.shape) == 2 else self.current_image height, width, channel = image_bgr.shape bytes_per_line = 3 * width qimage = QtGui.QImage(image_bgr.data, width, height, bytes_per_line, QtGui.QImage.Format_BGR888) pixmap = QtGui.QPixmap.fromImage(qimage).scaled(self.label.size(), QtCore.Qt.KeepAspectRatio) self.label.setPixmap(pixmap) def close_camera(self): """關閉相機""" if self.camera and self.camera.IsOpen(): self.stop_keep_shot() # 確保先停止擷取 self.camera.Close() self.statusbar.showMessage("相機已關閉") self.camera = None def closeEvent(self, event): """關閉程式時停止擷取執行緒""" self.stop_keep_shot() event.accept() if __name__ == "__main__": app = QtWidgets.QApplication(sys.argv) window = CameraApp() window.show() sys.exit(app.exec_())