nach sehr langem Hin und Her habe ich es endlich geschafft, ein GUI zu erstellen, in dem man sich die am PC angeschlossenen Webcams anzeigen lassen kann – jede in einem separaten Fenster. Die Fenster kann man einzeln schließen oder über das Menü alle auf einmal.
Ich stehe aktuell vor zwei zentralen Problemen, die ich nicht in den Griff bekomme:
- Die einzelnen Kamera-Fenster kann ich zwar vergrößern, aber nicht wieder verkleinern.
Weiß jemand, warum ich die Fenster nicht kleiner skalieren kann? - Das Programm ist insgesamt extrem langsam: Es dauert lange zu laden und auch, bis eine Kamera angezeigt wird.
Vielen Dank schon mal im Voraus!
Gruß
Mücke
Code: Alles auswählen
from PyQt6.QtWidgets import (
QApplication, QLabel, QMainWindow, QMdiArea, QMdiSubWindow
)
from PyQt6.QtGui import QAction, QIcon, QImage, QPixmap
from PyQt6.QtCore import Qt, QTimer, QThread, pyqtSignal
import cv2
# Thread zur Kameraerkennung
class CameraDetectThread(QThread):
detected = pyqtSignal(list)
def run(self):
cams = []
for i in range(4):
cap = cv2.VideoCapture(i)
if cap.isOpened():
cams.append(i)
cap.release()
self.detected.emit(cams)
# Thread zum Laden der Kamera
class CameraLoadThread(QThread):
frame_ready = pyqtSignal(QImage)
def __init__(self, cam_index):
super().__init__()
self.cam_index = cam_index
self.running = True
def run(self):
cap = cv2.VideoCapture(self.cam_index)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080)
while self.running:
ret, frame = cap.read()
if ret:
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
h, w, ch = frame.shape
bytes_per_line = ch * w
img = QImage(frame.data, w, h, bytes_per_line, QImage.Format.Format_RGB888)
self.frame_ready.emit(img)
self.msleep(30)
cap.release()
def stop(self):
self.running = False
self.wait()
# Kamera-Widget
class CameraWidget(QLabel):
def __init__(self, cam_index):
super().__init__()
self.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.setStyleSheet("background-color: black;")
self.pixmap_orig = None
self.setText("Loading...")
self.setStyleSheet("font-size: 24px; color: white; background-color: rgba(0,0,0,150);")
self.thread = CameraLoadThread(cam_index)
self.thread.frame_ready.connect(self.update_image)
self.thread.start()
def update_image(self, img):
self.pixmap_orig = QPixmap.fromImage(img)
self.update_scaled_pixmap()
def update_scaled_pixmap(self):
if self.pixmap_orig:
scaled = self.pixmap_orig.scaled(
self.width(), self.height(),
Qt.AspectRatioMode.KeepAspectRatio,
Qt.TransformationMode.SmoothTransformation
)
self.setPixmap(scaled)
def resizeEvent(self, event):
self.update_scaled_pixmap()
super().resizeEvent(event)
def closeEvent(self, event):
self.thread.stop()
event.accept()
# Hauptfenster
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Multi-Kamera Viewer")
# Hier das Icon setzen
self.setWindowIcon(QIcon("camera_icon_home.png"))
self.mdi_area = QMdiArea()
self.setCentralWidget(self.mdi_area)
self.cameras_open = []
# Loading beim Start
self.loading_label = QLabel("Loading", alignment=Qt.AlignmentFlag.AlignCenter)
self.loading_label.setStyleSheet("font-size: 36px; color: white; background-color: black;")
self.loading_window = QMdiSubWindow()
self.loading_window.setWidget(self.loading_label)
self.loading_window.setWindowFlags(Qt.WindowType.FramelessWindowHint)
self.mdi_area.addSubWindow(self.loading_window)
self.resize_loading()
self.loading_window.show()
self.dot_count = 0
self.loading_timer = QTimer()
self.loading_timer.timeout.connect(self.update_loading)
self.loading_timer.start(500)
QTimer.singleShot(100, self.start_camera_detection)
self.mdi_area.resizeEvent = self.on_mdi_resize
def resize_loading(self):
self.loading_window.setGeometry(0, 0, self.mdi_area.width(), self.mdi_area.height())
def on_mdi_resize(self, event):
self.resize_loading()
event.accept()
def update_loading(self):
self.dot_count = (self.dot_count + 1) % 4
self.loading_label.setText("Loading" + "." * self.dot_count)
def start_camera_detection(self):
self.thread = CameraDetectThread()
self.thread.detected.connect(self.init_menu)
self.thread.start()
def init_menu(self, available_cams):
self.loading_timer.stop()
self.loading_window.close()
menu_bar = self.menuBar()
cam_menu = menu_bar.addMenu("Kameras")
for idx in available_cams:
action = QAction(f"Kamera {idx}", self)
action.triggered.connect(lambda checked, i=idx: self.open_camera(i))
cam_menu.addAction(action)
close_all_action = QAction("Alle Kameras schließen", self)
close_all_action.triggered.connect(self.close_all_cameras)
cam_menu.addSeparator()
cam_menu.addAction(close_all_action)
def open_camera(self, cam_index):
cam_window = QMdiSubWindow()
cam_widget = CameraWidget(cam_index)
cam_window.setWidget(cam_widget)
cam_window.setWindowTitle(f"Kamera {cam_index}")
cam_window.setWindowIcon(QIcon("camera_icon_home.png"))
cam_window.resize(640, 480)
self.mdi_area.addSubWindow(cam_window)
cam_window.show()
self.cameras_open.append(cam_window)
def close_all_cameras(self):
for win in self.cameras_open:
win.close()
self.cameras_open.clear()
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
window = MainWindow()
window.resize(1400, 900)
window.show()
sys.exit(app.exec())