LoginSignup
5

More than 3 years have passed since last update.

OpenCV+pySide2でWebカメラ画像表示

Last updated at Posted at 2021-02-06

OpenCV単体でもGUIが作れますが、ここではpySide2との連携について。

環境

macOS + vscode
macOSとvscodeの組み合わせでWebカメラを使うにはTerminalから起動しないとcv2.VideoCapture(0)で失敗してうまくいかない。権限不足でiSight(MacのWebカメラ)が動作しないので注意。

zsh
% sw_vers
ProductName:    Mac OS X
ProductVersion: 10.15.7
BuildVersion:   19H114
% uname -m
x86_64
% python --version
Python 3.8.6
% code --version
1.53.0
% code . # vscodeはTerminalから起動しないと権限不足でiSight(MacのWebカメラ)が動作しない

セットアップ

zsh
pip install opencv-python-headless # headless (GUIなし)でないとpySide2のQtと被る
pip install PySide2

サンプルコード

pySide2でWebカメラ表示するだけのプログラムをいくつかの方法で書いてみた。

サンプル1 (シンプル版)

webcam.py
from PySide2.QtCore import *
from PySide2.QtWidgets import *
from PySide2.QtGui import *
import cv2

def displayFrame():
    ret, frame = cap.read()
    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    h, w = frame.shape[:2]
    image = QImage(frame.flatten(), w, h, QImage.Format_RGB888) # cv::Mat -> Qt(numpy.array)
    label.setPixmap(QPixmap.fromImage(image))

app = QApplication()
window = QWidget()

# Webカメラ起動
cap = cv2.VideoCapture(0)

# 画面表示タイミング
timer = QTimer()
timer.timeout.connect(displayFrame)
timer.start(33) # [msec]

# 画面構成
label = QLabel('No Camera Feed')
layout = QVBoxLayout()
layout.addWidget(label)
window.setLayout(layout)
window.setWindowTitle("Camera")
window.show()
app.exec_()

サンプル2 (QGraphicsScene版、マウスでクリックした位置(画像座標)を取得)

画像の座標を得るにはQGraphicsSceneでmousePressEventを取ってscenePosを得る。

webcam_qgraphicsscene.py
from PySide2.QtCore import *
from PySide2.QtWidgets import *
from PySide2.QtGui import *
import cv2

class myImage(QGraphicsScene):
    mScene = None
    def __init__(self, parent=None):
        super(myImage, self).__init__()

    def mousePressEvent(self, event):
        print(event.type())
        p = event.scenePos() # relative to widget
        print(p)

class webCam(QWidget):
    cap = None
    view = None
    scene = None
    timer = None

    def __init__(self, parent=None):
        super(webCam, self).__init__()
        self.left = 70
        self.top = 70
        self.width = 640
        self.height = 480
        self.setGeometry(self.left, self.top, self.width, self.height)
        self.init()

    def cv_to_pixmap(self, cv_img):
        frame = cv2.cvtColor(cv_img, cv2.COLOR_BGR2RGB)
        h, w = frame.shape[:2]
        qimage = QImage(frame.flatten(), w, h, QImage.Format_RGB888) # cv::Mat -> Qt(numpy.array)
        pixmap = QPixmap.fromImage(qimage)
        return pixmap

    def displayFrame(self):
        ret, frame = self.cap.read()
        pixmap = self.cv_to_pixmap(frame)
        self.scene.clear()
        self.scene.addPixmap(pixmap)
        self.view.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatio) # 原寸表示したい時はこの行をコメントアウト

    def init(self):
        # Webカメラ起動
        self.cap = cv2.VideoCapture(0)

        # 画面構成
        self.scene = myImage('No camera frame')
        self.view = QGraphicsView()
        self.view.setScene(self.scene)
        self.view.setMouseTracking(True) 
        layout = QVBoxLayout()
        layout.addWidget(self.view)
        scrollArea = QScrollArea() # 原寸表示時のスクロール用
        scrollArea.setLayout(layout)
        super(webCam, self).setLayout(layout)
        super(webCam, self).setWindowTitle("Camera")

        # 画面表示タイミング
        self.timer = QTimer()
        self.timer.timeout.connect(self.displayFrame)
        self.timer.start(33) # [msec]

def main():
    app = QApplication()
    window = webCam()
    window.show()
    app.exec_()

if __name__ == '__main__':
    main()

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5