みらいテックラボ

音声・画像認識や機械学習など, 週末プログラマである管理人が興味のある技術の紹介や実際にトライしてみた様子などメモしていく.

Webカメラ画像をPySide2で表示すると...

OpenCVWebカメラ画像を取り込み, PySide2のQGraphicsViewに表示した際に, 少しハマったのでメモしておく.

[開発環境]
CPU : Intel Core i7 - 7700
OS : Ubuntu 20.04
Python : 3.7.11
opencv-python-headless : 4.5.5.62
PySide2 : 5.15.2.1


1. 不具合症状
まず, 発生した不具合症状について説明する.
以下のようなコードで, Webカメラ画像を読み込み, 表示するようなものである.

class MainDialog(QMainWindow):
    def __init__(self):
        super(MainDialog, self).__init__()

        self.ui = QUiLoader().load('./resource/dlgMain.ui')
        self.setWindowTitle(self.ui.windowTitle())
        self.setCentralWidget(self.ui)
        # Setup Camera
        self.cap = cv2.VideoCapture(0)
        if not self.cap.isOpened():
            raise 'Camera open error!'
        width = self.cap.get(cv2.CAP_PROP_FRAME_WIDTH)
        height = self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
        fps = self.cap.get(cv2.CAP_PROP_FPS)
        # Setup Timer
        self.timer = QTimer()
        self.timer.timeout.connect(self.displayFrame)
        self.timer.start(1000/fps)
        # Setup View
        self.scene = QGraphicsScene(0, 0, width, height, self.ui.viewImage)
        self.ui.viewImage.setScene(self.scene)
        self.ui.viewImage.setCacheMode(QGraphicsView.CacheBackground)

    def displayFrame(self):
        ret, frame = self.cap.read()
        if ret == False:
            return
        # View
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        h, w, c = frame.shape
        image = QImage(frame.flatten(), w, h, QImage.Format_RGB888)
        self.pixmap = QPixmap.fromImage(image)
        self.scene.clear()
        self.scene.addPixmap(self.pixmap)
        self.ui.viewImage.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatio)

カメラ画像のビューへの表示は, QImage→QPixmap→QGraphicsSceneに追加→QGraphicsViewにセットって感じで行う.
この場合, 一応画像が表示されたが, カメラを動かしたりすると, 一部フレームで白っぽい画像となりチラついた動画となる時があった.
また, Webカメラ画像の読み込みを別スレッドで動作させた場合, 以下のような少しノイズのある 白っぽい画像となってカメラ画像が表示されません.


2. 対応策
少し調べて, あれこれ試してみたところ, 原因はいまだ不明なのだが, 対応策は見えてきた.

OpenCVで読み込んだ画像をQImageにする際, よく以下のようなコードを見かける. [1][2]

        image = QImage(frame.flatten(), w, h, QImage.Format_RGB888)

ここの所を, 以下のように記述することで安定して画像表示できることが分かった. [3]

        image = QImage(frame.data, w, h, w*c, QImage.Format_RGB888)

OpenCVやPySide2のバージョンに依存する不具合かもしれませんが, ご参考まで.

----
参照URL :
[1] OpenCV+pySide2でWebカメラ画像表示
[2] PyQtとOpenCVでwebカメラの映像表示 - 坂推しNIerの雑記帳
[3] OpenCV Face Detection Example - Qt for Python