diff --git a/.idea/.name b/.idea/.name
index 9465664..d581472 100644
--- a/.idea/.name
+++ b/.idea/.name
@@ -1 +1 @@
-test.py
\ No newline at end of file
+detection.py
\ No newline at end of file
diff --git a/Detection_window.py b/Detection_window.py
new file mode 100644
index 0000000..68095f1
--- /dev/null
+++ b/Detection_window.py
@@ -0,0 +1,54 @@
+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'Detection_window.ui'
+#
+# Created by: PyQt5 UI code generator 5.15.6
+#
+# WARNING: Any manual changes made to this file will be lost when pyuic5 is
+# run again. Do not edit this file unless you know what you are doing.
+
+
+from PyQt5 import QtCore, QtGui, QtWidgets
+
+
+class Ui_MainWindow(object):
+ def setupUi(self, MainWindow):
+ MainWindow.setObjectName("MainWindow")
+ MainWindow.resize(1308, 865)
+ self.centralwidget = QtWidgets.QWidget(MainWindow)
+ self.centralwidget.setObjectName("centralwidget")
+ self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
+ self.gridLayout.setObjectName("gridLayout")
+ self.bt_detection = QtWidgets.QPushButton(self.centralwidget)
+ self.bt_detection.setMinimumSize(QtCore.QSize(100, 50))
+ self.bt_detection.setMaximumSize(QtCore.QSize(100, 50))
+ self.bt_detection.setObjectName("bt_detection")
+ self.gridLayout.addWidget(self.bt_detection, 0, 0, 1, 1)
+ self.view_origin = QtWidgets.QLabel(self.centralwidget)
+ self.view_origin.setMinimumSize(QtCore.QSize(1000, 1000))
+ self.view_origin.setMaximumSize(QtCore.QSize(1000, 1000))
+ self.view_origin.setObjectName("view_origin")
+ self.gridLayout.addWidget(self.view_origin, 1, 0, 1, 1)
+ self.view_predict = QtWidgets.QLabel(self.centralwidget)
+ self.view_predict.setMinimumSize(QtCore.QSize(1000, 1000))
+ self.view_predict.setMaximumSize(QtCore.QSize(1000, 1000))
+ self.view_predict.setObjectName("view_predict")
+ self.gridLayout.addWidget(self.view_predict, 1, 1, 1, 1)
+ MainWindow.setCentralWidget(self.centralwidget)
+ self.menubar = QtWidgets.QMenuBar(MainWindow)
+ self.menubar.setGeometry(QtCore.QRect(0, 0, 1308, 22))
+ self.menubar.setObjectName("menubar")
+ MainWindow.setMenuBar(self.menubar)
+ self.statusbar = QtWidgets.QStatusBar(MainWindow)
+ self.statusbar.setObjectName("statusbar")
+ MainWindow.setStatusBar(self.statusbar)
+
+ self.retranslateUi(MainWindow)
+ QtCore.QMetaObject.connectSlotsByName(MainWindow)
+
+ def retranslateUi(self, MainWindow):
+ _translate = QtCore.QCoreApplication.translate
+ MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
+ self.bt_detection.setText(_translate("MainWindow", "檢測"))
+ self.view_origin.setText(_translate("MainWindow", "原圖影像"))
+ self.view_predict.setText(_translate("MainWindow", "檢測影像"))
diff --git a/Detection_window.ui b/Detection_window.ui
new file mode 100644
index 0000000..3f32aa8
--- /dev/null
+++ b/Detection_window.ui
@@ -0,0 +1,91 @@
+
+
+ MainWindow
+
+
+
+ 0
+ 0
+ 1308
+ 865
+
+
+
+ MainWindow
+
+
+
+ -
+
+
+
+ 100
+ 50
+
+
+
+
+ 100
+ 50
+
+
+
+ 檢測
+
+
+
+ -
+
+
+
+ 1000
+ 1000
+
+
+
+
+ 1000
+ 1000
+
+
+
+ 原圖影像
+
+
+
+ -
+
+
+
+ 1000
+ 1000
+
+
+
+
+ 1000
+ 1000
+
+
+
+ 檢測影像
+
+
+
+
+
+
+
+
+
+
+
diff --git a/camera/camera.py b/camera/camera.py
index 6f8025c..c919ea8 100644
--- a/camera/camera.py
+++ b/camera/camera.py
@@ -7,7 +7,6 @@ import cv2
import numpy as np
from camera_window import Ui_MainWindow
-
class CameraThread(QThread):
update_image_signal = pyqtSignal(np.ndarray) # 訊號:傳遞影像數據
@@ -45,9 +44,6 @@ class CameraThread(QThread):
except Exception as e:
print(f"影像擷取錯誤: {e}")
- except Exception as e:
- print(f"影像擷取錯誤: {e}")
-
def stop(self):
"""停止執行緒"""
self.running = False
@@ -57,9 +53,9 @@ class CameraThread(QThread):
self.wait() # 確保執行緒完全停止
-class CameraApp(QtWidgets.QMainWindow, Ui_MainWindow):
+class Camera(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
- super(CameraApp, self).__init__()
+ super(Camera, self).__init__()
self.setupUi(self)
# 連接按鈕事件
@@ -76,6 +72,7 @@ class CameraApp(QtWidgets.QMainWindow, Ui_MainWindow):
self.camera = None
self.camera_thread = None
self.current_image = None
+ self.latest_image = None # 用於存儲最新影像
self.last_exposure_time = None # 記錄最後的曝光時間,避免重複更新
def connect_camera(self):
@@ -83,9 +80,11 @@ class CameraApp(QtWidgets.QMainWindow, Ui_MainWindow):
try:
self.camera = pylon.InstantCamera(pylon.TlFactory.GetInstance().CreateFirstDevice())
self.camera.Open()
- self.statusbar.showMessage("相機連線成功")
+ print("相機連線成功")
+ return True
except Exception as e:
- self.statusbar.showMessage(f"相機連線失敗: {e}")
+ print(f"相機連線失敗: {e}")
+ return False
def get_exposure_time(self):
"""取得曝光時間,若為空則使用預設值"""
@@ -102,23 +101,34 @@ class CameraApp(QtWidgets.QMainWindow, Ui_MainWindow):
if not (self.camera and self.camera.IsOpen()):
return
- new_exposure_time = self.get_exposure_time()
+ try:
+ new_exposure_time = self.get_exposure_time()
- # 避免重複設定相同的曝光時間,降低 CPU 負載
- if new_exposure_time == self.last_exposure_time:
- return
+ # 確保曝光時間在相機允許的範圍內
+ min_exp = self.camera.ExposureTime.GetMin()
+ max_exp = self.camera.ExposureTime.GetMax()
- self.last_exposure_time = new_exposure_time # 更新最後的曝光時間
+ if new_exposure_time < min_exp or new_exposure_time > max_exp:
+ self.statusbar.showMessage(f"曝光時間超出範圍 ({min_exp} ~ {max_exp}),請輸入有效值")
+ return
- self.camera.ExposureTime.SetValue(float(new_exposure_time))
- self.statusbar.showMessage(f"曝光時間更新為 {new_exposure_time} 微秒")
+ # 避免重複設定相同的曝光時間
+ if new_exposure_time == self.last_exposure_time:
+ return
- # 若相機正在連續擷取,直接應用新的曝光時間
- if self.camera_thread and self.camera_thread.isRunning():
- self.stop_keep_shot()
- self.keep_shot_capture()
- else:
- self.one_shot_capture()
+ self.last_exposure_time = new_exposure_time
+ self.camera.ExposureTime.SetValue(float(new_exposure_time)) # 設定曝光時間
+ self.statusbar.showMessage(f"曝光時間更新為 {new_exposure_time} 微秒")
+
+ # 重新擷取影像
+ if self.camera_thread and self.camera_thread.isRunning():
+ self.stop_keep_shot()
+ self.keep_shot_capture()
+ else:
+ self.one_shot_capture()
+
+ except Exception as e:
+ self.statusbar.showMessage(f"設定曝光時間失敗: {e}")
def one_shot_capture(self):
"""單張擷取"""
@@ -189,6 +199,6 @@ class CameraApp(QtWidgets.QMainWindow, Ui_MainWindow):
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
- window = CameraApp()
+ window = Camera()
window.show()
sys.exit(app.exec_())
diff --git a/camera/camera_process.py b/camera/camera_process.py
new file mode 100644
index 0000000..73fff3c
--- /dev/null
+++ b/camera/camera_process.py
@@ -0,0 +1,49 @@
+import time
+import numpy as np
+import cv2
+import multiprocessing
+from pypylon import pylon
+
+class CameraProcess(multiprocessing.Process):
+ """ 相機擷取獨立進程 """
+ def __init__(self, image_queue, exposure_time=20000):
+ super(CameraProcess, self).__init__()
+ self.image_queue = image_queue
+ self.exposure_time = exposure_time
+ self.running = multiprocessing.Value('b', True) # 控制進程是否運行
+ self.camera = None
+
+ def connect_camera(self):
+ """ 連接相機 """
+ try:
+ self.camera = pylon.InstantCamera(pylon.TlFactory.GetInstance().CreateFirstDevice())
+ self.camera.Open()
+ self.camera.ExposureTime.SetValue(float(self.exposure_time))
+ print("相機連線成功")
+ return True
+ except Exception as e:
+ print(f"相機連線失敗: {e}")
+ return False
+
+ def run(self):
+ """ 進程啟動後執行影像擷取 """
+ if not self.connect_camera():
+ return
+
+ self.camera.StartGrabbing(pylon.GrabStrategy_LatestImageOnly)
+
+ while self.running.value and self.camera.IsGrabbing():
+ grab_result = self.camera.RetrieveResult(20000, pylon.TimeoutHandling_ThrowException)
+ if grab_result.GrabSucceeded():
+ image = grab_result.Array # 取得影像數據
+ if not self.image_queue.full():
+ self.image_queue.put(image) # 將影像放入 Queue
+ grab_result.Release()
+ time.sleep(0.05) # 控制擷取速度,避免 CPU 過載
+
+ self.camera.Close()
+ print("相機關閉")
+
+ def stop(self):
+ """ 停止相機擷取進程 """
+ self.running.value = False
diff --git a/detection.py b/detection.py
new file mode 100644
index 0000000..652b1d5
--- /dev/null
+++ b/detection.py
@@ -0,0 +1,52 @@
+import sys
+import cv2
+import numpy as np
+import multiprocessing
+from PyQt5 import QtWidgets, QtGui, QtCore
+from PyQt5.QtCore import QTimer
+from Detection_window import Ui_MainWindow
+from camera.camera_process import CameraProcess
+
+class DetectionApp(QtWidgets.QMainWindow, Ui_MainWindow):
+ def __init__(self):
+ super(DetectionApp, self).__init__()
+ self.setupUi(self)
+
+ self.image_queue = multiprocessing.Queue(maxsize=1)
+
+ # ✅ 啟動 CameraProcess
+ self.camera_process = CameraProcess(self.image_queue)
+ self.camera_process.start()
+
+ # ✅ 設定 QTimer,每 100ms 更新影像
+ self.timer = QTimer(self)
+ self.timer.timeout.connect(self.update_view_origin)
+ self.timer.start(100) # 每 100ms 更新一次影像
+
+ def update_view_origin(self):
+ """ 從 Queue 獲取影像並顯示在 QLabel (view_origin) 上 """
+ if not self.image_queue.empty():
+ image = self.image_queue.get() # 取得最新影像
+ self.display_image(image)
+
+ def display_image(self, image):
+ """ 顯示影像到 QLabel (view_origin) """
+ image_bgr = cv2.cvtColor(image, cv2.COLOR_BayerBG2BGR) if len(image.shape) == 2 else 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.view_origin.size(), QtCore.Qt.KeepAspectRatio)
+ self.view_origin.setPixmap(pixmap)
+
+ def closeEvent(self, event):
+ """ 確保程式關閉時正確停止相機擷取進程 """
+ self.camera_process.stop() # 停止相機擷取
+ self.camera_process.join() # 等待進程結束
+ event.accept()
+
+
+if __name__ == "__main__":
+ app = QtWidgets.QApplication(sys.argv)
+ window = DetectionApp()
+ window.show()
+ sys.exit(app.exec_())
diff --git a/main.ui b/main.ui
deleted file mode 100644
index 14843c1..0000000
--- a/main.ui
+++ /dev/null
@@ -1,58 +0,0 @@
-
-
- MainWindow
-
-
-
- 0
- 0
- 1308
- 865
-
-
-
- MainWindow
-
-
-
-
-
- 70
- 110
- 471
- 461
-
-
-
- TextLabel
-
-
-
-
-
- 70
- 40
- 91
- 61
-
-
-
- PushButton
-
-
-
-
-
-
-
-
-