Saya mencoba untuk menjalankan loop sementara tetapi ketika itu menjalankan gui (pyqt5) macet. Saya mencoba menjalankan fungsi pada tekan tombol. Ketika btn_off_on ditekan saya ingin off_on metode. Metode ini menjalankan kamera virtual dan alasan saya membutuhkan loop adalah karena saya terus-menerus perlu mengirim bingkai video ke kamera virtual, jika hotkey ditekan frame yang dikirim ke perubahan kamera video ke webcam.

import PyQt5.QtWidgets as qtw
import pyvirtualcam
import cv2
import keyboard


class MainWindow(qtw.QWidget):
    def __init__(self):
        super().__init__()
        # Initiating Variables
        self.path = ""
        self.WIDTH = 1920
        self.HEIGHT = 1080
        self.FPS = 30
        self.HOTKEY = "alt+shift+;"
        self.cap = cv2.VideoCapture(0)
        self.camera_use = False
        self.FMT = pyvirtualcam.PixelFormat.BGR

        # Initiating Elements
        self.btn_off_on = qtw.QPushButton("On/Off")
        self.btn_path = qtw.QPushButton("Get Video")

        # Everything needed for PyQt5
        self.setWindowTitle("Matthew's Cute")
        self.setLayout(qtw.QVBoxLayout())
        self.front_page()

        self.show()

    def off_on(self):
        with pyvirtualcam.Camera(width=self.WIDTH, height=self.HEIGHT, fps=self.FPS, fmt=self.FMT) as cam:
            print(pyvirtualcam.Camera)
            print(f'Using virtual camera: {cam.device}')
            while True:
                while not self.camera_use: ##########HERE IS WHERE I RUN MY WHILE LOOP
                    try:
                        ret, frame = loop_cap.read()
                        frame = cv2.resize(frame, (self.WIDTH, self.HEIGHT), interpolation=cv2.INTER_AREA)
                        self.front_page()
                        self.show()
                        cam.send(frame)
                        cam.sleep_until_next_frame()
                    except:
                        loop_cap = cv2.VideoCapture(self.path[0])
                        self.camera_use = False

                    if keyboard.is_pressed(self.HOTKEY):
                        self.camera_use = True

                while self.camera_use:
                    ret, frame = self.cap.read()
                    frame = cv2.resize(frame, (self.WIDTH, self.HEIGHT), interpolation=cv2.INTER_AREA)
                    super().__init__()
                    self.setWindowTitle("Matthew's Cute")
                    self.setLayout(qtw.QVBoxLayout())
                    self.front_page()
                    self.show()
                    cam.send(frame)
                    cam.sleep_until_next_frame()

                    if keyboard.is_pressed(self.HOTKEY):
                        self.camera_use = False

    def get_path(self):
        self.path = qtw.QFileDialog.getOpenFileName()
        print(self.path[0])

    def front_page(self):
        container = qtw.QWidget()
        container.setLayout(qtw.QGridLayout())

        # Adding the buttons to the layout
        container.layout().addWidget(self.btn_off_on, 0, 0, 1, 2)
        self.btn_off_on.clicked.connect(self.off_on)############ HERE IS WHERE I CALL THE METHOD

        container.layout().addWidget(self.btn_path, 2, 0, 1, 2)
        self.btn_path.clicked.connect(self.get_path)

        self.layout().addWidget(container)


if __name__ == '__main__':
    app = qtw.QApplication([])
    mw = MainWindow()
    app.setStyle(qtw.QStyleFactory.create('Fusion'))
    app.exec_()
0
asd 4 April 2021, 05:49

1 menjawab

Jawaban Terbaik

Sementara benar memblokir tugas sehingga mereka harus dieksekusi di utas sekunder. Dalam hal ini, dimungkinkan untuk membaca dan menulis gambar di utas itu dan memohonnya setiap detik dengan QTimer, jadi akan mudah untuk memulai atau menghentikan pemutaran.

