AP/camera/camera.py

166 lines
5.9 KiB
Python
Raw Normal View History

2025-03-07 12:01:16 +08:00
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_())