PyQtで作ったビデオキャプチャプログラムがWindowsでは動くがLinuxでは動かない
- 評価
- クリップ 0
- VIEW 1,299
前提・実現したいこと
PyQtでビデオキャプチャをするプログラムを作っています。
発生している問題・エラーメッセージ
Windows10ではカメラからの画像が表示されるのですが、Ubuntu Linux上で同じコードを動かすとSegmentention Fault となってしまいます。
該当のソースコード
from PyQt5 import QtCore, QtGui, QtWidgets
import cv2
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
thread = CapThread(self)
thread.start()
class CapThread(QtCore.QThread):
def run(self):
capture = cv2.VideoCapture(0)
while True:
ret, frame = capture.read()
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
試したこと
Pythonのバージョンを変えてみましたが、LinuxではSegfaultします。
多分、Threadの使い方に問題があって、Win10ではたまたま動いているように思います。
MainWindowにはボタンをつけて録画等のスレッドを動かすつもりです。
補足情報(FW/ツールのバージョンなど)
Windows10/Python3.6.5 Ubuntu Linux 18.10/Python3.6.7
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+1
以下の点が怪しい気がします。(そもそもやっていいのかどうか)
- OpenCV の GUI と Qt を混ぜて使っている
- メインスレッド以外から cv2.imshow() で GUI を触っている
以下のようにしてはどうでしょうか。
- せっかく Qt を使っているだから、 OpenCV の GUI は使わない。
- UI は別スレッドで触ってはいけないので、シグナルスロットを使う。
→ UI をメインスレッド以外で触るのは動作未定義となっているので、やってはいけません。
改善案
import sys
import cv2
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class Thread(QThread):
frameGrabbed = pyqtSignal(QImage)
def run(self):
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
if not ret:
break
# Qt はチャンネル順が RGB なので変換する。
rgbImage = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# numpy 配列を QImage に変換する。
qImage = QImage(
rgbImage.data, rgbImage.shape[1], rgbImage.shape[0], QImage.Format_RGB888)
# シグナルを送出する。
self.frameGrabbed.emit(qImage)
# スリープを入れる。1000 / fps 分入れる
QThread.msleep(1000 / 30)
class Window(QWidget):
def __init__(self):
super().__init__()
self.initUI()
@pyqtSlot(QImage)
def setImage(self, image):
pixmap = QPixmap.fromImage(image)
# ラベルの大きさに合わせて QPixmap をスケールする。
pixmap = pixmap.scaled(
self.label.width(), self.label.height(), Qt.KeepAspectRatio)
self.label.setPixmap(pixmap)
def initUI(self):
self.setGeometry(100, 100, 500, 500)
# 画像表示用のラベル
self.label = QLabel(self)
self.label.resize(640, 480)
# 画像キャプチャー用のスレッドを作成する。
th = Thread(self)
th.frameGrabbed.connect(self.setImage)
th.start()
if __name__ == "__main__":
app = QApplication(sys.argv)
w = Window()
w.show()
sys.exit(app.exec_())
今カメラがないので VideoCapture の引数を動画ファイルにして試しました。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.35%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2019/02/15 16:56
改善されたコードをよく読んで勉強したいと思います。
2019/02/15 17:04
2019/02/18 10:39
QThread.msleep(1000 / 30)
を
QThread.msleep(int(1000 / 30))
と変更しないとエラーが出ました。
2019/02/18 10:44 編集
import sys
import cv2
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class Thread(QThread):
frameGrabbed = pyqtSignal()
def run(self):
self.frameGrabbed.emit()
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.initUI()
self.setObjectName("MainWindow")
self.resize(300, 400)
@pyqtSlot()
def setImage(self):
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
if not ret:
break
cv2.imshow('frame',frame)
cv2.waitKey(10)
def initUI(self):
# 画像キャプチャー用のスレッドを作成する。
th = Thread(self)
th.frameGrabbed.connect(self.setImage)
th.start()
if __name__ == "__main__":
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
2019/02/18 13:13 編集
メインスレッド外で GUI を触っていた (cv2.imshow()) が問題だったようですね。Linux でも動いたようでよかったです。