from functools import cached_property

import PyQt5.QtCore as qtc
import PyQt5.QtWidgets as qtw
from PyQt5 import sip

import pyvirtualcam
import cv2
import keyboard
import threading


class VirtualCameraController(qtc.QObject):

    WIDTH = 1920
    HEIGHT = 1080
    FPS = 30
    FMT = pyvirtualcam.PixelFormat.BGR

    mutex = threading.Lock()
    finished = qtc.pyqtSignal()

    def __init__(self, parent=None):
        super().__init__(parent)
        self._capture = None

        self.virtual_camera = pyvirtualcam.Camera(
            width=self.WIDTH, height=self.HEIGHT, fps=self.FPS, fmt=self.FMT
        )
        self.timer.timeout.connect(self.on_timeout)
        self.finished.connect(self.timer.start)

        print(f"Using virtual camera: {self.virtual_camera.device}")

    @cached_property
    def timer(self):
        return qtc.QTimer(singleShot=True, interval=0)

    @property
    def capture(self):
        return self._capture

    @capture.setter
    def capture(self, capture):
        if self.capture == capture:
            return
        with self.mutex:
            if self.capture is not None:
                self.capture.release()
            self._capture = capture

    def start(self):
        self.timer.start()

    def read_frame(self):
        if self._capture is not None:
            ret, frame = self._capture.read()
            if ret:
                return frame

    def on_timeout(self):
        threading.Thread(target=self._execute, daemon=True).start()

    def _execute(self):
        with self.mutex:
            frame = self.read_frame()
            if frame is not None:
                try:
                    frame = cv2.resize(
                        frame,
                        (self.virtual_camera.width, self.virtual_camera.height),
                        interpolation=cv2.INTER_AREA,
                    )
                    self.virtual_camera.send(frame)
                except Exception as e:
                    print(e)
                else:
                    self.virtual_camera.sleep_until_next_frame()
        if sip.isdeleted(self):
            self.virtual_camera.close()
            return
        self.finished.emit()

    def stop(self):
        self.timer.stop()


class MainWindow(qtw.QWidget):
    HOTKEY = "alt+shift+;"

    def __init__(self):
        super().__init__()

        self._filename = ""

        self.btn_off_on = qtw.QPushButton("On/Off")
        self.btn_path = qtw.QPushButton("Get Video")

        self.setWindowTitle("Matthew's Cute")

        lay = qtw.QVBoxLayout(self)
        container = qtw.QWidget()
        grid_layout = qtw.QGridLayout(container)
        grid_layout.addWidget(self.btn_off_on, 0, 0, 1, 2)
        container.layout().addWidget(self.btn_path, 2, 0, 1, 2)
        lay.addWidget(container)

        self.btn_off_on.clicked.connect(self.off_on)
        self.btn_path.clicked.connect(self.get_path)

        keyboard.add_hotkey(self.HOTKEY, self.change_capture)

        self._flag = False

    @cached_property
    def virtual_camera_controller(self):
        return VirtualCameraController()

    @property
    def filename(self):
        return self._filename

    def off_on(self):
        self.change_capture()
        self.virtual_camera_controller.start()

    def get_path(self):
        filename, _ = qtw.QFileDialog.getOpenFileName()
        if filename:
            self._filename = filename

    def closeEvent(self, event):
        super().closeEvent(event)
        self.virtual_camera_controller.stop()

    def use_camera(self):
        self.virtual_camera_controller.capture = cv2.VideoCapture(0)

    def use_video(self):
        self.virtual_camera_controller.capture = cv2.VideoCapture(self.filename)

    def change_capture(self):
        if self._flag:
            self.use_video()
        else:
            self.use_camera()
        self._flag = not self._flag


if __name__ == "__main__":
    app = qtw.QApplication([])
    w = MainWindow()
    w.show()
    ret = app.exec_()
2
eyllanesc 4 April 2021, 04:43