PyQt와 OpenCV로 카메라 스트리밍 토글하기

2023. 8. 2. 23:21개발

그냥 반복에 반복하며 쓰고 있는 코드라서 정리할 겸 작성해봄.

목표 및 설계

  • 연결된 카메라를 이용한 스트리밍을 토글할 수 있는 GUI
  • 카메라 쓰레드는 파일을 따로 생성
  • cam_id로 특정 카메라 불러오기 (보통 0 또는 1)
  • width, height, fps 설정할 수 있도록..

스트리밍 토글 전(좌), 토글 후(우)

1. 설치

pip install pyqt5
pip install opencv-python

2. 코딩

# main.py
import sys

from camera import CameraThread
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import (
    QApplication,
    QMainWindow,
    QWidget,
    QVBoxLayout,
    QLabel,
    QPushButton,
)

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.camera_thread = CameraThread(
            cam_id=1,
            width=640,
            height=360
        )
        self.camera_thread.q_img.connect(self.update_label)

        self.label_view = QLabel()
        self.btn_camera = QPushButton('ON')
        self.btn_camera.clicked.connect(self.handle_streaming)

        layout = QVBoxLayout()
        layout.addWidget(self.label_view)
        layout.addWidget(self.btn_camera)
        widget = QWidget()
        widget.setLayout(layout)
        self.setCentralWidget(widget)
        self.show()

    def handle_streaming(self):
        if self.btn_camera.text() == 'ON':
            self.btn_camera.setText('OFF')
            self.camera_thread.is_streaming = True
            self.camera_thread.start()
        else:
            self.btn_camera.setText('ON')
            self.camera_thread.is_streaming = False

    def update_label(self, q_img):
        self.label_view.setPixmap(
            QPixmap.fromImage(q_img)
        )


if __name__ == "__main__":
    app = QApplication(sys.argv)
    main = MainWindow()
    app.exec()
# camera.py
import cv2
import numpy as np

from PyQt5.QtGui import QImage
from PyQt5.QtCore import (
    QThread,
    pyqtSignal,
)

class CameraThread(QThread):
    q_img = pyqtSignal(QImage)
    def __init__(self, cam_id=0, width=1280, height=720, fps=30):
        super().__init__()
        self.is_streaming = False
        self.cam_id = cam_id
        self.width = width
        self.height = height
        self.fps = fps

    def init_view(self):
        self.q_img.emit(
            QImage(
                np.zeros((self.height, self.width, 3)),
                self.width,
                self.height,
                self.width * 3,
                QImage.Format_Grayscale16
            )
        )

    def run(self):
        cap = cv2.VideoCapture(self.cam_id)
        cap.set(cv2.CAP_PROP_FRAME_WIDTH, self.width)
        cap.set(cv2.CAP_PROP_FRAME_HEIGHT, self.height)
        cap.set(cv2.CAP_PROP_FPS, self.fps)
        while self.is_streaming:
            ret, frame = cap.read()
            if not ret:
                break
            frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            q_img = QImage(
                frame_rgb,
                self.width,
                self.height,
                self.width * 3,
                QImage.Format_RGB888
            )
            self.q_img.emit(q_img)
        self.init_view()
        cap.release()
728x90
반응형